diff --git a/files/file.c b/files/file.c index bcb62c781a4bce5eb59b3fc9cc8c1c220bf48815..c9dd1069d1d3a8024e4097cfebb31c096cc94e42 100644 --- a/files/file.c +++ b/files/file.c @@ -208,17 +208,27 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access ) int FILE_GetUnixHandle( HANDLE handle, DWORD access ) { int ret, fd = -1; - SERVER_START_REQ( get_handle_fd ) + + do { - req->handle = handle; - req->access = access; - if (!(ret = SERVER_CALL_ERR())) fd = req->fd; - } - SERVER_END_REQ; - if (!ret) + SERVER_START_REQ( get_handle_fd ) + { + req->handle = handle; + req->access = access; + if (!(ret = SERVER_CALL_ERR())) fd = req->fd; + } + SERVER_END_REQ; + if (ret) return -1; + + if (fd == -1) /* it wasn't in the cache, get it from the server */ + fd = wine_server_recv_fd( handle ); + + } while (fd == -2); /* -2 means race condition, so restart from scratch */ + + if (fd != -1) { - if (fd == -1) return wine_server_recv_fd( handle, 1 ); - fd = dup(fd); + if ((fd = dup(fd)) == -1) + SetLastError( ERROR_TOO_MANY_OPEN_FILES ); } return fd; } diff --git a/include/server.h b/include/server.h index a697d97487855ddf92fca85787777e360bb1d533..6c15ba49b2276addca86cd8f51f20bfcd9cb1214 100644 --- a/include/server.h +++ b/include/server.h @@ -163,6 +163,7 @@ struct new_thread_request REQUEST_HEADER; /* request header */ IN int suspend; /* new thread should be suspended on creation */ IN int inherit; /* inherit flag */ + IN int request_fd; /* fd for request pipe */ OUT void* tid; /* thread id */ OUT handle_t handle; /* thread handle (in the current process) */ }; @@ -214,15 +215,8 @@ struct init_thread_request IN int unix_pid; /* Unix pid of new thread */ IN void* teb; /* TEB of new thread (in thread address space) */ IN void* entry; /* thread entry point (in thread address space) */ -}; - - -/* Retrieve the thread buffer file descriptor */ -/* The reply to this request is the first thing a newly */ -/* created thread gets (without having to request it) */ -struct get_thread_buffer_request -{ - REQUEST_HEADER; /* request header */ + IN int reply_fd; /* fd for reply pipe */ + IN int wait_fd; /* fd for blocking calls pipe */ OUT void* pid; /* process id of the new thread's process */ OUT void* tid; /* thread id of the new thread */ OUT int boot; /* is this the boot thread? */ @@ -230,6 +224,16 @@ struct get_thread_buffer_request }; +/* Set the shared buffer for a thread */ +struct set_thread_buffer_request +{ + REQUEST_HEADER; + IN int fd; /* fd to mmap as shared buffer */ + OUT unsigned int offset; /* offset of buffer in file */ + OUT unsigned int size; /* size of buffer */ +}; + + /* Terminate a process */ struct terminate_process_request { @@ -1379,7 +1383,7 @@ enum request REQ_init_process, REQ_init_process_done, REQ_init_thread, - REQ_get_thread_buffer, + REQ_set_thread_buffer, REQ_terminate_process, REQ_terminate_thread, REQ_get_process_info, @@ -1495,7 +1499,7 @@ union generic_request struct init_process_request init_process; struct init_process_done_request init_process_done; struct init_thread_request init_thread; - struct get_thread_buffer_request get_thread_buffer; + struct set_thread_buffer_request set_thread_buffer; struct terminate_process_request terminate_process; struct terminate_thread_request terminate_thread; struct get_process_info_request get_process_info; @@ -1599,7 +1603,7 @@ union generic_request struct async_result_request async_result; }; -#define SERVER_PROTOCOL_VERSION 40 +#define SERVER_PROTOCOL_VERSION 41 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ @@ -1622,7 +1626,7 @@ extern void server_protocol_error( const char *err, ... ) WINE_NORETURN; extern void server_protocol_perror( const char *err ) WINE_NORETURN; extern void wine_server_alloc_req( union generic_request *req, size_t size ); extern void wine_server_send_fd( int fd ); -extern int wine_server_recv_fd( int handle, int cache ); +extern int wine_server_recv_fd( handle_t handle ); extern const char *get_config_dir(void); /* do a server call and set the last error code */ @@ -1694,10 +1698,10 @@ struct __server_exception_frame #define SERVER_CALL_ERR() (__server_call_err( &__req, sizeof(*req) )) -extern int CLIENT_InitServer(void); -extern int CLIENT_BootDone( int debug_level ); +extern void CLIENT_InitServer(void); +extern void CLIENT_InitThread(void); +extern void CLIENT_BootDone( int debug_level ); extern int CLIENT_IsBootThread(void); -extern int CLIENT_InitThread(void); #endif /* __WINE_SERVER__ */ #endif /* __WINE_SERVER_H */ diff --git a/include/thread.h b/include/thread.h index 7d84170ee02eb0c246e9345b16b126bfe56ca607..85f5e1703181e5994935e0322216e6e0686999a0 100644 --- a/include/thread.h +++ b/include/thread.h @@ -92,19 +92,18 @@ typedef struct _TEB /* The following are Wine-specific fields (NT: GDI stuff) */ DWORD cleanup; /* --3 1fc Cleanup service handle */ - int socket; /* --3 200 Socket for server communication */ - void *buffer; /* --3 204 Buffer shared with server */ - unsigned int buffer_pos; /* --3 208 Buffer current position */ - unsigned int buffer_size; /* --3 20c Buffer size */ - int request_fd; /* --3 210 fd for sending server requests */ - int reply_fd; /* --3 214 fd for receiving server replies */ - int wait_fd; /* --3 218 fd for sleeping server requests */ - void *debug_info; /* --3 21c Info for debugstr functions */ - void *pthread_data; /* --3 220 Data for pthread emulation */ + void *buffer; /* --3 200 Buffer shared with server */ + unsigned int buffer_pos; /* --3 204 Buffer current position */ + unsigned int buffer_size; /* --3 208 Buffer size */ + int request_fd; /* --3 20c fd for sending server requests */ + int reply_fd; /* --3 210 fd for receiving server replies */ + int wait_fd; /* --3 214 fd for sleeping server requests */ + void *debug_info; /* --3 218 Info for debugstr functions */ + void *pthread_data; /* --3 21c 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[629]; /* --n 224 */ + DWORD pad6[630]; /* --n 220 */ UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */ USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */ DWORD pad7; /* --n e0c */ diff --git a/scheduler/client.c b/scheduler/client.c index 1a6bc606db1a13eaac93c97378a02abec3841344..6ef25d876d5bb7f822df1a3d2b1d508c1147c62b 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -93,7 +93,7 @@ void server_protocol_error( const char *err, ... ) va_list args; va_start( args, err ); - fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid ); + fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid ); vfprintf( stderr, err, args ); va_end( args ); SYSDEPS_ExitThread(1); @@ -105,7 +105,7 @@ void server_protocol_error( const char *err, ... ) */ void server_protocol_perror( const char *err ) { - fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid ); + fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid ); perror( err ); SYSDEPS_ExitThread(1); } @@ -252,49 +252,14 @@ void wine_server_send_fd( int fd ) /*********************************************************************** - * 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( set_handle_info ) - { - req->handle = handle; - req->flags = 0; - req->mask = 0; - req->fd = fd; - if (!SERVER_CALL()) - { - 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_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 ) +static int receive_fd( handle_t *handle ) { struct iovec vec; - int ret, fd, server_handle; + int ret, fd; #ifdef HAVE_MSGHDR_ACCRIGHTS struct msghdr msghdr; @@ -319,24 +284,18 @@ int wine_server_recv_fd( int handle, int cache ) msghdr.msg_namelen = 0; msghdr.msg_iov = &vec; msghdr.msg_iovlen = 1; - vec.iov_base = (void *)&server_handle; - vec.iov_len = sizeof(server_handle); + vec.iov_base = (void *)handle; + vec.iov_len = sizeof(*handle); for (;;) { - if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) > 0) + if ((ret = recvmsg( fd_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); - } + if (fd == -1) server_protocol_error( "no fd received for handle %d\n", *handle ); + fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ return fd; } if (!ret) break; @@ -349,6 +308,50 @@ int wine_server_recv_fd( int handle, int cache ) } +/*********************************************************************** + * wine_server_recv_fd + * + * Receive a file descriptor passed from the server. + * The file descriptor must be closed after use. + * Return -2 if a race condition stole our file descriptor. + */ +int wine_server_recv_fd( handle_t handle ) +{ + handle_t fd_handle; + + int fd = receive_fd( &fd_handle ); + + /* now store it in the server fd cache for this handle */ + + SERVER_START_REQ( set_handle_info ) + { + req->handle = fd_handle; + req->flags = 0; + req->mask = 0; + req->fd = fd; + if (!SERVER_CALL()) + { + if (req->cur_fd != fd) + { + /* someone was here before us */ + close( fd ); + fd = req->cur_fd; + } + } + else + { + close( fd ); + fd = -1; + } + } + SERVER_END_REQ; + + if (handle != fd_handle) return -2; /* not the one we expected */ + if (fd != -1) fd = dup(fd); + return fd; +} + + /*********************************************************************** * get_config_dir * @@ -520,12 +523,13 @@ static int server_connect( const char *oldcwd, const char *serverdir ) * * Start the server and create the initial socket pair. */ -int CLIENT_InitServer(void) +void CLIENT_InitServer(void) { - int fd, size; + int size; char hostname[64]; char *oldcwd, *serverdir; const char *configdir; + handle_t dummy_handle; /* retrieve the current directory */ for (size = 512; ; size *= 2) @@ -562,8 +566,7 @@ int CLIENT_InitServer(void) strcat( serverdir, hostname ); /* connect to the server */ - fd = server_connect( oldcwd, serverdir ); - fd_socket = dup(fd); + fd_socket = server_connect( oldcwd, serverdir ); /* switch back to the starting directory */ if (oldcwd) @@ -579,69 +582,107 @@ int CLIENT_InitServer(void) sigaddset( &block_set, SIGINT ); sigaddset( &block_set, SIGHUP ); - return fd; + /* receive the first thread request fd on the main socket */ + NtCurrentTeb()->request_fd = receive_fd( &dummy_handle ); + + CLIENT_InitThread(); } /*********************************************************************** - * CLIENT_InitThread - * - * Send an init thread request. Return 0 if OK. + * set_request_buffer */ -int CLIENT_InitThread(void) +inline static void set_request_buffer(void) { - struct get_thread_buffer_request *req; - TEB *teb = NtCurrentTeb(); + char *name; int fd, ret; + unsigned int offset, size; - /* ignore SIGPIPE so that we get a EPIPE error instead */ - signal( SIGPIPE, SIG_IGN ); + /* create a temporary file */ + do + { + if (!(name = tmpnam(NULL))) server_protocol_perror( "tmpnam" ); + fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 ); + } while ((fd == -1) && (errno == EEXIST)); - teb->request_fd = wine_server_recv_fd( 0, 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 */ + if (fd == -1) server_protocol_perror( "create" ); + unlink( name ); - teb->reply_fd = wine_server_recv_fd( 0, 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 */ + wine_server_send_fd( fd ); - teb->wait_fd = wine_server_recv_fd( 0, 0 ); - if (teb->wait_fd == -1) server_protocol_error( "no wait fd passed on first request\n" ); - fcntl( teb->wait_fd, F_SETFD, 1 ); /* set close on exec flag */ + SERVER_START_REQ( set_thread_buffer ) + { + req->fd = fd; + ret = SERVER_CALL(); + offset = req->offset; + size = req->size; + } + SERVER_END_REQ; + if (ret) server_protocol_error( "set_thread_buffer failed with status %x\n", ret ); - fd = wine_server_recv_fd( 0, 0 ); - if (fd == -1) server_protocol_error( "no fd received for thread buffer\n" ); + if ((NtCurrentTeb()->buffer = mmap( 0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, offset )) == (void*)-1) + server_protocol_perror( "mmap" ); - if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) server_protocol_perror( "lseek" ); - teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); - teb->buffer_pos = 0; close( fd ); - if (teb->buffer == (void*)-1) server_protocol_perror( "mmap" ); + NtCurrentTeb()->buffer_pos = 0; + NtCurrentTeb()->buffer_size = size; +} - req = (struct get_thread_buffer_request *)teb->buffer; - wait_reply( (union generic_request *)req ); - teb->pid = req->pid; - teb->tid = req->tid; - if (req->version != SERVER_PROTOCOL_VERSION) - server_protocol_error( "version mismatch %d/%d.\n" - "Your %s binary was not upgraded correctly,\n" - "or you have an older one somewhere in your PATH.\n" - "Or maybe the wrong wineserver is still running?\n", - req->version, SERVER_PROTOCOL_VERSION, - (req->version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); - if (req->boot) boot_thread_id = teb->tid; - else if (boot_thread_id == teb->tid) boot_thread_id = 0; +/*********************************************************************** + * CLIENT_InitThread + * + * Send an init thread request. Return 0 if OK. + */ +void CLIENT_InitThread(void) +{ + TEB *teb = NtCurrentTeb(); + int version, ret; + int reply_pipe[2], wait_pipe[2]; + + /* ignore SIGPIPE so that we get a EPIPE error instead */ + signal( SIGPIPE, SIG_IGN ); + + /* create the server->client communication pipes */ + if (pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" ); + if (pipe( wait_pipe ) == -1) server_protocol_perror( "pipe" ); + wine_server_send_fd( reply_pipe[1] ); + wine_server_send_fd( wait_pipe[1] ); + teb->reply_fd = reply_pipe[0]; + teb->wait_fd = wait_pipe[0]; + + /* set close on exec flag */ + fcntl( teb->reply_fd, F_SETFD, 1 ); + fcntl( teb->wait_fd, F_SETFD, 1 ); SERVER_START_REQ( init_thread ) { - req->unix_pid = getpid(); - req->teb = teb; - req->entry = teb->entry_point; + req->unix_pid = getpid(); + req->teb = teb; + req->entry = teb->entry_point; + req->reply_fd = reply_pipe[1]; + req->wait_fd = wait_pipe[1]; ret = SERVER_CALL(); + teb->pid = req->pid; + teb->tid = req->tid; + version = req->version; + if (req->boot) boot_thread_id = teb->tid; + else if (boot_thread_id == teb->tid) boot_thread_id = 0; + close( reply_pipe[1] ); + close( wait_pipe[1] ); } SERVER_END_REQ; - return ret; + + if (ret) server_protocol_error( "init_thread failed with status %x\n", ret ); + if (version != SERVER_PROTOCOL_VERSION) + server_protocol_error( "version mismatch %d/%d.\n" + "Your %s binary was not upgraded correctly,\n" + "or you have an older one somewhere in your PATH.\n" + "Or maybe the wrong wineserver is still running?\n", + version, SERVER_PROTOCOL_VERSION, + (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); + set_request_buffer(); } @@ -650,16 +691,14 @@ int CLIENT_InitThread(void) * * Signal that we have finished booting, and set debug level. */ -int CLIENT_BootDone( int debug_level ) +void CLIENT_BootDone( int debug_level ) { - int ret; SERVER_START_REQ( boot_done ) { req->debug_level = debug_level; - ret = SERVER_CALL(); + SERVER_CALL(); } SERVER_END_REQ; - return ret; } diff --git a/scheduler/process.c b/scheduler/process.c index 482cedb0d6da0e724a8749da8ca6b936fb07ced5..ac85e655b593806d2e829c05c101be968412a470 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -269,8 +269,7 @@ static BOOL process_init( char *argv[] ) current_process.priority = 8; /* Normal */ /* Setup the server connection */ - NtCurrentTeb()->socket = CLIENT_InitServer(); - if (CLIENT_InitThread()) return FALSE; + CLIENT_InitServer(); /* Retrieve startup info from the server */ SERVER_START_VAR_REQ( init_process, sizeof(main_exe_name)-1 ) diff --git a/scheduler/sysdeps.c b/scheduler/sysdeps.c index 1a1a1042c6c5af518f56439a6d197fc2547f255d..86ac9b953364c8dc9c2538a44bfff3fbc710ac03 100644 --- a/scheduler/sysdeps.c +++ b/scheduler/sysdeps.c @@ -95,7 +95,7 @@ int SYSDEPS_SpawnThread( TEB *teb ) const int flags = CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD; if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top, flags, teb ) < 0) return -1; - if (!(flags & CLONE_FILES)) close( teb->socket ); /* close the child socket in the parent */ + if (!(flags & CLONE_FILES)) close( teb->request_fd ); /* close the child socket in the parent */ return 0; #endif @@ -118,7 +118,7 @@ int SYSDEPS_SpawnThread( TEB *teb ) "addl $8,%%esp" : : "r" (sp), "g" (SYS_rfork), "g" (flags) : "eax", "edx"); - if (flags & RFFDG) close( teb->socket ); /* close the child socket in the parent */ + if (flags & RFFDG) close( teb->request_fd ); /* close the child socket in the parent */ return 0; #endif @@ -146,9 +146,9 @@ int SYSDEPS_SpawnThread( TEB *teb ) */ void SYSDEPS_ExitThread( int status ) { - int socket = NtCurrentTeb()->socket; - NtCurrentTeb()->socket = -1; - close( socket ); + int fd = NtCurrentTeb()->request_fd; + NtCurrentTeb()->request_fd = -1; + close( fd ); #ifdef HAVE__LWP_CREATE _lwp_exit(); #endif diff --git a/scheduler/thread.c b/scheduler/thread.c index 77daaacf8ed67c9cb8777ad7ccedcf9a3041b640..738d4c8f378a7a482eb6e4a27b7606b79e7b9cfa 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -89,7 +89,6 @@ static BOOL THREAD_InitTEB( TEB *teb ) teb->tibflags = TEBF_WIN32; teb->tls_ptr = teb->tls_array; teb->exit_code = STILL_ACTIVE; - teb->socket = -1; teb->request_fd = -1; teb->reply_fd = -1; teb->wait_fd = -1; @@ -114,7 +113,6 @@ static void CALLBACK THREAD_FreeTEB( TEB *teb ) /* Free the associated memory */ - if (teb->socket != -1) close( teb->socket ); close( teb->request_fd ); close( teb->reply_fd ); close( teb->wait_fd ); @@ -285,38 +283,46 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack, LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, LPDWORD id ) { - int socket = -1; HANDLE handle = 0; TEB *teb; void *tid = 0; + int request_pipe[2]; + + if (pipe( request_pipe ) == -1) + { + SetLastError( ERROR_TOO_MANY_OPEN_FILES ); + return 0; + } + fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */ + wine_server_send_fd( request_pipe[0] ); SERVER_START_REQ( new_thread ) { - req->suspend = ((flags & CREATE_SUSPENDED) != 0); - req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); + req->suspend = ((flags & CREATE_SUSPENDED) != 0); + req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); + req->request_fd = request_pipe[0]; if (!SERVER_CALL_ERR()) { handle = req->handle; tid = req->tid; - socket = wine_server_recv_fd( handle, 0 ); } + close( request_pipe[0] ); } SERVER_END_REQ; - if (!handle) return 0; - if (!(teb = THREAD_InitStack( NULL, stack ))) + if (!handle || !(teb = THREAD_InitStack( NULL, stack ))) { - close( socket ); + close( request_pipe[1] ); return 0; } teb->process = NtCurrentTeb()->process; - teb->socket = socket; + teb->tid = tid; + teb->request_fd = request_pipe[1]; teb->entry_point = start; teb->entry_arg = param; teb->startup = THREAD_Start; teb->htask16 = GetCurrentTask(); - fcntl( socket, F_SETFD, 1 ); /* set close on exec flag */ if (id) *id = (DWORD)tid; if (SYSDEPS_SpawnThread( teb ) == -1) diff --git a/server/file.c b/server/file.c index 0ce961aa7205bebc3cd7360ec192f5ed22ff63cf..75b1dd89eabd89a8f05ad1810974ec2e00471096 100644 --- a/server/file.c +++ b/server/file.c @@ -487,7 +487,7 @@ DECL_HANDLER(get_handle_fd) else if (!get_error()) { if ((fd = obj->ops->get_fd( obj )) != -1) - send_client_fd( current, fd, req->handle ); + send_client_fd( current->process, fd, req->handle ); } release_object( obj ); } diff --git a/server/process.c b/server/process.c index 9f4bdc4a6ec6d5bfd41423e1b06b9e0d02afe2d6..39f40e6f301e76a81822817852709ea9072dd6fd 100644 --- a/server/process.c +++ b/server/process.c @@ -147,6 +147,7 @@ struct thread *create_process( int fd ) { struct process *process; struct thread *thread = NULL; + int request_pipe[2]; if (!(process = alloc_object( &process_ops, fd ))) return NULL; process->next = NULL; @@ -180,7 +181,14 @@ struct thread *create_process( int fd ) if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error; /* create the main thread */ - if (!(thread = create_thread( dup(fd), process ))) goto error; + if (pipe( request_pipe ) == -1) + { + file_set_error(); + goto error; + } + send_client_fd( process, request_pipe[1], 0 ); + close( request_pipe[1] ); + if (!(thread = create_thread( request_pipe[0], process ))) goto error; set_select_events( &process->obj, POLLIN ); /* start listening to events */ release_object( process ); diff --git a/server/request.c b/server/request.c index 96bb71114714bd20228d83672290ea9fd159e4cc..4072fd1e052e41df9b49d20a4b3ec1d0b9c9c388 100644 --- a/server/request.c +++ b/server/request.c @@ -71,32 +71,6 @@ 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 */ @@ -199,6 +173,25 @@ static inline void call_req_handler( struct thread *thread, union generic_reques fatal_protocol_error( current, "bad request %d\n", req ); } +/* read a request from a thread */ +void read_request( struct thread *thread ) +{ + union generic_request req; + int ret; + + if ((ret = read( thread->obj.fd, &req, sizeof(req) )) == sizeof(req)) + { + call_req_handler( thread, &req ); + return; + } + if (!ret) /* closed pipe */ + kill_thread( thread, 0 ); + else if (ret > 0) + fatal_protocol_error( thread, "partial read %d\n", ret ); + else + fatal_protocol_perror( thread, "read" ); +} + /* send a reply to a thread */ void send_reply( struct thread *thread, union generic_request *request ) { @@ -215,7 +208,7 @@ void send_reply( struct thread *thread, union generic_request *request ) else if (errno == EPIPE) kill_thread( thread, 0 ); /* normal death */ else - fatal_protocol_perror( thread, "sendmsg" ); + fatal_protocol_perror( thread, "reply write" ); } } @@ -244,7 +237,11 @@ int receive_fd( struct process *process ) if (ret == sizeof(data)) { - struct thread *thread = get_thread_from_id( data.tid ); + struct thread *thread; + + if (data.tid) thread = get_thread_from_id( data.tid ); + else thread = (struct thread *)grab_object( process->thread_list ); + if (!thread || thread->process != process) { if (debug_level) @@ -259,19 +256,16 @@ int receive_fd( struct process *process ) (unsigned int)thread, data.fd, fd ); thread_add_inflight_fd( thread, data.fd, fd ); } + if (thread) release_object( thread ); return 0; } - if (!ret) - { - set_select_events( &process->obj, -1 ); /* stop waiting on it */ - } - else if (ret > 0) + if (ret >= 0) { fprintf( stderr, "Protocol error: process %p: partial recvmsg %d for fd\n", process, ret ); kill_process( process, NULL, 1 ); } - else if (ret < 0) + else { if (errno != EWOULDBLOCK && errno != EAGAIN) { @@ -298,12 +292,12 @@ int send_thread_wakeup( struct thread *thread, int signaled ) } /* send an fd to a client */ -int send_client_fd( struct thread *thread, int fd, handle_t handle ) +int send_client_fd( struct process *process, int fd, handle_t handle ) { int ret; if (debug_level) - fprintf( stderr, "%08x: *fd* %d -> %d\n", (unsigned int)thread, handle, fd ); + fprintf( stderr, "%08x: *fd* %d -> %d\n", (unsigned int)current, handle, fd ); #ifdef HAVE_MSGHDR_ACCRIGHTS msghdr.msg_accrightslen = sizeof(fd); @@ -317,16 +311,20 @@ int send_client_fd( struct thread *thread, int fd, handle_t handle ) myiovec.iov_base = (void *)&handle; myiovec.iov_len = sizeof(handle); - ret = sendmsg( thread->obj.fd, &msghdr, 0 ); + ret = sendmsg( process->obj.fd, &msghdr, 0 ); - if (ret > 0) return 0; - if (errno == EPIPE) + if (ret == sizeof(handle)) return 0; + + if (ret >= 0) { - kill_thread( thread, 0 ); /* normal death */ + fprintf( stderr, "Protocol error: process %p: partial sendmsg %d\n", process, ret ); + kill_process( process, NULL, 1 ); } else { - fatal_protocol_perror( thread, "sendmsg" ); + fprintf( stderr, "Protocol error: process %p: ", process ); + perror( "sendmsg" ); + kill_process( process, NULL, 1 ); } return -1; } @@ -373,60 +371,6 @@ 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; - union generic_request req; - int ret; - - if ((ret = read( sock->obj.fd, &req, sizeof(req) )) == sizeof(req)) - { - call_req_handler( thread, &req ); - return; - } - if (!ret) /* closed pipe */ - kill_thread( thread, 0 ); - else if (ret > 0) - fatal_protocol_error( thread, "partial read %d\n", ret ); - else - fatal_protocol_perror( thread, "read" ); - } -} - -/* 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], 0 ); - close( fd[1] ); - fcntl( fd[0], F_SETFL, O_NONBLOCK ); - 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 b4275594130779c4ab5ace9942614a48e7b1f76d..1c7b4fbd02b4183328f9369a3c4ecb78c57293d9 100644 --- a/server/request.h +++ b/server/request.h @@ -33,12 +33,12 @@ extern void fatal_perror( const char *err, ... ) WINE_NORETURN; extern const char *get_config_dir(void); extern int receive_fd( struct process *process ); extern int send_thread_wakeup( struct thread *thread, int signaled ); -extern int send_client_fd( struct thread *thread, int fd, handle_t handle ); +extern int send_client_fd( struct process *process, int fd, handle_t handle ); +extern void read_request( struct thread *thread ); extern void send_reply( struct thread *thread, union generic_request *request ); 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( struct thread *thread, const union generic_request *request ); extern void trace_reply( struct thread *thread, const union generic_request *request ); @@ -71,7 +71,7 @@ DECL_HANDLER(boot_done); DECL_HANDLER(init_process); DECL_HANDLER(init_process_done); DECL_HANDLER(init_thread); -DECL_HANDLER(get_thread_buffer); +DECL_HANDLER(set_thread_buffer); DECL_HANDLER(terminate_process); DECL_HANDLER(terminate_thread); DECL_HANDLER(get_process_info); @@ -186,7 +186,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_init_process, (req_handler)req_init_process_done, (req_handler)req_init_thread, - (req_handler)req_get_thread_buffer, + (req_handler)req_set_thread_buffer, (req_handler)req_terminate_process, (req_handler)req_terminate_thread, (req_handler)req_get_process_info, diff --git a/server/thread.c b/server/thread.c index 25361c4af2b728e31ad2b7093f93ce764ac5c2b0..60363c7f15e7049fdc0b6b59443d77e34bb3ec3f 100644 --- a/server/thread.c +++ b/server/thread.c @@ -17,10 +17,6 @@ #include <sys/mman.h> #endif #include <sys/types.h> -#ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> -#endif -#include <sys/uio.h> #include <unistd.h> #include <stdarg.h> @@ -84,61 +80,6 @@ static const struct object_ops thread_ops = static struct thread *first_thread; static struct thread *booting_thread; -/* allocate the buffer for the communication with the client */ -static int alloc_client_buffer( struct thread *thread ) -{ - union generic_request *req; - int fd = -1, fd_pipe[2], wait_pipe[2]; - - wait_pipe[0] = wait_pipe[1] = -1; - if (pipe( fd_pipe ) == -1) - { - file_set_error(); - return 0; - } - if (pipe( wait_pipe ) == -1) goto error; - 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; - if (!(thread->request_fd = create_request_socket( thread ))) goto error; - thread->reply_fd = fd_pipe[1]; - thread->wait_fd = wait_pipe[1]; - - /* make the pipes non-blocking */ - fcntl( fd_pipe[1], F_SETFL, O_NONBLOCK ); - fcntl( wait_pipe[1], F_SETFL, O_NONBLOCK ); - - /* build the first request into the buffer and send it */ - req = thread->buffer; - req->get_thread_buffer.pid = get_process_id( thread->process ); - req->get_thread_buffer.tid = get_thread_id( thread ); - req->get_thread_buffer.boot = (thread == booting_thread); - req->get_thread_buffer.version = SERVER_PROTOCOL_VERSION; - - /* add it here since send_client_fd may call kill_thread */ - add_process_thread( thread->process, thread ); - - send_client_fd( thread, fd_pipe[0], 0 ); - send_client_fd( thread, wait_pipe[0], 0 ); - send_client_fd( thread, fd, 0 ); - send_reply( thread, req ); - close( fd_pipe[0] ); - close( wait_pipe[0] ); - close( fd ); - - return 1; - - error: - file_set_error(); - if (fd != -1) close( fd ); - close( fd_pipe[0] ); - close( fd_pipe[1] ); - if (wait_pipe[0] != -1) close( wait_pipe[0] ); - if (wait_pipe[1] != -1) close( wait_pipe[1] ); - return 0; -} - /* initialize the structure for a newly allocated thread */ inline static void init_thread_structure( struct thread *thread ) { @@ -170,7 +111,6 @@ inline static void init_thread_structure( struct thread *thread ) thread->affinity = 1; thread->suspend = 0; thread->buffer = (void *)-1; - thread->last_req = REQ_get_thread_buffer; for (i = 0; i < MAX_INFLIGHT_FDS; i++) thread->inflight[i].server = thread->inflight[i].client = -1; @@ -181,9 +121,6 @@ struct thread *create_thread( int fd, struct process *process ) { struct thread *thread; - int flags = fcntl( fd, F_GETFL, 0 ); - fcntl( fd, F_SETFL, flags | O_NONBLOCK ); - if (!(thread = alloc_object( &thread_ops, fd ))) return NULL; init_thread_structure( thread ); @@ -200,15 +137,10 @@ struct thread *create_thread( int fd, struct process *process ) if ((thread->next = first_thread) != NULL) thread->next->prev = thread; first_thread = thread; -#if 0 + fcntl( fd, F_SETFL, O_NONBLOCK ); set_select_events( &thread->obj, POLLIN ); /* start listening to events */ -#endif - if (!alloc_client_buffer( thread )) goto error; + add_process_thread( thread->process, thread ); return thread; - - error: - release_object( thread ); - return NULL; } /* handle a client event */ @@ -218,9 +150,7 @@ static void thread_poll_event( struct object *obj, int event ) assert( obj->ops == &thread_ops ); if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 ); -#if 0 else if (event & POLLIN) read_request( thread ); -#endif } /* cleanup everything that is no longer needed by a dead thread */ @@ -773,8 +703,6 @@ struct thread_snapshot *thread_snap( int *count ) DECL_HANDLER(boot_done) { debug_level = max( debug_level, req->debug_level ); - /* Make sure last_req is initialized */ - current->last_req = REQ_boot_done; if (current == booting_thread) { booting_thread = (struct thread *)~0UL; /* make sure it doesn't match other threads */ @@ -786,48 +714,97 @@ DECL_HANDLER(boot_done) DECL_HANDLER(new_thread) { struct thread *thread; - int sock[2]; + int request_fd = thread_get_inflight_fd( current, req->request_fd ); - if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1) + if (request_fd == -1) { - if ((thread = create_thread( sock[0], current->process ))) + set_error( STATUS_INVALID_HANDLE ); + return; + } + + if ((thread = create_thread( request_fd, current->process ))) + { + if (req->suspend) thread->suspend++; + req->tid = thread; + if ((req->handle = alloc_handle( current->process, thread, + THREAD_ALL_ACCESS, req->inherit ))) { - if (req->suspend) thread->suspend++; - req->tid = thread; - if ((req->handle = alloc_handle( current->process, thread, - THREAD_ALL_ACCESS, req->inherit ))) - { - send_client_fd( current, sock[1], req->handle ); - close( sock[1] ); - /* thread object will be released when the thread gets killed */ - return; - } - kill_thread( thread, 1 ); + /* thread object will be released when the thread gets killed */ + return; } - close( sock[1] ); + kill_thread( thread, 1 ); + request_fd = -1; } - else file_set_error(); -} - -/* retrieve the thread buffer file descriptor */ -DECL_HANDLER(get_thread_buffer) -{ - fatal_protocol_error( current, "get_thread_buffer: should never get called directly\n" ); } /* initialize a new thread */ DECL_HANDLER(init_thread) { + int reply_fd = thread_get_inflight_fd( current, req->reply_fd ); + int wait_fd = thread_get_inflight_fd( current, req->wait_fd ); + if (current->unix_pid) { fatal_protocol_error( current, "init_thread: already running\n" ); - return; + goto error; } + if (reply_fd == -1) + { + fatal_protocol_error( current, "bad reply fd\n" ); + goto error; + } + if (wait_fd == -1) + { + fatal_protocol_error( current, "bad wait fd\n" ); + goto error; + } + current->unix_pid = req->unix_pid; current->teb = req->teb; + current->reply_fd = reply_fd; + current->wait_fd = wait_fd; + if (current->suspend + current->process->suspend > 0) stop_thread( current ); if (current->process->running_threads > 1) generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, req->entry ); + + req->pid = get_process_id( current->process ); + req->tid = get_thread_id( current ); + req->boot = (current == booting_thread); + req->version = SERVER_PROTOCOL_VERSION; + return; + + error: + if (reply_fd != -1) close( reply_fd ); + if (wait_fd != -1) close( wait_fd ); +} + +/* set the shared buffer for a thread */ +DECL_HANDLER(set_thread_buffer) +{ + unsigned int size = MAX_REQUEST_LENGTH; + unsigned int offset = 0; + int fd = thread_get_inflight_fd( current, req->fd ); + + req->size = size; + req->offset = offset; + + if (fd != -1) + { + if (ftruncate( fd, size ) == -1) file_set_error(); + else + { + void *buffer = mmap( 0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset ); + if (buffer == (void *)-1) file_set_error(); + else + { + if (current->buffer != (void *)-1) munmap( current->buffer, size ); + current->buffer = buffer; + } + } + close( fd ); + } + else set_error( STATUS_INVALID_HANDLE ); } /* terminate a thread */ diff --git a/server/thread.h b/server/thread.h index 5d25f3c9cc627234d064107a1b47d447f42b5c80..6b71bdd9238626877bcb68e1f7824160fbd03ffc 100644 --- a/server/thread.h +++ b/server/thread.h @@ -75,7 +75,6 @@ struct thread int affinity; /* affinity mask */ int suspend; /* suspend count */ void *buffer; /* buffer for communication with the client */ - enum request last_req; /* last request received (for debugging) */ }; struct thread_snapshot diff --git a/server/trace.c b/server/trace.c index 744bc8466395d7842824f6b8d00c95e558cc4049..14fa6f28e608468a25deca7cd076a9f17bf7d930 100644 --- a/server/trace.c +++ b/server/trace.c @@ -299,7 +299,8 @@ static void dump_get_new_process_info_reply( const struct get_new_process_info_r static void dump_new_thread_request( const struct new_thread_request *req ) { fprintf( stderr, " suspend=%d,", req->suspend ); - fprintf( stderr, " inherit=%d", req->inherit ); + fprintf( stderr, " inherit=%d,", req->inherit ); + fprintf( stderr, " request_fd=%d", req->request_fd ); } static void dump_new_thread_reply( const struct new_thread_request *req ) @@ -351,14 +352,12 @@ static void dump_init_thread_request( const struct init_thread_request *req ) { fprintf( stderr, " unix_pid=%d,", req->unix_pid ); fprintf( stderr, " teb=%p,", req->teb ); - fprintf( stderr, " entry=%p", req->entry ); -} - -static void dump_get_thread_buffer_request( const struct get_thread_buffer_request *req ) -{ + fprintf( stderr, " entry=%p,", req->entry ); + fprintf( stderr, " reply_fd=%d,", req->reply_fd ); + fprintf( stderr, " wait_fd=%d", req->wait_fd ); } -static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request *req ) +static void dump_init_thread_reply( const struct init_thread_request *req ) { fprintf( stderr, " pid=%p,", req->pid ); fprintf( stderr, " tid=%p,", req->tid ); @@ -366,6 +365,17 @@ static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request fprintf( stderr, " version=%d", req->version ); } +static void dump_set_thread_buffer_request( const struct set_thread_buffer_request *req ) +{ + fprintf( stderr, " fd=%d", req->fd ); +} + +static void dump_set_thread_buffer_reply( const struct set_thread_buffer_request *req ) +{ + fprintf( stderr, " offset=%08x,", req->offset ); + fprintf( stderr, " size=%08x", req->size ); +} + static void dump_terminate_process_request( const struct terminate_process_request *req ) { fprintf( stderr, " handle=%d,", req->handle ); @@ -1492,7 +1502,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_init_process_request, (dump_func)dump_init_process_done_request, (dump_func)dump_init_thread_request, - (dump_func)dump_get_thread_buffer_request, + (dump_func)dump_set_thread_buffer_request, (dump_func)dump_terminate_process_request, (dump_func)dump_terminate_thread_request, (dump_func)dump_get_process_info_request, @@ -1603,8 +1613,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)dump_init_process_reply, (dump_func)dump_init_process_done_reply, - (dump_func)0, - (dump_func)dump_get_thread_buffer_reply, + (dump_func)dump_init_thread_reply, + (dump_func)dump_set_thread_buffer_reply, (dump_func)dump_terminate_process_reply, (dump_func)dump_terminate_thread_reply, (dump_func)dump_get_process_info_reply, @@ -1716,7 +1726,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "init_process", "init_process_done", "init_thread", - "get_thread_buffer", + "set_thread_buffer", "terminate_process", "terminate_thread", "get_process_info", @@ -1884,7 +1894,6 @@ void trace_request( struct thread *thread, const union generic_request *request { enum request req = request->header.req; cur_pos = 0; - current->last_req = req; if (req < REQ_NB_REQUESTS) { fprintf( stderr, "%08x: %s(", (unsigned int)thread, req_names[req] ); @@ -1897,14 +1906,20 @@ void trace_request( struct thread *thread, const union generic_request *request void trace_reply( struct thread *thread, const union generic_request *request ) { - fprintf( stderr, "%08x: %s() = %s", - (unsigned int)thread, req_names[thread->last_req], get_status_name(thread->error) ); - if (reply_dumpers[thread->last_req]) + enum request req = request->header.req; + if (req < REQ_NB_REQUESTS) { - fprintf( stderr, " {" ); - cur_pos = 0; - reply_dumpers[thread->last_req]( request ); - fprintf( stderr, " }" ); + fprintf( stderr, "%08x: %s() = %s", + (unsigned int)thread, req_names[req], get_status_name(thread->error) ); + if (reply_dumpers[req]) + { + fprintf( stderr, " {" ); + cur_pos = 0; + reply_dumpers[req]( request ); + fprintf( stderr, " }" ); + } + fputc( '\n', stderr ); } - fputc( '\n', stderr ); + else fprintf( stderr, "%08x: %d() = %s\n", + (unsigned int)thread, req, get_status_name(thread->error) ); }