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/dlls/ntdll/om.c b/dlls/ntdll/om.c
index 3e31fc8..e8a70cf 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "debugtools.h"
#include "ntddk.h"
@@ -221,6 +222,7 @@
struct close_handle_request *req = server_alloc_req( sizeof(*req), 0 );
req->handle = Handle;
ret = server_call_noerr( REQ_CLOSE_HANDLE );
+ if (!ret && req->fd != -1) close( req->fd );
}
SERVER_END_REQ;
return ret;
diff --git a/files/file.c b/files/file.c
index 3d957aa..3d5e0e4 100644
--- a/files/file.c
+++ b/files/file.c
@@ -185,7 +185,7 @@
{
struct alloc_file_handle_request *req = get_req_buffer();
req->access = access;
- server_call_fd( REQ_ALLOC_FILE_HANDLE, fd, NULL );
+ server_call_fd( REQ_ALLOC_FILE_HANDLE, fd );
return req->handle;
}
@@ -197,12 +197,21 @@
*/
int FILE_GetUnixHandle( HANDLE handle, DWORD access )
{
- int unix_handle = -1;
- struct get_handle_fd_request *req = get_req_buffer();
- req->handle = handle;
- req->access = access;
- server_call_fd( REQ_GET_HANDLE_FD, -1, &unix_handle );
- return unix_handle;
+ int ret, fd = -1;
+ SERVER_START_REQ
+ {
+ struct get_handle_fd_request *req = wine_server_alloc_req( sizeof(*req), 0 );
+ req->handle = handle;
+ req->access = access;
+ if (!(ret = server_call( REQ_GET_HANDLE_FD ))) fd = req->fd;
+ }
+ SERVER_END_REQ;
+ if (!ret)
+ {
+ if (fd == -1) return wine_server_recv_fd( handle, 1 );
+ fd = dup(fd);
+ }
+ return fd;
}
diff --git a/include/server.h b/include/server.h
index f0a614d..d7c7075 100644
--- a/include/server.h
+++ b/include/server.h
@@ -359,15 +359,7 @@
{
REQUEST_HEADER; /* request header */
IN int handle; /* handle to close */
-};
-
-
-/* Get information about a handle */
-struct get_handle_info_request
-{
- REQUEST_HEADER; /* request header */
- IN int handle; /* handle we are interested in */
- OUT int flags; /* handle flags */
+ OUT int fd; /* associated fd to close */
};
@@ -378,6 +370,9 @@
IN int handle; /* handle we are interested in */
IN int flags; /* new handle flags */
IN int mask; /* mask for flags to set */
+ IN int fd; /* file descriptor or -1 */
+ OUT int old_flags; /* old flag value */
+ OUT int cur_fd; /* current file descriptor */
};
@@ -392,6 +387,7 @@
IN int inherit; /* inherit flag */
IN int options; /* duplicate options (see below) */
OUT int handle; /* duplicated handle in dst process */
+ OUT int fd; /* associated fd to close */
};
#define DUP_HANDLE_CLOSE_SOURCE DUPLICATE_CLOSE_SOURCE
#define DUP_HANDLE_SAME_ACCESS DUPLICATE_SAME_ACCESS
@@ -860,6 +856,7 @@
OUT void* base; /* default base addr (for VPROT_IMAGE mapping) */
OUT int shared_file; /* shared mapping file handle */
OUT int shared_size; /* shared mapping size */
+ OUT int anonymous; /* anonymous mapping? */
};
@@ -1373,7 +1370,6 @@
REQ_QUEUE_APC,
REQ_GET_APC,
REQ_CLOSE_HANDLE,
- REQ_GET_HANDLE_INFO,
REQ_SET_HANDLE_INFO,
REQ_DUP_HANDLE,
REQ_OPEN_PROCESS,
@@ -1489,7 +1485,6 @@
struct queue_apc_request queue_apc;
struct get_apc_request get_apc;
struct close_handle_request close_handle;
- struct get_handle_info_request get_handle_info;
struct set_handle_info_request set_handle_info;
struct dup_handle_request dup_handle;
struct open_process_request open_process;
@@ -1579,7 +1574,7 @@
struct async_result_request async_result;
};
-#define SERVER_PROTOCOL_VERSION 30
+#define SERVER_PROTOCOL_VERSION 31
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
@@ -1605,9 +1600,10 @@
/* client communication functions */
extern unsigned int wine_server_call( enum request req );
-extern unsigned int server_call_fd( enum request req, int fd_out, int *fd_in );
+extern unsigned int server_call_fd( enum request req, int fd_out );
extern void server_protocol_error( const char *err, ... ) WINE_NORETURN;
extern void *wine_server_alloc_req( size_t fixed_size, size_t var_size );
+extern int wine_server_recv_fd( int handle, int cache );
extern const char *get_config_dir(void);
/* compatibility macros */
diff --git a/include/thread.h b/include/thread.h
index 72a3ea8..572b981 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -94,13 +94,15 @@
DWORD cleanup; /* --3 1fc Cleanup service handle */
int socket; /* --3 200 Socket for server communication */
void *buffer; /* --3 204 Buffer shared with server */
- struct server_buffer_info *buffer_info; /* --3 208 Buffer information */
- void *debug_info; /* --3 20c Info for debugstr functions */
- void *pthread_data; /* --3 210 Data for pthread emulation */
+ int request_fd; /* --3 208 fd for sending server requests */
+ int reply_fd; /* --3 20c fd for receiving server replies */
+ struct server_buffer_info *buffer_info; /* --3 210 Buffer information */
+ void *debug_info; /* --3 214 Info for debugstr functions */
+ void *pthread_data; /* --3 218 Data for pthread emulation */
/* here is plenty space for wine specific fields (don't forget to change pad6!!) */
/* the following are nt specific fields */
- DWORD pad6[633]; /* --n 214 */
+ DWORD pad6[631]; /* --n 21c */
UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */
USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */
DWORD pad7; /* --n e0c */
diff --git a/loader/ne/module.c b/loader/ne/module.c
index 3cc10d7..f4fc76a 100644
--- a/loader/ne/module.c
+++ b/loader/ne/module.c
@@ -1019,7 +1019,7 @@
LPSTR cmdline;
WORD cmdShow;
HANDLE hThread = -1;
- int socket;
+ int socket = -1;
/* Load module */
@@ -1066,7 +1066,11 @@
struct new_thread_request *req = server_alloc_req( sizeof(*req), 0 );
req->suspend = 0;
req->inherit = 0;
- if (!server_call_fd( REQ_NEW_THREAD, -1, &socket )) hThread = req->handle;
+ if (!server_call( REQ_NEW_THREAD ))
+ {
+ hThread = req->handle;
+ socket = wine_server_recv_fd( hThread, 0 );
+ }
}
SERVER_END_REQ;
if (hThread == -1) return 0;
diff --git a/memory/virtual.c b/memory/virtual.c
index e104336..a94d3a5 100644
--- a/memory/virtual.c
+++ b/memory/virtual.c
@@ -1478,8 +1478,10 @@
UINT ptr = (UINT)-1, size = 0;
int flags = MAP_PRIVATE;
int unix_handle = -1;
- int prot;
- struct get_mapping_info_request *req = get_req_buffer();
+ int prot, anonymous, res;
+ void *base;
+ DWORD size_low, size_high, header_size, shared_size;
+ HANDLE shared_file;
/* Check parameters */
@@ -1490,25 +1492,44 @@
return NULL;
}
- req->handle = handle;
- if (server_call_fd( REQ_GET_MAPPING_INFO, -1, &unix_handle )) goto error;
- prot = req->protect;
+ SERVER_START_REQ
+ {
+ struct get_mapping_info_request *req = server_alloc_req( sizeof(*req), 0 );
+ req->handle = handle;
+ res = server_call( REQ_GET_MAPPING_INFO );
+ prot = req->protect;
+ base = req->base;
+ size_low = req->size_low;
+ size_high = req->size_high;
+ header_size = req->header_size;
+ shared_file = req->shared_file;
+ shared_size = req->shared_size;
+ anonymous = req->anonymous;
+ }
+ SERVER_END_REQ;
+ if (res) goto error;
+
+ if (!anonymous)
+ {
+ if ((unix_handle = FILE_GetUnixHandle( handle, 0 )) == -1) goto error;
+ }
if (prot & VPROT_IMAGE)
- return map_image( handle, unix_handle, req->base, req->size_low, req->header_size,
- req->shared_file, req->shared_size );
+ return map_image( handle, unix_handle, base, size_low, header_size,
+ shared_file, shared_size );
- if (req->size_high || offset_high)
+
+ if (size_high || offset_high)
ERR("Offsets larger than 4Gb not supported\n");
- if ((offset_low >= req->size_low) ||
- (count > req->size_low - offset_low))
+ if ((offset_low >= size_low) ||
+ (count > size_low - offset_low))
{
SetLastError( ERROR_INVALID_PARAMETER );
goto error;
}
if (count) size = ROUND_SIZE( offset_low, count );
- else size = req->size_low - offset_low;
+ else size = size_low - offset_low;
switch(access)
{
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
*
diff --git a/scheduler/handle.c b/scheduler/handle.c
index 21c6021..f60d4b8 100644
--- a/scheduler/handle.c
+++ b/scheduler/handle.c
@@ -6,6 +6,7 @@
#include <assert.h>
#include <stdio.h>
+#include <unistd.h>
#include "winbase.h"
#include "server.h"
#include "winerror.h"
@@ -40,10 +41,13 @@
BOOL ret;
SERVER_START_REQ
{
- struct get_handle_info_request *req = server_alloc_req( sizeof(*req), 0 );
+ struct set_handle_info_request *req = server_alloc_req( sizeof(*req), 0 );
req->handle = handle;
- ret = !server_call( REQ_GET_HANDLE_INFO );
- if (ret && flags) *flags = req->flags;
+ req->flags = 0;
+ req->mask = 0;
+ req->fd = -1;
+ ret = !server_call( REQ_SET_HANDLE_INFO );
+ if (ret && flags) *flags = req->old_flags;
}
SERVER_END_REQ;
return ret;
@@ -62,6 +66,7 @@
req->handle = handle;
req->flags = flags;
req->mask = mask;
+ req->fd = -1;
ret = !server_call( REQ_SET_HANDLE_INFO );
}
SERVER_END_REQ;
@@ -89,7 +94,11 @@
req->options = options;
ret = !server_call( REQ_DUP_HANDLE );
- if (ret && dest) *dest = req->handle;
+ if (ret)
+ {
+ if (dest) *dest = req->handle;
+ if (req->fd != -1) close( req->fd );
+ }
}
SERVER_END_REQ;
return ret;
diff --git a/scheduler/thread.c b/scheduler/thread.c
index e894292..afc1a11 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -91,7 +91,9 @@
teb->tls_ptr = teb->tls_array;
teb->exit_code = STILL_ACTIVE;
teb->socket = -1;
- teb->stack_top = (void *)~0UL;
+ teb->request_fd = -1;
+ teb->reply_fd = -1;
+ teb->stack_top = (void *)~0UL;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, WINE_LDT_FLAGS_DATA|WINE_LDT_FLAGS_32BIT );
@@ -113,6 +115,8 @@
/* Free the associated memory */
if (teb->socket != -1) close( teb->socket );
+ close( NtCurrentTeb()->request_fd );
+ close( NtCurrentTeb()->reply_fd );
if (teb->stack_sel) FreeSelector16( teb->stack_sel );
FreeSelector16( teb->teb_sel );
if (teb->buffer) munmap( (void *)teb->buffer,
@@ -280,7 +284,7 @@
LPTHREAD_START_ROUTINE start, LPVOID param,
DWORD flags, LPDWORD id )
{
- int socket, handle = -1;
+ int socket = -1, handle = -1;
TEB *teb;
void *tid = 0;
@@ -290,10 +294,11 @@
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
- if (!server_call_fd( REQ_NEW_THREAD, -1, &socket ))
+ if (!server_call( REQ_NEW_THREAD ))
{
handle = req->handle;
tid = req->tid;
+ socket = wine_server_recv_fd( handle, 0 );
}
}
SERVER_END_REQ;
diff --git a/server/console.c b/server/console.c
index 6f72ade..dcdc287 100644
--- a/server/console.c
+++ b/server/console.c
@@ -419,7 +419,7 @@
if ((out = alloc_handle( current->process, current->process->console_out,
req->access, req->inherit )) != -1)
goto done; /* everything is fine */
- close_handle( current->process, in );
+ close_handle( current->process, in, NULL );
in = -1;
}
free_console( current->process );
diff --git a/server/debugger.c b/server/debugger.c
index c88f82e..7f84410 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -118,7 +118,7 @@
/* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
{
- close_handle( debugger, event->data.info.create_process.process );
+ close_handle( debugger, event->data.info.create_process.process, NULL );
return 0;
}
event->data.info.create_process.thread = handle;
@@ -128,8 +128,8 @@
/* the doc says write access too, but this doesn't seem a good idea */
((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1))
{
- close_handle( debugger, event->data.info.create_process.process );
- close_handle( debugger, event->data.info.create_process.thread );
+ close_handle( debugger, event->data.info.create_process.process, NULL );
+ close_handle( debugger, event->data.info.create_process.thread, NULL );
return 0;
}
event->data.info.create_process.file = handle;
@@ -316,17 +316,17 @@
switch(event->data.code)
{
case CREATE_THREAD_DEBUG_EVENT:
- close_handle( debugger, event->data.info.create_thread.handle );
+ close_handle( debugger, event->data.info.create_thread.handle, NULL );
break;
case CREATE_PROCESS_DEBUG_EVENT:
if (event->data.info.create_process.file != -1)
- close_handle( debugger, event->data.info.create_process.file );
- close_handle( debugger, event->data.info.create_process.thread );
- close_handle( debugger, event->data.info.create_process.process );
+ close_handle( debugger, event->data.info.create_process.file, NULL );
+ close_handle( debugger, event->data.info.create_process.thread, NULL );
+ close_handle( debugger, event->data.info.create_process.process, NULL );
break;
case LOAD_DLL_DEBUG_EVENT:
if (event->data.info.load_dll.handle != -1)
- close_handle( debugger, event->data.info.load_dll.handle );
+ close_handle( debugger, event->data.info.load_dll.handle, NULL );
break;
}
}
diff --git a/server/file.c b/server/file.c
index 5c0f59a..e0ce8a7 100644
--- a/server/file.c
+++ b/server/file.c
@@ -325,11 +325,6 @@
return (struct file *)get_handle_obj( process, handle, access, &file_ops );
}
-int file_get_mmap_fd( struct file *file )
-{
- return dup( file->obj.fd );
-}
-
static int set_file_pointer( int handle, int *low, int *high, int whence )
{
struct file *file;
@@ -479,7 +474,8 @@
req->fd = -1;
if ((obj = get_handle_obj( current->process, req->handle, req->access, NULL )))
{
- set_reply_fd( current, obj->ops->get_fd( obj ) );
+ if ((req->fd = get_handle_fd( current->process, req->handle, req->access )) == -1)
+ send_client_fd( current, obj->ops->get_fd( obj ), req->handle );
release_object( obj );
}
}
diff --git a/server/handle.c b/server/handle.c
index 1d1317f..6a3e1f6 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -19,8 +19,9 @@
struct handle_entry
{
- struct object *ptr;
- unsigned int access;
+ struct object *ptr; /* object */
+ unsigned int access; /* access rights */
+ int fd; /* file descriptor (in client process) */
};
struct handle_table
@@ -173,6 +174,7 @@
table->free = i + 1;
entry->ptr = grab_object( obj );
entry->access = access;
+ entry->fd = -1;
return index_to_handle(i);
}
@@ -269,6 +271,7 @@
for (i = 0; i <= table->last; i++, ptr++)
{
if (!ptr->ptr) continue;
+ ptr->fd = -1;
if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
else ptr->ptr = NULL; /* don't inherit this entry */
}
@@ -280,7 +283,7 @@
/* close a handle and decrement the refcount of the associated object */
/* return 1 if OK, 0 on error */
-int close_handle( struct process *process, int handle )
+int close_handle( struct process *process, int handle, int *fd )
{
struct handle_table *table;
struct handle_entry *entry;
@@ -294,6 +297,9 @@
}
obj = entry->ptr;
entry->ptr = NULL;
+ if (fd) *fd = entry->fd;
+ else if (entry->fd != -1) return 1; /* silently ignore close attempt if we cannot close the fd */
+ entry->fd = -1;
table = HANDLE_IS_GLOBAL(handle) ? global_table : (struct handle_table *)process->handles;
if (entry < table->entries + table->free) table->free = entry - table->entries;
if (entry == table->entries + table->last) shrink_handle_table( table );
@@ -351,12 +357,28 @@
return grab_object( obj );
}
-/* get/set the handle reserved flags */
-/* return the new flags (or -1 on error) */
-static int set_handle_info( struct process *process, int handle, int mask, int flags )
+/* retrieve the cached fd for a given handle */
+int get_handle_fd( struct process *process, int handle, unsigned int access )
{
struct handle_entry *entry;
+ if (HANDLE_IS_GLOBAL(handle)) return -1; /* no fd cache for global handles */
+ if (!(entry = get_handle( process, handle ))) return -1;
+ if ((entry->access & access) != access)
+ {
+ set_error( STATUS_ACCESS_DENIED );
+ return -1;
+ }
+ return entry->fd;
+}
+
+/* get/set the handle reserved flags */
+/* return the old flags (or -1 on error) */
+static int set_handle_info( struct process *process, int handle, int mask, int flags, int *fd )
+{
+ struct handle_entry *entry;
+ unsigned int old_access;
+
if (get_magic_handle( handle ))
{
/* we can retrieve but not set info for magic handles */
@@ -364,10 +386,14 @@
return 0;
}
if (!(entry = get_handle( process, handle ))) return -1;
+ old_access = entry->access;
mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
flags = (flags << RESERVED_SHIFT) & mask;
entry->access = (entry->access & ~mask) | flags;
- return (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
+ /* if no current fd set it, otherwise return current fd */
+ if (entry->fd == -1) entry->fd = *fd;
+ *fd = entry->fd;
+ return (old_access & RESERVED_ALL) >> RESERVED_SHIFT;
}
/* duplicate a handle */
@@ -420,19 +446,17 @@
/* close a handle */
DECL_HANDLER(close_handle)
{
- close_handle( current->process, req->handle );
-}
-
-/* get information about a handle */
-DECL_HANDLER(get_handle_info)
-{
- req->flags = set_handle_info( current->process, req->handle, 0, 0 );
+ close_handle( current->process, req->handle, &req->fd );
}
/* set a handle information */
DECL_HANDLER(set_handle_info)
{
- set_handle_info( current->process, req->handle, req->mask, req->flags );
+ int fd = req->fd;
+
+ if (HANDLE_IS_GLOBAL(req->handle)) fd = -1; /* no fd cache for global handles */
+ req->old_flags = set_handle_info( current->process, req->handle, req->mask, req->flags, &fd );
+ req->cur_fd = fd;
}
/* duplicate a handle */
@@ -441,6 +465,7 @@
struct process *src, *dst;
req->handle = -1;
+ req->fd = -1;
if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
{
if (req->options & DUP_HANDLE_MAKE_GLOBAL)
@@ -456,7 +481,10 @@
}
/* close the handle no matter what happened */
if (req->options & DUP_HANDLE_CLOSE_SOURCE)
- close_handle( src, req->src_handle );
+ {
+ if (src == current->process) close_handle( src, req->src_handle, &req->fd );
+ else close_handle( src, req->src_handle, NULL );
+ }
release_object( src );
}
}
diff --git a/server/handle.h b/server/handle.h
index 7bba30b..d648dd7 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -23,9 +23,10 @@
/* that the thing pointed to starts with a struct object... */
extern int alloc_handle( struct process *process, void *obj,
unsigned int access, int inherit );
-extern int close_handle( struct process *process, int handle );
+extern int close_handle( struct process *process, int handle, int *fd );
extern struct object *get_handle_obj( struct process *process, int handle,
unsigned int access, const struct object_ops *ops );
+extern int get_handle_fd( struct process *process, int handle, unsigned int access );
extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
unsigned int access, int inherit, int options );
extern int open_object( const WCHAR *name, size_t len, const struct object_ops *ops,
diff --git a/server/mapping.c b/server/mapping.c
index a68e8fb..38d1d89 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -30,6 +30,7 @@
int shared_size; /* shared mapping total size */
};
+static int mapping_get_fd( struct object *obj );
static void mapping_dump( struct object *obj, int verbose );
static void mapping_destroy( struct object *obj );
@@ -43,7 +44,7 @@
NULL, /* satisfied */
NULL, /* get_poll_events */
NULL, /* poll_event */
- no_get_fd, /* get_fd */
+ mapping_get_fd, /* get_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
mapping_destroy /* destroy */
@@ -86,6 +87,13 @@
#define ROUND_SIZE(addr,size) \
(((int)(size) + ((int)(addr) & page_mask) + page_mask) & ~page_mask)
+/* get the fd to use for mmaping a file */
+inline static int get_mmap_fd( struct file *file )
+{
+ struct object *obj;
+ if (!(obj = (struct object *)file)) return -1;
+ return obj->ops->get_fd( obj );
+}
/* allocate and fill the temp file for a shared PE image mapping */
static int build_shared_mapping( struct mapping *mapping, int fd,
@@ -115,7 +123,7 @@
if (!(mapping->shared_file = create_temp_file( GENERIC_READ|GENERIC_WRITE ))) goto error;
if (!grow_file( mapping->shared_file, 0, total_size )) goto error;
- if ((shared_fd = file_get_mmap_fd( mapping->shared_file )) == -1) goto error;
+ if ((shared_fd = get_mmap_fd( mapping->shared_file )) == -1) goto error;
if (!(buffer = malloc( max_size ))) goto error;
@@ -159,7 +167,7 @@
/* load the headers */
- if ((fd = file_get_mmap_fd( mapping->file )) == -1) return 0;
+ if ((fd = get_mmap_fd( mapping->file )) == -1) return 0;
filepos = lseek( fd, 0, SEEK_SET );
if (read( fd, &dos, sizeof(dos) ) != sizeof(dos)) goto error;
if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error;
@@ -270,6 +278,13 @@
fputc( '\n', stderr );
}
+static int mapping_get_fd( struct object *obj )
+{
+ struct mapping *mapping = (struct mapping *)obj;
+ assert( obj->ops == &mapping_ops );
+ return get_mmap_fd( mapping->file );
+}
+
static void mapping_destroy( struct object *obj )
{
struct mapping *mapping = (struct mapping *)obj;
@@ -323,11 +338,10 @@
req->base = mapping->base;
req->shared_file = -1;
req->shared_size = mapping->shared_size;
+ req->anonymous = !mapping->file;
if (mapping->shared_file)
req->shared_file = alloc_handle( current->process, mapping->shared_file,
GENERIC_READ|GENERIC_WRITE, 0 );
- if (mapping->file) set_reply_fd( current, file_get_mmap_fd( mapping->file ) );
release_object( mapping );
}
}
-
diff --git a/server/object.h b/server/object.h
index 7a7d1a3..deec306 100644
--- a/server/object.h
+++ b/server/object.h
@@ -148,7 +148,6 @@
extern struct file *get_file_obj( struct process *process, int handle,
unsigned int access );
-extern int file_get_mmap_fd( struct file *file );
extern int grow_file( struct file *file, int size_high, int size_low );
extern int create_anonymous_file(void);
extern struct file *create_temp_file( int access );
diff --git a/server/pipe.c b/server/pipe.c
index 5c830c0..7838c12 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -165,7 +165,7 @@
STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
req->inherit );
if (hwrite == -1)
- close_handle( current->process, hread );
+ close_handle( current->process, hread, NULL );
}
release_object( obj[0] );
release_object( obj[1] );
diff --git a/server/request.c b/server/request.c
index c3928e5..fff02dd4 100644
--- a/server/request.c
+++ b/server/request.c
@@ -71,6 +71,32 @@
};
+struct request_socket
+{
+ struct object obj; /* object header */
+ struct thread *thread; /* owning thread */
+};
+
+static void request_socket_dump( struct object *obj, int verbose );
+static void request_socket_poll_event( struct object *obj, int event );
+
+static const struct object_ops request_socket_ops =
+{
+ sizeof(struct request_socket), /* size */
+ request_socket_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ request_socket_poll_event, /* poll_event */
+ no_get_fd, /* get_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ no_destroy /* destroy */
+};
+
+
struct thread *current = NULL; /* thread handling the current request */
unsigned int global_error = 0; /* global error code for when no thread is current */
@@ -149,13 +175,6 @@
fatal_protocol_error( current, "bad request %d\n", req );
}
-/* set the fd to pass to the thread */
-void set_reply_fd( struct thread *thread, int pass_fd )
-{
- assert( thread->pass_fd == -1 );
- thread->pass_fd = pass_fd;
-}
-
/* send a reply to a thread */
void send_reply( struct thread *thread )
{
@@ -213,29 +232,9 @@
header->error = thread->error;
- if (thread->pass_fd == -1)
- {
- /* write a single byte; the value is ignored anyway */
- ret = write( thread->obj.fd, header, 1 );
- }
- else /* we have an fd to send */
- {
-#ifdef HAVE_MSGHDR_ACCRIGHTS
- msghdr.msg_accrightslen = sizeof(int);
- msghdr.msg_accrights = (void *)&thread->pass_fd;
-#else /* HAVE_MSGHDR_ACCRIGHTS */
- msghdr.msg_control = &cmsg;
- msghdr.msg_controllen = sizeof(cmsg);
- cmsg.fd = thread->pass_fd;
-#endif /* HAVE_MSGHDR_ACCRIGHTS */
+ assert (thread->pass_fd == -1);
- myiovec.iov_base = (void *)header;
- myiovec.iov_len = 1;
-
- ret = sendmsg( thread->obj.fd, &msghdr, 0 );
- close( thread->pass_fd );
- thread->pass_fd = -1;
- }
+ ret = write( thread->reply_fd, header, 1 );
if (ret > 0)
{
set_select_events( &thread->obj, POLLIN );
@@ -255,6 +254,40 @@
return -1;
}
+/* send an fd to a client */
+int send_client_fd( struct thread *thread, int fd, int handle )
+{
+ int ret;
+
+#ifdef HAVE_MSGHDR_ACCRIGHTS
+ msghdr.msg_accrightslen = sizeof(fd);
+ msghdr.msg_accrights = (void *)&fd;
+#else /* HAVE_MSGHDR_ACCRIGHTS */
+ msghdr.msg_control = &cmsg;
+ msghdr.msg_controllen = sizeof(cmsg);
+ cmsg.fd = fd;
+#endif /* HAVE_MSGHDR_ACCRIGHTS */
+
+ myiovec.iov_base = (void *)&handle;
+ myiovec.iov_len = sizeof(handle);
+
+ ret = sendmsg( thread->obj.fd, &msghdr, 0 );
+ close( fd );
+
+ if (ret > 0) return 0;
+ if (errno == EPIPE)
+ {
+ kill_thread( thread, 0 ); /* normal death */
+ }
+ else
+ {
+ perror("sendmsg");
+ thread->exit_code = 1;
+ kill_thread( thread, 1 );
+ }
+ return -1;
+}
+
static void master_socket_dump( struct object *obj, int verbose )
{
struct master_socket *sock = (struct master_socket *)obj;
@@ -297,6 +330,61 @@
socket_cleanup();
}
+static void request_socket_dump( struct object *obj, int verbose )
+{
+ struct request_socket *sock = (struct request_socket *)obj;
+ assert( obj->ops == &request_socket_ops );
+ fprintf( stderr, "Request socket fd=%d thread=%p\n", sock->obj.fd, sock->thread );
+}
+
+/* handle a request socket event */
+static void request_socket_poll_event( struct object *obj, int event )
+{
+ struct request_socket *sock = (struct request_socket *)obj;
+ assert( obj->ops == &request_socket_ops );
+
+ if (event & (POLLERR | POLLHUP)) kill_thread( sock->thread, 0 );
+ else if (event & POLLIN)
+ {
+ struct thread *thread = sock->thread;
+ int ret;
+ char dummy[1];
+
+ ret = read( sock->obj.fd, &dummy, 1 );
+ if (ret > 0)
+ {
+ call_req_handler( thread );
+ return;
+ }
+ if (!ret) /* closed pipe */
+ {
+ kill_thread( thread, 0 );
+ return;
+ }
+ perror("read");
+ thread->exit_code = 1;
+ kill_thread( thread, 1 );
+ }
+}
+
+/* create a request socket and send the fd to the client thread */
+struct object *create_request_socket( struct thread *thread )
+{
+ struct request_socket *sock;
+ int fd[2];
+
+ if (pipe( fd )) return NULL;
+ if (!(sock = alloc_object( &request_socket_ops, fd[0] )))
+ {
+ close( fd[1] );
+ return NULL;
+ }
+ sock->thread = thread;
+ send_client_fd( thread, fd[1], -1 );
+ set_select_events( &sock->obj, POLLIN );
+ return &sock->obj;
+}
+
/* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
const char *get_config_dir(void)
{
diff --git a/server/request.h b/server/request.h
index ef856f3..c58d5fb 100644
--- a/server/request.h
+++ b/server/request.h
@@ -33,11 +33,12 @@
extern const char *get_config_dir(void);
extern void read_request( struct thread *thread );
extern int write_request( struct thread *thread );
-extern void set_reply_fd( struct thread *thread, int pass_fd );
+extern int send_client_fd( struct thread *thread, int fd, int handle );
extern void send_reply( struct thread *thread );
extern void open_master_socket(void);
extern void close_master_socket(void);
extern void lock_master_socket( int locked );
+extern struct object *create_request_socket( struct thread *thread );
extern void trace_request( enum request req );
extern void trace_reply( struct thread *thread );
@@ -90,7 +91,6 @@
DECL_HANDLER(queue_apc);
DECL_HANDLER(get_apc);
DECL_HANDLER(close_handle);
-DECL_HANDLER(get_handle_info);
DECL_HANDLER(set_handle_info);
DECL_HANDLER(dup_handle);
DECL_HANDLER(open_process);
@@ -205,7 +205,6 @@
(req_handler)req_queue_apc,
(req_handler)req_get_apc,
(req_handler)req_close_handle,
- (req_handler)req_get_handle_info,
(req_handler)req_set_handle_info,
(req_handler)req_dup_handle,
(req_handler)req_open_process,
diff --git a/server/thread.c b/server/thread.c
index 7cfacdc..12e9377 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -89,26 +89,33 @@
static int alloc_client_buffer( struct thread *thread )
{
struct get_thread_buffer_request *req;
- int fd;
+ int fd, fd_pipe[2];
- if ((fd = create_anonymous_file()) == -1) return -1;
+ if (pipe( fd_pipe ) == -1) return -1;
+ if ((fd = create_anonymous_file()) == -1) goto error;
if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error;
if ((thread->buffer = mmap( 0, MAX_REQUEST_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0 )) == (void*)-1) goto error;
thread->buffer_info = (struct server_buffer_info *)((char *)thread->buffer + MAX_REQUEST_LENGTH) - 1;
+ if (!(thread->request_fd = create_request_socket( thread ))) goto error;
+ thread->reply_fd = fd_pipe[1];
/* build the first request into the buffer and send it */
req = thread->buffer;
req->pid = get_process_id( thread->process );
req->tid = get_thread_id( thread );
req->boot = (thread == booting_thread);
req->version = SERVER_PROTOCOL_VERSION;
- set_reply_fd( thread, fd );
+
+ send_client_fd( thread, fd_pipe[0], -1 );
+ send_client_fd( thread, fd, -1 );
send_reply( thread );
return 1;
error:
file_set_error();
if (fd != -1) close( fd );
+ close( fd_pipe[0] );
+ close( fd_pipe[1] );
return 0;
}
@@ -135,6 +142,8 @@
thread->apc_tail = NULL;
thread->error = 0;
thread->pass_fd = -1;
+ thread->request_fd = NULL;
+ thread->reply_fd = -1;
thread->state = RUNNING;
thread->attached = 0;
thread->exit_code = 0;
@@ -197,7 +206,9 @@
if (thread->info) release_object( thread->info );
if (thread->queue) release_object( thread->queue );
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
+ if (thread->reply_fd != -1) close( thread->reply_fd );
if (thread->pass_fd != -1) close( thread->pass_fd );
+ if (thread->request_fd) release_object( thread->request_fd );
}
/* dump a thread on stdout for debugging purposes */
@@ -618,7 +629,11 @@
wake_up( &thread->obj, 0 );
detach_thread( thread, violent_death ? SIGTERM : 0 );
remove_select_user( &thread->obj );
+ release_object( thread->request_fd );
+ close( thread->reply_fd );
munmap( thread->buffer, MAX_REQUEST_LENGTH );
+ thread->request_fd = NULL;
+ thread->reply_fd = -1;
thread->buffer = (void *)-1;
release_object( thread );
}
@@ -675,7 +690,7 @@
if ((req->handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, req->inherit )) != -1)
{
- set_reply_fd( current, sock[1] );
+ send_client_fd( current, sock[1], req->handle );
/* thread object will be released when the thread gets killed */
add_process_thread( current->process, thread );
return;
diff --git a/server/thread.h b/server/thread.h
index c0db481..8e36569 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -48,7 +48,9 @@
struct thread_apc *apc_head; /* queue of async procedure calls */
struct thread_apc *apc_tail; /* queue of async procedure calls */
unsigned int error; /* current error code */
- int pass_fd; /* fd to pass to the client */
+ struct object *request_fd; /* fd for receiving client requests */
+ int pass_fd; /* fd to pass to the client */
+ int reply_fd; /* fd to use to wake a client waiting on a reply */
enum run_state state; /* running state */
int attached; /* is thread attached with ptrace? */
int exit_code; /* thread exit code */
diff --git a/server/trace.c b/server/trace.c
index bad07e8..534f4d43 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -471,21 +471,23 @@
fprintf( stderr, " handle=%d", req->handle );
}
-static void dump_get_handle_info_request( const struct get_handle_info_request *req )
+static void dump_close_handle_reply( const struct close_handle_request *req )
{
- fprintf( stderr, " handle=%d", req->handle );
-}
-
-static void dump_get_handle_info_reply( const struct get_handle_info_request *req )
-{
- fprintf( stderr, " flags=%d", req->flags );
+ fprintf( stderr, " fd=%d", req->fd );
}
static void dump_set_handle_info_request( const struct set_handle_info_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " flags=%d,", req->flags );
- fprintf( stderr, " mask=%d", req->mask );
+ fprintf( stderr, " mask=%d,", req->mask );
+ fprintf( stderr, " fd=%d", req->fd );
+}
+
+static void dump_set_handle_info_reply( const struct set_handle_info_request *req )
+{
+ fprintf( stderr, " old_flags=%d,", req->old_flags );
+ fprintf( stderr, " cur_fd=%d", req->cur_fd );
}
static void dump_dup_handle_request( const struct dup_handle_request *req )
@@ -500,7 +502,8 @@
static void dump_dup_handle_reply( const struct dup_handle_request *req )
{
- fprintf( stderr, " handle=%d", req->handle );
+ fprintf( stderr, " handle=%d,", req->handle );
+ fprintf( stderr, " fd=%d", req->fd );
}
static void dump_open_process_request( const struct open_process_request *req )
@@ -957,7 +960,8 @@
fprintf( stderr, " header_size=%d,", req->header_size );
fprintf( stderr, " base=%p,", req->base );
fprintf( stderr, " shared_file=%d,", req->shared_file );
- fprintf( stderr, " shared_size=%d", req->shared_size );
+ fprintf( stderr, " shared_size=%d,", req->shared_size );
+ fprintf( stderr, " anonymous=%d", req->anonymous );
}
static void dump_create_device_request( const struct create_device_request *req )
@@ -1471,7 +1475,6 @@
(dump_func)dump_queue_apc_request,
(dump_func)dump_get_apc_request,
(dump_func)dump_close_handle_request,
- (dump_func)dump_get_handle_info_request,
(dump_func)dump_set_handle_info_request,
(dump_func)dump_dup_handle_request,
(dump_func)dump_open_process_request,
@@ -1582,9 +1585,8 @@
(dump_func)0,
(dump_func)0,
(dump_func)dump_get_apc_reply,
- (dump_func)0,
- (dump_func)dump_get_handle_info_reply,
- (dump_func)0,
+ (dump_func)dump_close_handle_reply,
+ (dump_func)dump_set_handle_info_reply,
(dump_func)dump_dup_handle_reply,
(dump_func)dump_open_process_reply,
(dump_func)dump_select_reply,
@@ -1695,7 +1697,6 @@
"queue_apc",
"get_apc",
"close_handle",
- "get_handle_info",
"set_handle_info",
"dup_handle",
"open_process",