Commit d549f690 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent 44b65a50
......@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "debugtools.h"
#include "ntddk.h"
......@@ -221,6 +222,7 @@ NTSTATUS WINAPI NtClose( HANDLE Handle )
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;
......
......@@ -185,7 +185,7 @@ HFILE FILE_DupUnixHandle( int fd, DWORD access )
{
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 @@ HFILE FILE_DupUnixHandle( int fd, DWORD access )
*/
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;
}
......
......@@ -359,15 +359,7 @@ struct close_handle_request
{
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 @@ struct set_handle_info_request
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 @@ struct dup_handle_request
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 @@ struct get_mapping_info_request
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 @@ enum request
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 @@ union generic_request
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 @@ union generic_request
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 @@ struct server_buffer_info
/* 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 */
......
......@@ -94,13 +94,15 @@ typedef struct _TEB
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 */
......
......@@ -1019,7 +1019,7 @@ HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
LPSTR cmdline;
WORD cmdShow;
HANDLE hThread = -1;
int socket;
int socket = -1;
/* Load module */
......@@ -1066,7 +1066,11 @@ HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
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;
......
......@@ -1478,8 +1478,10 @@ LPVOID WINAPI MapViewOfFileEx(
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 @@ LPVOID WINAPI MapViewOfFileEx(
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)
{
......
......@@ -157,7 +157,7 @@ static void send_request( enum request req, struct request_header *header )
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 @@ static void wait_reply(void)
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,22 +232,90 @@ static void wait_reply(void)
/***********************************************************************
* wait_reply_fd
* wine_server_call
*
* Perform a server call.
*/
unsigned int wine_server_call( enum request req )
{
void *req_ptr = get_req_buffer();
send_request( req, req_ptr );
wait_reply();
return ((struct request_header *)req_ptr)->error;
}
/***********************************************************************
* server_call_fd
*
* Wait for a reply from the server, when a file descriptor is passed.
* Perform a server call, passing a file descriptor.
*/
static void wait_reply_fd( int *fd )
unsigned int server_call_fd( enum request req, int fd_out )
{
unsigned int res;
void *req_ptr = get_req_buffer();
send_request_fd( req, req_ptr, fd_out );
wait_reply();
if ((res = ((struct request_header *)req_ptr)->error))
SetLastError( RtlNtStatusToDosError(res) );
return res; /* error code */
}
/***********************************************************************
* 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;
char dummy[1];
int ret, fd, server_handle;
#ifdef HAVE_MSGHDR_ACCRIGHTS
struct msghdr msghdr;
*fd = -1;
msghdr.msg_accrights = (void *)fd;
msghdr.msg_accrightslen = sizeof(*fd);
fd = -1;
msghdr.msg_accrights = (void *)&fd;
msghdr.msg_accrightslen = sizeof(fd);
#else /* HAVE_MSGHDR_ACCRIGHTS */
struct msghdr msghdr;
struct cmsg_fd cmsg;
......@@ -265,17 +333,25 @@ static void wait_reply_fd( int *fd )
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
vec.iov_base = (void *)dummy;
vec.iov_len = 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;
fd = cmsg.fd;
#endif
return;
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;
......@@ -288,44 +364,6 @@ static void wait_reply_fd( int *fd )
/***********************************************************************
* wine_server_call
*
* Perform a server call.
*/
unsigned int wine_server_call( enum request req )
{
void *req_ptr = get_req_buffer();
send_request( req, req_ptr );
wait_reply();
return ((struct request_header *)req_ptr)->error;
}
/***********************************************************************
* 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 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();
if ((res = ((struct request_header *)req_ptr)->error))
SetLastError( RtlNtStatusToDosError(res) );
return res; /* error code */
}
/***********************************************************************
* get_config_dir
*
* Return the configuration directory ($WINEPREFIX or $HOME/.wine)
......@@ -564,8 +602,16 @@ int CLIENT_InitThread(void)
/* 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 @@ int CLIENT_InitThread(void)
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 @@ int CLIENT_InitThread(void)
return ret;
}
/***********************************************************************
* CLIENT_BootDone
*
......
......@@ -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 WINAPI GetHandleInformation( HANDLE handle, LPDWORD flags )
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 @@ BOOL WINAPI SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags )
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 @@ BOOL WINAPI DuplicateHandle( HANDLE source_process, HANDLE source,
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;
......
......@@ -91,7 +91,9 @@ static BOOL THREAD_InitTEB( TEB *teb )
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 @@ static void CALLBACK THREAD_FreeTEB( TEB *teb )
/* 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 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
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 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
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;
......
......@@ -419,7 +419,7 @@ DECL_HANDLER(alloc_console)
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 );
......
......@@ -118,7 +118,7 @@ static int fill_create_process_event( struct debug_event *event, void *arg )
/* 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 @@ static int fill_create_process_event( struct debug_event *event, void *arg )
/* 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 @@ static void debug_event_destroy( struct object *obj )
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;
}
}
......
......@@ -325,11 +325,6 @@ struct file *get_file_obj( struct process *process, int handle, unsigned int acc
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 @@ DECL_HANDLER(get_handle_fd)
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 );
}
}
......
......@@ -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 @@ static int alloc_entry( struct handle_table *table, void *obj, unsigned int acce
table->free = i + 1;
entry->ptr = grab_object( obj );
entry->access = access;
entry->fd = -1;
return index_to_handle(i);
}
......@@ -269,6 +271,7 @@ struct object *copy_handle_table( struct process *process, struct process *paren
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 @@ struct object *copy_handle_table( struct process *process, struct process *paren
/* 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 @@ int close_handle( struct process *process, int handle )
}
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,11 +357,27 @@ struct object *get_handle_obj( struct process *process, int handle,
return grab_object( obj );
}
/* 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 new flags (or -1 on error) */
static int set_handle_info( struct process *process, int handle, int mask, int 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 ))
{
......@@ -364,10 +386,14 @@ static int set_handle_info( struct process *process, int handle, int mask, int f
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 @@ int open_object( const WCHAR *name, size_t len, const struct object_ops *ops,
/* 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 @@ DECL_HANDLER(dup_handle)
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 @@ DECL_HANDLER(dup_handle)
}
/* 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 );
}
}
......@@ -23,9 +23,10 @@ struct object_ops;
/* 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,
......
......@@ -30,6 +30,7 @@ struct mapping
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 @@ static const struct object_ops mapping_ops =
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 @@ static void init_page_size(void)
#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 @@ static int build_shared_mapping( struct mapping *mapping, int fd,
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 @@ static int get_image_params( struct mapping *mapping )
/* 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 @@ static void mapping_dump( struct object *obj, int verbose )
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 @@ DECL_HANDLER(get_mapping_info)
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 );
}
}
......@@ -148,7 +148,6 @@ extern void abandon_mutexes( struct thread *thread );
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 );
......
......@@ -165,7 +165,7 @@ DECL_HANDLER(create_pipe)
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] );
......
......@@ -71,6 +71,32 @@ static const struct object_ops master_socket_ops =
};
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 @@ static inline void call_req_handler( struct thread *thread )
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,35 +232,49 @@ int write_request( struct thread *thread )
header->error = thread->error;
if (thread->pass_fd == -1)
assert (thread->pass_fd == -1);
ret = write( thread->reply_fd, header, 1 );
if (ret > 0)
{
/* write a single byte; the value is ignored anyway */
ret = write( thread->obj.fd, header, 1 );
set_select_events( &thread->obj, POLLIN );
return 1;
}
else /* we have an fd to send */
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
if (errno == EPIPE)
{
kill_thread( thread, 0 ); /* normal death */
}
else
{
perror("sendmsg");
thread->exit_code = 1;
kill_thread( thread, 1 );
}
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(int);
msghdr.msg_accrights = (void *)&thread->pass_fd;
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 = thread->pass_fd;
msghdr.msg_control = &cmsg;
msghdr.msg_controllen = sizeof(cmsg);
cmsg.fd = fd;
#endif /* HAVE_MSGHDR_ACCRIGHTS */
myiovec.iov_base = (void *)header;
myiovec.iov_len = 1;
myiovec.iov_base = (void *)&handle;
myiovec.iov_len = sizeof(handle);
ret = sendmsg( thread->obj.fd, &msghdr, 0 );
close( thread->pass_fd );
thread->pass_fd = -1;
}
if (ret > 0)
{
set_select_events( &thread->obj, POLLIN );
return 1;
}
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
ret = sendmsg( thread->obj.fd, &msghdr, 0 );
close( fd );
if (ret > 0) return 0;
if (errno == EPIPE)
{
kill_thread( thread, 0 ); /* normal death */
......@@ -297,6 +330,61 @@ static void master_socket_destroy( struct object *obj )
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)
{
......
......@@ -33,11 +33,12 @@ extern void fatal_perror( const char *err, ... ) WINE_NORETURN;
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(unload_dll);
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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(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,
......
......@@ -89,26 +89,33 @@ static struct thread *booting_thread;
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 @@ struct thread *create_thread( int fd, struct process *process )
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 @@ static void destroy_thread( struct object *obj )
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 @@ void kill_thread( struct thread *thread, int violent_death )
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 @@ DECL_HANDLER(new_thread)
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;
......
......@@ -48,7 +48,9 @@ struct thread
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 */
......
......@@ -471,21 +471,23 @@ static void dump_close_handle_request( const struct close_handle_request *req )
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_request( const struct dup_handle_request *req )
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 @@ static void dump_get_mapping_info_reply( const struct get_mapping_info_request *
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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(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 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"queue_apc",
"get_apc",
"close_handle",
"get_handle_info",
"set_handle_info",
"dup_handle",
"open_process",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment