Use a separate FIFO pair for server requests that don't need to pass a
file descriptor.
Associate file descriptors with handles on the server side so that we
don't need to pass the fd every time the client wants to use it.
diff --git a/scheduler/client.c b/scheduler/client.c
index a936f73..607e566 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -157,7 +157,7 @@
header->req = req;
NtCurrentTeb()->buffer_info->cur_req = (char *)header - (char *)NtCurrentTeb()->buffer;
/* write a single byte; the value is ignored anyway */
- if (write( NtCurrentTeb()->socket, header, 1 ) == -1)
+ if (write( NtCurrentTeb()->request_fd, header, 1 ) == -1)
{
if (errno == EPIPE) SYSDEPS_ExitThread(0);
server_perror( "sendmsg" );
@@ -220,7 +220,7 @@
for (;;)
{
- if ((ret = read( NtCurrentTeb()->socket, dummy, 1 )) > 0) return;
+ if ((ret = read( NtCurrentTeb()->reply_fd, dummy, 1 )) > 0) return;
if (!ret) break;
if (errno == EINTR) continue;
if (errno == EPIPE) break;
@@ -232,62 +232,6 @@
/***********************************************************************
- * wait_reply_fd
- *
- * Wait for a reply from the server, when a file descriptor is passed.
- */
-static void wait_reply_fd( int *fd )
-{
- struct iovec vec;
- int ret;
- char dummy[1];
-
-#ifdef HAVE_MSGHDR_ACCRIGHTS
- struct msghdr msghdr;
-
- *fd = -1;
- msghdr.msg_accrights = (void *)fd;
- msghdr.msg_accrightslen = sizeof(*fd);
-#else /* HAVE_MSGHDR_ACCRIGHTS */
- struct msghdr msghdr;
- struct cmsg_fd cmsg;
-
- cmsg.len = sizeof(cmsg);
- cmsg.level = SOL_SOCKET;
- cmsg.type = SCM_RIGHTS;
- cmsg.fd = -1;
- msghdr.msg_control = &cmsg;
- msghdr.msg_controllen = sizeof(cmsg);
- msghdr.msg_flags = 0;
-#endif /* HAVE_MSGHDR_ACCRIGHTS */
-
- msghdr.msg_name = NULL;
- msghdr.msg_namelen = 0;
- msghdr.msg_iov = &vec;
- msghdr.msg_iovlen = 1;
- vec.iov_base = (void *)dummy;
- vec.iov_len = 1;
-
- for (;;)
- {
- if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) > 0)
- {
-#ifndef HAVE_MSGHDR_ACCRIGHTS
- *fd = cmsg.fd;
-#endif
- return;
- }
- if (!ret) break;
- if (errno == EINTR) continue;
- if (errno == EPIPE) break;
- server_perror("recvmsg");
- }
- /* the server closed the connection; time to die... */
- SYSDEPS_ExitThread(0);
-}
-
-
-/***********************************************************************
* wine_server_call
*
* Perform a server call.
@@ -305,19 +249,14 @@
* 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_out, int *fd_in )
+unsigned int server_call_fd( enum request req, int fd_out )
{
unsigned int res;
void *req_ptr = get_req_buffer();
- if (fd_out == -1) send_request( req, req_ptr );
- else send_request_fd( req, req_ptr, fd_out );
-
- if (fd_in) wait_reply_fd( fd_in );
- else wait_reply();
+ send_request_fd( req, req_ptr, fd_out );
+ wait_reply();
if ((res = ((struct request_header *)req_ptr)->error))
SetLastError( RtlNtStatusToDosError(res) );
@@ -326,6 +265,105 @@
/***********************************************************************
+ * set_handle_fd
+ *
+ * Store the fd for a given handle in the server
+ */
+static int set_handle_fd( int handle, int fd )
+{
+ SERVER_START_REQ
+ {
+ struct set_handle_info_request *req = wine_server_alloc_req( sizeof(*req), 0 );
+ req->handle = handle;
+ req->flags = 0;
+ req->mask = 0;
+ req->fd = fd;
+ if (!server_call( REQ_SET_HANDLE_INFO ))
+ {
+ if (req->cur_fd != fd)
+ {
+ /* someone was here before us */
+ close( fd );
+ fd = req->cur_fd;
+ }
+ else fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
+ }
+ else
+ {
+ close( fd );
+ fd = -1;
+ }
+ }
+ SERVER_END_REQ;
+ return fd;
+}
+
+
+/***********************************************************************
+ * wine_server_recv_fd
+ *
+ * Receive a file descriptor passed from the server.
+ * The file descriptor must be closed after use.
+ */
+int wine_server_recv_fd( int handle, int cache )
+{
+ struct iovec vec;
+ int ret, fd, server_handle;
+
+#ifdef HAVE_MSGHDR_ACCRIGHTS
+ struct msghdr msghdr;
+
+ fd = -1;
+ msghdr.msg_accrights = (void *)&fd;
+ msghdr.msg_accrightslen = sizeof(fd);
+#else /* HAVE_MSGHDR_ACCRIGHTS */
+ struct msghdr msghdr;
+ struct cmsg_fd cmsg;
+
+ cmsg.len = sizeof(cmsg);
+ cmsg.level = SOL_SOCKET;
+ cmsg.type = SCM_RIGHTS;
+ cmsg.fd = -1;
+ msghdr.msg_control = &cmsg;
+ msghdr.msg_controllen = sizeof(cmsg);
+ msghdr.msg_flags = 0;
+#endif /* HAVE_MSGHDR_ACCRIGHTS */
+
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = &vec;
+ msghdr.msg_iovlen = 1;
+ vec.iov_base = (void *)&server_handle;
+ vec.iov_len = sizeof(server_handle);
+
+ for (;;)
+ {
+ if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) > 0)
+ {
+#ifndef HAVE_MSGHDR_ACCRIGHTS
+ fd = cmsg.fd;
+#endif
+ if (handle != server_handle)
+ server_protocol_error( "recv_fd: got handle %d, expected %d\n",
+ server_handle, handle );
+ if (cache)
+ {
+ fd = set_handle_fd( handle, fd );
+ if (fd != -1) fd = dup(fd);
+ }
+ return fd;
+ }
+ if (!ret) break;
+ if (errno == EINTR) continue;
+ if (errno == EPIPE) break;
+ server_perror("recvmsg");
+ }
+ /* the server closed the connection; time to die... */
+ SYSDEPS_ExitThread(0);
+}
+
+
+/***********************************************************************
* get_config_dir
*
* Return the configuration directory ($WINEPREFIX or $HOME/.wine)
@@ -564,8 +602,16 @@
/* ignore SIGPIPE so that we get a EPIPE error instead */
signal( SIGPIPE, SIG_IGN );
- wait_reply_fd( &fd );
- if (fd == -1) server_protocol_error( "no fd passed on first request\n" );
+ teb->request_fd = wine_server_recv_fd( -1, 0 );
+ if (teb->request_fd == -1) server_protocol_error( "no request fd passed on first request\n" );
+ fcntl( teb->request_fd, F_SETFD, 1 ); /* set close on exec flag */
+
+ teb->reply_fd = wine_server_recv_fd( -1, 0 );
+ if (teb->reply_fd == -1) server_protocol_error( "no reply fd passed on first request\n" );
+ fcntl( teb->reply_fd, F_SETFD, 1 ); /* set close on exec flag */
+
+ fd = wine_server_recv_fd( -1, 0 );
+ if (fd == -1) server_protocol_error( "no fd received for thread buffer\n" );
if ((size = lseek( fd, 0, SEEK_END )) == -1) server_perror( "lseek" );
teb->buffer = mmap( 0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
@@ -573,6 +619,8 @@
if (teb->buffer == (void*)-1) server_perror( "mmap" );
teb->buffer_info = (struct server_buffer_info *)((char *)teb->buffer + size) - 1;
+ wait_reply();
+
req = (struct get_thread_buffer_request *)teb->buffer;
teb->pid = req->pid;
teb->tid = req->tid;
@@ -597,6 +645,7 @@
return ret;
}
+
/***********************************************************************
* CLIENT_BootDone
*