Made server communication faster by using a shared memory block.
A few other optimizations in request processing in the server.
Moved automatically generated request definitions to server.h and
removed include/server/request.h.
diff --git a/scheduler/client.c b/scheduler/client.c
index db3070b..4f5dbdb 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -11,13 +11,13 @@
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/mman.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdarg.h>
#include "process.h"
#include "thread.h"
-#include "server/request.h"
#include "server.h"
#include "winerror.h"
@@ -54,120 +54,139 @@
/***********************************************************************
- * CLIENT_SendRequest_v
+ * CLIENT_perror
+ */
+void CLIENT_perror( const char *err )
+{
+ fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
+ perror( err );
+ CLIENT_Die();
+}
+
+
+/***********************************************************************
+ * send_request
*
* Send a request to the server.
*/
-static void CLIENT_SendRequest_v( enum request req, int pass_fd,
- struct iovec *vec, int veclen )
+static void send_request( enum request req )
{
+ struct header *head = NtCurrentTeb()->buffer;
+ int ret, seq = NtCurrentTeb()->seq++;
+
+ assert( server_remaining() >= 0 );
+
+ head->type = req;
+ head->len = (char *)NtCurrentTeb()->buffer_args - (char *)NtCurrentTeb()->buffer;
+
+ NtCurrentTeb()->buffer_args = head + 1; /* reset the args buffer */
+
+ if ((ret = write( NtCurrentTeb()->socket, &seq, sizeof(seq) )) == sizeof(seq))
+ return;
+ if (ret == -1)
+ {
+ if (errno == EPIPE) CLIENT_Die();
+ CLIENT_perror( "sendmsg" );
+ }
+ CLIENT_ProtocolError( "partial seq sent %d/%d\n", ret, sizeof(seq) );
+}
+
+/***********************************************************************
+ * send_request_fd
+ *
+ * Send a request to the server, passing a file descriptor.
+ */
+static void send_request_fd( enum request req, int fd )
+{
+ struct header *head = NtCurrentTeb()->buffer;
+ int ret, seq = NtCurrentTeb()->seq++;
#ifndef HAVE_MSGHDR_ACCRIGHTS
struct cmsg_fd cmsg;
#endif
struct msghdr msghdr;
- struct header head;
- int i, ret, len;
+ struct iovec vec;
- assert( veclen > 0 );
- vec[0].iov_base = &head;
- vec[0].iov_len = sizeof(head);
- for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
+ assert( server_remaining() >= 0 );
- assert( len <= MAX_MSG_LENGTH );
- head.type = req;
- head.len = len;
- head.seq = NtCurrentTeb()->seq++;
+ head->type = req;
+ head->len = (char *)NtCurrentTeb()->buffer_args - (char *)NtCurrentTeb()->buffer;
+
+ NtCurrentTeb()->buffer_args = head + 1; /* reset the args buffer */
+
+ vec.iov_base = &seq;
+ vec.iov_len = sizeof(seq);
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
- msghdr.msg_iov = vec;
- msghdr.msg_iovlen = veclen;
+ msghdr.msg_iov = &vec;
+ msghdr.msg_iovlen = 1;
#ifdef HAVE_MSGHDR_ACCRIGHTS
- if (pass_fd != -1) /* we have an fd to send */
- {
- msghdr.msg_accrights = (void *)&pass_fd;
- msghdr.msg_accrightslen = sizeof(pass_fd);
- }
- else
- {
- msghdr.msg_accrights = NULL;
- msghdr.msg_accrightslen = 0;
- }
+ msghdr.msg_accrights = (void *)&fd;
+ msghdr.msg_accrightslen = sizeof(fd);
#else /* HAVE_MSGHDR_ACCRIGHTS */
- if (pass_fd != -1) /* we have an fd to send */
- {
- cmsg.len = sizeof(cmsg);
- cmsg.level = SOL_SOCKET;
- cmsg.type = SCM_RIGHTS;
- cmsg.fd = pass_fd;
- msghdr.msg_control = &cmsg;
- msghdr.msg_controllen = sizeof(cmsg);
- }
- else
- {
- msghdr.msg_control = NULL;
- msghdr.msg_controllen = 0;
- }
- msghdr.msg_flags = 0;
+ cmsg.len = sizeof(cmsg);
+ cmsg.level = SOL_SOCKET;
+ cmsg.type = SCM_RIGHTS;
+ cmsg.fd = fd;
+ msghdr.msg_control = &cmsg;
+ msghdr.msg_controllen = sizeof(cmsg);
+ msghdr.msg_flags = 0;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
- if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) < len)
+ if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(seq)) return;
+ if (ret == -1)
{
- if (ret == -1)
- {
- if (errno == EPIPE) CLIENT_Die();
- perror( "sendmsg" );
- }
- CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
+ if (errno == EPIPE) CLIENT_Die();
+ CLIENT_perror( "sendmsg" );
}
- /* we passed the fd now we can close it */
- if (pass_fd != -1) close( pass_fd );
+ CLIENT_ProtocolError( "partial seq sent %d/%d\n", ret, sizeof(seq) );
}
-
/***********************************************************************
- * CLIENT_SendRequest
- *
- * Send a request to the server.
- */
-void CLIENT_SendRequest( enum request req, int pass_fd,
- int n, ... /* arg_1, len_1, etc. */ )
-{
- struct iovec vec[16];
- va_list args;
- int i;
-
- n++; /* for vec[0] */
- assert( n < 16 );
- va_start( args, n );
- for (i = 1; i < n; i++)
- {
- vec[i].iov_base = va_arg( args, void * );
- vec[i].iov_len = va_arg( args, int );
- }
- va_end( args );
- CLIENT_SendRequest_v( req, pass_fd, vec, n );
-}
-
-
-/***********************************************************************
- * CLIENT_WaitReply_v
+ * wait_reply
*
* Wait for a reply from the server.
- * Returns the error code (or 0 if OK).
*/
-static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
- struct iovec *vec, int veclen )
+static void wait_reply(void)
{
- int pass_fd = -1;
- struct header head;
- int ret, remaining;
+ int seq, ret;
+
+ for (;;)
+ {
+ if ((ret = read( NtCurrentTeb()->socket, &seq, sizeof(seq) )) == sizeof(seq))
+ {
+ if (seq != NtCurrentTeb()->seq++)
+ CLIENT_ProtocolError( "sequence %08x instead of %08x\n", seq, NtCurrentTeb()->seq - 1 );
+ return;
+ }
+ if (ret == -1)
+ {
+ if (errno == EINTR) continue;
+ if (errno == EPIPE) CLIENT_Die();
+ CLIENT_perror("read");
+ }
+ if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
+ CLIENT_ProtocolError( "partial seq received %d/%d\n", ret, sizeof(seq) );
+ }
+}
+
+
+/***********************************************************************
+ * wait_reply_fd
+ *
+ * Wait for a reply from the server, when a file descriptor is passed.
+ */
+static int wait_reply_fd(void)
+{
+ struct iovec vec;
+ int seq, ret;
#ifdef HAVE_MSGHDR_ACCRIGHTS
struct msghdr msghdr;
+ int fd = -1;
- msghdr.msg_accrights = (void *)&pass_fd;
+ msghdr.msg_accrights = (void *)&fd;
msghdr.msg_accrightslen = sizeof(int);
#else /* HAVE_MSGHDR_ACCRIGHTS */
struct msghdr msghdr;
@@ -184,88 +203,136 @@
msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
- msghdr.msg_iov = vec;
- msghdr.msg_iovlen = veclen;
+ msghdr.msg_iov = &vec;
+ msghdr.msg_iovlen = 1;
+ vec.iov_base = &seq;
+ vec.iov_len = sizeof(seq);
- assert( veclen > 0 );
- vec[0].iov_base = &head;
- vec[0].iov_len = sizeof(head);
-
- while ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == -1)
+ for (;;)
{
- if (errno == EINTR) continue;
- if (errno == EPIPE) CLIENT_Die();
- perror("recvmsg");
- CLIENT_ProtocolError( "recvmsg\n" );
- }
- if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
-
- /* sanity checks */
-
- if (ret < sizeof(head))
- CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
-
- if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
- CLIENT_ProtocolError( "header length %d\n", head.len );
-
- if (head.seq != NtCurrentTeb()->seq++)
- CLIENT_ProtocolError( "sequence %08x instead of %08x\n",
- head.seq, NtCurrentTeb()->seq - 1 );
-
-#ifndef HAVE_MSGHDR_ACCRIGHTS
- pass_fd = cmsg.fd;
-#endif
-
- if (passed_fd)
- {
- *passed_fd = pass_fd;
- pass_fd = -1;
- }
-
- if (len) *len = ret - sizeof(head);
- if (pass_fd != -1) close( pass_fd );
- remaining = head.len - ret;
- while (remaining > 0) /* get remaining data */
- {
- char *bufp, buffer[1024];
- int addlen, i, iovtot = 0;
-
- /* see if any iovs are still incomplete, otherwise drop the rest */
- for (i = 0; i < veclen && remaining > 0; i++)
- {
- if (iovtot + vec[i].iov_len > head.len - remaining)
- {
- addlen = iovtot + vec[i].iov_len - (head.len - remaining);
- bufp = (char *)vec[i].iov_base + (vec[i].iov_len - addlen);
- if (addlen > remaining) addlen = remaining;
- if ((addlen = recv( NtCurrentTeb()->socket, bufp, addlen, 0 )) == -1)
- {
- perror( "recv" );
- CLIENT_ProtocolError( "recv\n" );
- }
- if (!addlen) CLIENT_Die(); /* the server closed the connection; time to die... */
- if (len) *len += addlen;
- remaining -= addlen;
- }
- iovtot += vec[i].iov_len;
- }
-
- if (remaining > 0)
- addlen = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
- else
- break;
-
- if ((addlen = recv( NtCurrentTeb()->socket, buffer, addlen, 0 )) == -1)
+ if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(seq))
{
- perror( "recv" );
- CLIENT_ProtocolError( "recv\n" );
+ if (seq != NtCurrentTeb()->seq++)
+ CLIENT_ProtocolError( "sequence %08x instead of %08x\n", seq, NtCurrentTeb()->seq - 1 );
+#ifdef HAVE_MSGHDR_ACCRIGHTS
+ return fd;
+#else
+ return cmsg.fd;
+#endif
}
- if (!addlen) CLIENT_Die(); /* the server closed the connection; time to die... */
- remaining -= addlen;
+ if (ret == -1)
+ {
+ if (errno == EINTR) continue;
+ if (errno == EPIPE) CLIENT_Die();
+ CLIENT_perror("recvmsg");
+ }
+ if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
+ CLIENT_ProtocolError( "partial seq received %d/%d\n", ret, sizeof(seq) );
}
+}
- if (head.type) SetLastError( head.type );
- return head.type; /* error code */
+
+/***********************************************************************
+ * server_call
+ *
+ * Perform a server call.
+ */
+unsigned int server_call( enum request req )
+{
+ struct header *head;
+
+ send_request( req );
+ wait_reply();
+
+ head = (struct header *)NtCurrentTeb()->buffer;
+ if ((head->len < sizeof(*head)) || (head->len > NtCurrentTeb()->buffer_size))
+ CLIENT_ProtocolError( "header length %d\n", head->len );
+ if (head->type) SetLastError( head->type );
+ return head->type; /* error code */
+}
+
+/***********************************************************************
+ * server_call_fd
+ *
+ * Perform a server call, passing a file descriptor.
+ * If *fd is != -1, it will be passed to the server.
+ * If the server passes an fd, it will be stored into *fd.
+ */
+unsigned int server_call_fd( enum request req, int *fd )
+{
+ struct header *head;
+
+ if (*fd == -1) send_request( req );
+ else send_request_fd( req, *fd );
+ *fd = wait_reply_fd();
+
+ head = (struct header *)NtCurrentTeb()->buffer;
+ if ((head->len < sizeof(*head)) || (head->len > NtCurrentTeb()->buffer_size))
+ CLIENT_ProtocolError( "header length %d\n", head->len );
+ if (head->type) SetLastError( head->type );
+ return head->type; /* error code */
+}
+
+/***********************************************************************
+ * CLIENT_SendRequest
+ *
+ * Send a request to the server.
+ */
+void CLIENT_SendRequest( enum request req, int pass_fd,
+ int n, ... /* arg_1, len_1, etc. */ )
+{
+ va_list args;
+
+ va_start( args, n );
+ while (n--)
+ {
+ void *ptr = va_arg( args, void * );
+ int len = va_arg( args, int );
+ memcpy( server_add_data( len ), ptr, len );
+ }
+ va_end( args );
+
+ if (pass_fd == -1) send_request( req );
+ else
+ {
+ send_request_fd( req, pass_fd );
+ close( pass_fd ); /* we passed the fd now we can close it */
+ }
+}
+
+
+/***********************************************************************
+ * CLIENT_WaitReply_v
+ *
+ * Wait for a reply from the server.
+ * Returns the error code (or 0 if OK).
+ */
+static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
+ struct iovec *vec, int veclen )
+{
+ struct header *head;
+ char *ptr;
+ int i, remaining;
+
+ if (passed_fd) *passed_fd = wait_reply_fd();
+ else wait_reply();
+
+ head = (struct header *)NtCurrentTeb()->buffer;
+ if ((head->len < sizeof(*head)) || (head->len > NtCurrentTeb()->buffer_size))
+ CLIENT_ProtocolError( "header length %d\n", head->len );
+
+ remaining = head->len - sizeof(*head);
+ ptr = (char *)(head + 1);
+ for (i = 0; i < veclen; i++, vec++)
+ {
+ int len = MIN( remaining, vec->iov_len );
+ memcpy( vec->iov_base, ptr, len );
+ ptr += len;
+ if (!(remaining -= len)) break;
+ }
+ if (len) *len = head->len - sizeof(*head);
+ if (head->type) SetLastError( head->type );
+ return head->type; /* error code */
}
@@ -281,10 +348,9 @@
va_list args;
int i;
- n++; /* for vec[0] */
assert( n < 16 );
va_start( args, n );
- for (i = 1; i < n; i++)
+ for (i = 0; i < n; i++)
{
vec[i].iov_base = va_arg( args, void * );
vec[i].iov_len = va_arg( args, int );
@@ -301,13 +367,13 @@
*/
unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd )
{
- struct iovec vec[2];
+ struct iovec vec;
unsigned int ret;
int got;
- vec[1].iov_base = reply;
- vec[1].iov_len = len;
- ret = CLIENT_WaitReply_v( &got, passed_fd, vec, 2 );
+ vec.iov_base = reply;
+ vec.iov_len = len;
+ ret = CLIENT_WaitReply_v( &got, passed_fd, &vec, 1 );
if (got != len)
CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
return ret;
@@ -363,13 +429,22 @@
{
struct init_thread_request req;
struct init_thread_reply reply;
+ TEB *teb = NtCurrentTeb();
+
+ int fd = wait_reply_fd();
+ if (fd == -1) CLIENT_ProtocolError( "no fd passed on first request\n" );
+ if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) CLIENT_perror( "lseek" );
+ teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
+ close( fd );
+ if (teb->buffer == (void*)-1) CLIENT_perror( "mmap" );
+ teb->buffer_args = (char *)teb->buffer + sizeof(struct header);
req.unix_pid = getpid();
- req.teb = NtCurrentTeb();
+ req.teb = teb;
CLIENT_SendRequest( REQ_INIT_THREAD, -1, 1, &req, sizeof(req) );
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return -1;
- NtCurrentTeb()->process->server_pid = reply.pid;
- NtCurrentTeb()->tid = reply.tid;
+ teb->process->server_pid = reply.pid;
+ teb->tid = reply.tid;
return 0;
}