From d90e964cee892ffaf4554c6b20844066bc6867bb Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 21 Feb 2001 04:21:50 +0000 Subject: [PATCH] Added separate server pipe to wait on blocking server calls. Send the complete request/reply through the request fifo instead of just a dummy byte. Convert error status to text in server reply tracing. --- dlls/kernel/kernel.spec | 6 +- include/server.h | 3 +- include/thread.h | 9 +-- scheduler/client.c | 48 ++++++++------- scheduler/synchro.c | 56 ++++++++++++----- scheduler/thread.c | 2 + server/request.c | 130 +++++++++++++++++++++------------------ server/request.h | 14 ++--- server/thread.c | 131 +++++++++++++++++++++------------------- server/thread.h | 8 +-- server/trace.c | 86 ++++++++++++++++++++------ 11 files changed, 292 insertions(+), 201 deletions(-) diff --git a/dlls/kernel/kernel.spec b/dlls/kernel/kernel.spec index 96242c12d4d..b4e40d58ac7 100644 --- a/dlls/kernel/kernel.spec +++ b/dlls/kernel/kernel.spec @@ -369,8 +369,8 @@ owner kernel32 457 pascal CreateW32Event(long long) WIN16_CreateEvent 458 pascal SetW32Event(long) SetEvent 459 pascal ResetW32Event(long) ResetEvent -460 pascal WaitForSingleObject(long long) WIN16_WaitForSingleObject -461 pascal WaitForMultipleObjects(long ptr long long) WIN16_WaitForMultipleObjects +460 pascal WaitForSingleObject(long long) WaitForSingleObject16 +461 pascal WaitForMultipleObjects(long ptr long long) WaitForMultipleObjects16 462 pascal GetCurrentThreadId() GetCurrentThreadId 463 pascal SetThreadQueue(long word) SetThreadQueue16 464 pascal GetThreadQueue(long) GetThreadQueue16 @@ -406,7 +406,7 @@ owner kernel32 494 stub KERNEL_494 # 495 is present only in Win98 -495 pascal WaitForMultipleObjectsEx(long ptr long long long) WIN16_WaitForMultipleObjectsEx +495 pascal WaitForMultipleObjectsEx(long ptr long long long) WaitForMultipleObjectsEx16 # 500-544 are WinNT extensions; some are also available in Win95 diff --git a/include/server.h b/include/server.h index 1e437041549..60f19134568 100644 --- a/include/server.h +++ b/include/server.h @@ -417,7 +417,6 @@ struct select_request IN int flags; /* wait flags (see below) */ IN int sec; /* absolute timeout */ IN int usec; /* absolute timeout */ - OUT int signaled; /* signaled handle */ IN VARARG(handles,handles); /* handles to select on */ }; #define SELECT_ALL 1 @@ -1593,7 +1592,7 @@ union generic_request struct async_result_request async_result; }; -#define SERVER_PROTOCOL_VERSION 38 +#define SERVER_PROTOCOL_VERSION 39 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ diff --git a/include/thread.h b/include/thread.h index 572b981f8fb..a3526b16849 100644 --- a/include/thread.h +++ b/include/thread.h @@ -96,13 +96,14 @@ typedef struct _TEB void *buffer; /* --3 204 Buffer shared with server */ 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 */ + int wait_fd; /* --3 210 fd for sleeping server requests */ + struct server_buffer_info *buffer_info; /* --3 214 Buffer information */ + 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[631]; /* --n 21c */ + 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 1c022986d6e..b13ce7ce80d 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -154,14 +154,15 @@ void *wine_server_alloc_req( size_t fixed_size, size_t var_size ) */ static void send_request( enum request req, union generic_request *request ) { + int ret; + request->header.req = req; NtCurrentTeb()->buffer_info->cur_req = (char *)request - (char *)NtCurrentTeb()->buffer; - /* write a single byte; the value is ignored anyway */ - if (write( NtCurrentTeb()->request_fd, request, 1 ) == -1) - { - if (errno == EPIPE) SYSDEPS_ExitThread(0); - server_protocol_perror( "sendmsg" ); - } + if ((ret = write( NtCurrentTeb()->request_fd, request, sizeof(*request) )) == sizeof(*request)) + return; + if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); + if (errno == EPIPE) SYSDEPS_ExitThread(0); + server_protocol_perror( "sendmsg" ); } /*********************************************************************** @@ -176,10 +177,10 @@ static void send_request_fd( enum request req, union generic_request *request, i #endif struct msghdr msghdr; struct iovec vec; + int ret; - /* write a single byte; the value is ignored anyway */ vec.iov_base = (void *)request; - vec.iov_len = 1; + vec.iov_len = sizeof(*request); msghdr.msg_name = NULL; msghdr.msg_namelen = 0; @@ -201,11 +202,10 @@ static void send_request_fd( enum request req, union generic_request *request, i request->header.req = req; - if (sendmsg( NtCurrentTeb()->socket, &msghdr, 0 ) == -1) - { - if (errno == EPIPE) SYSDEPS_ExitThread(0); - server_protocol_perror( "sendmsg" ); - } + if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(*request)) return; + if (ret >= 0) server_protocol_error( "partial write %d\n", ret ); + if (errno == EPIPE) SYSDEPS_ExitThread(0); + server_protocol_perror( "sendmsg" ); } /*********************************************************************** @@ -213,15 +213,16 @@ static void send_request_fd( enum request req, union generic_request *request, i * * Wait for a reply from the server. */ -static void wait_reply(void) +static void wait_reply( union generic_request *req ) { int ret; - char dummy[1]; for (;;) { - if ((ret = read( NtCurrentTeb()->reply_fd, dummy, 1 )) > 0) return; + if ((ret = read( NtCurrentTeb()->reply_fd, req, sizeof(*req) )) == sizeof(*req)) + return; if (!ret) break; + if (ret > 0) server_protocol_error( "partial read %d\n", ret ); if (errno == EINTR) continue; if (errno == EPIPE) break; server_protocol_perror("read"); @@ -240,7 +241,7 @@ unsigned int wine_server_call( enum request req ) { union generic_request *req_ptr = NtCurrentTeb()->buffer; send_request( req, req_ptr ); - wait_reply(); + wait_reply( req_ptr ); return req_ptr->header.error; } @@ -256,7 +257,7 @@ unsigned int server_call_fd( enum request req, int fd_out ) union generic_request *req_ptr = NtCurrentTeb()->buffer; send_request_fd( req, req_ptr, fd_out ); - wait_reply(); + wait_reply( req_ptr ); if ((res = req_ptr->header.error)) SetLastError( RtlNtStatusToDosError(res) ); return res; /* error code */ @@ -609,6 +610,10 @@ int CLIENT_InitThread(void) 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 */ + 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 */ + fd = wine_server_recv_fd( 0, 0 ); if (fd == -1) server_protocol_error( "no fd received for thread buffer\n" ); @@ -618,15 +623,16 @@ int CLIENT_InitThread(void) if (teb->buffer == (void*)-1) server_protocol_perror( "mmap" ); teb->buffer_info = (struct server_buffer_info *)((char *)teb->buffer + size) - 1; - wait_reply(); - 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.\nOr maybe wrong wineserver still running ?", + "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; diff --git a/scheduler/synchro.c b/scheduler/synchro.c index 6d42029a5d3..e5fb13ff1cc 100644 --- a/scheduler/synchro.c +++ b/scheduler/synchro.c @@ -5,10 +5,11 @@ */ #include +#include #include #include #include -#include "heap.h" + #include "file.h" /* for DOSFS_UnixTimeToFileTime */ #include "thread.h" #include "winerror.h" @@ -34,6 +35,29 @@ inline static void get_timeout( struct timeval *when, int timeout ) } +/*********************************************************************** + * wait_reply + * + * Wait for a reply on the waiting pipe of the current thread. + */ +static int wait_reply(void) +{ + int signaled; + for (;;) + { + int ret = read( NtCurrentTeb()->wait_fd, &signaled, sizeof(signaled) ); + if (ret == sizeof(signaled)) return signaled; + if (!ret) break; + if (ret > 0) server_protocol_error( "partial wakeup read %d\n", ret ); + if (errno == EINTR) continue; + if (errno == EPIPE) break; + server_protocol_perror("read"); + } + /* the server closed the connection; time to die... */ + SYSDEPS_ExitThread(0); +} + + /*********************************************************************** * call_apcs * @@ -166,22 +190,27 @@ DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, if (alertable) req->flags |= SELECT_ALERTABLE; if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT; - server_call( REQ_SELECT ); - ret = req->signaled; + ret = server_call_noerr( REQ_SELECT ); } SERVER_END_REQ; + if (ret == STATUS_PENDING) ret = wait_reply(); if (ret != STATUS_USER_APC) break; call_apcs( alertable ); if (alertable) break; } + if (HIWORD(ret)) /* is it an error code? */ + { + SetLastError( RtlNtStatusToDosError(ret) ); + ret = WAIT_FAILED; + } return ret; } /*********************************************************************** - * WIN16_WaitForSingleObject (KERNEL.460) + * WaitForSingleObject16 (KERNEL.460) */ -DWORD WINAPI WIN16_WaitForSingleObject( HANDLE handle, DWORD timeout ) +DWORD WINAPI WaitForSingleObject16( HANDLE handle, DWORD timeout ) { DWORD retval, mutex_count; @@ -192,26 +221,24 @@ DWORD WINAPI WIN16_WaitForSingleObject( HANDLE handle, DWORD timeout ) } /*********************************************************************** - * WIN16_WaitForMultipleObjects (KERNEL.461) + * WaitForMultipleObjects16 (KERNEL.461) */ -DWORD WINAPI WIN16_WaitForMultipleObjects( DWORD count, const HANDLE *handles, - BOOL wait_all, DWORD timeout ) +DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles, + BOOL wait_all, DWORD timeout ) { DWORD retval, mutex_count; ReleaseThunkLock( &mutex_count ); - retval = WaitForMultipleObjects( count, handles, wait_all, timeout ); + retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE ); RestoreThunkLock( mutex_count ); return retval; } /*********************************************************************** - * WIN16_WaitForMultipleObjectsEx (KERNEL.495) + * WaitForMultipleObjectsEx16 (KERNEL.495) */ -DWORD WINAPI WIN16_WaitForMultipleObjectsEx( DWORD count, - const HANDLE *handles, - BOOL wait_all, DWORD timeout, - BOOL alertable ) +DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles, + BOOL wait_all, DWORD timeout, BOOL alertable ) { DWORD retval, mutex_count; @@ -220,4 +247,3 @@ DWORD WINAPI WIN16_WaitForMultipleObjectsEx( DWORD count, RestoreThunkLock( mutex_count ); return retval; } - diff --git a/scheduler/thread.c b/scheduler/thread.c index 12bbff6651b..2410c4c37fa 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -93,6 +93,7 @@ static BOOL THREAD_InitTEB( TEB *teb ) teb->socket = -1; teb->request_fd = -1; teb->reply_fd = -1; + teb->wait_fd = -1; teb->stack_top = (void *)~0UL; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer; @@ -117,6 +118,7 @@ static void CALLBACK THREAD_FreeTEB( TEB *teb ) if (teb->socket != -1) close( teb->socket ); close( teb->request_fd ); close( teb->reply_fd ); + close( teb->wait_fd ); if (teb->stack_sel) FreeSelector16( teb->stack_sel ); FreeSelector16( teb->teb_sel ); if (teb->buffer) munmap( (void *)teb->buffer, diff --git a/server/request.c b/server/request.c index fcaea8c95c3..c707aea00bc 100644 --- a/server/request.c +++ b/server/request.c @@ -129,6 +129,20 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... ) kill_thread( thread, 1 ); } +/* complain about a protocol error and terminate the client connection */ +void fatal_protocol_perror( struct thread *thread, const char *err, ... ) +{ + va_list args; + + va_start( args, err ); + fprintf( stderr, "Protocol error:%p: ", thread ); + vfprintf( stderr, err, args ); + perror( " " ); + va_end( args ); + thread->exit_code = 1; + kill_thread( thread, 1 ); +} + /* die on a fatal error */ void fatal_error( const char *err, ... ) { @@ -155,20 +169,24 @@ void fatal_perror( const char *err, ... ) } /* call a request handler */ -static inline void call_req_handler( struct thread *thread ) +static inline void call_req_handler( struct thread *thread, union generic_request *request ) { - enum request req; + enum request req = request->header.req; + current = thread; clear_error(); - req = ((struct request_header *)current->buffer)->req; + if (debug_level) trace_request( thread, request ); - if (debug_level) trace_request( req ); - - if (req < REQ_NB_REQUESTS) + if ((unsigned int)request->header.var_offset + request->header.var_size > MAX_REQUEST_LENGTH) { - req_handlers[req]( current->buffer ); - if (current && !current->wait) send_reply( current ); + fatal_protocol_error( current, "bad request offset/size %d/%d\n", + request->header.var_offset, request->header.var_size ); + } + else if (req < REQ_NB_REQUESTS) + { + req_handlers[req]( request ); + if (current) send_reply( current, request ); current = NULL; return; } @@ -176,18 +194,32 @@ static inline void call_req_handler( struct thread *thread ) } /* send a reply to a thread */ -void send_reply( struct thread *thread ) +void send_reply( struct thread *thread, union generic_request *request ) { - assert( !thread->wait ); - if (debug_level) trace_reply( thread ); - if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT ); + int ret; + + assert (thread->pass_fd == -1); + + if (debug_level) trace_reply( thread, request ); + + request->header.error = thread->error; + + if ((ret = write( thread->reply_fd, request, sizeof(*request) )) != sizeof(*request)) + { + if (ret >= 0) + fatal_protocol_error( thread, "partial write %d\n", ret ); + else if (errno == EPIPE) + kill_thread( thread, 0 ); /* normal death */ + else + fatal_protocol_perror( thread, "sendmsg" ); + } } /* read a message from a client that has something to say */ void read_request( struct thread *thread ) { + union generic_request req; int ret; - char dummy[1]; #ifdef HAVE_MSGHDR_ACCRIGHTS msghdr.msg_accrightslen = sizeof(int); @@ -200,57 +232,39 @@ void read_request( struct thread *thread ) assert( thread->pass_fd == -1 ); - myiovec.iov_base = dummy; - myiovec.iov_len = 1; + myiovec.iov_base = &req; + myiovec.iov_len = sizeof(req); ret = recvmsg( thread->obj.fd, &msghdr, 0 ); #ifndef HAVE_MSGHDR_ACCRIGHTS thread->pass_fd = cmsg.fd; #endif - if (ret > 0) + if (ret == sizeof(req)) { - call_req_handler( thread ); + call_req_handler( thread, &req ); thread->pass_fd = -1; return; } if (!ret) /* closed pipe */ - { kill_thread( thread, 0 ); - return; - } - perror("recvmsg"); - thread->exit_code = 1; - kill_thread( thread, 1 ); + else if (ret > 0) + fatal_protocol_error( thread, "partial recvmsg %d\n", ret ); + else + fatal_protocol_perror( thread, "recvmsg" ); } -/* send a message to a client that is ready to receive something */ -int write_request( struct thread *thread ) +/* send the wakeup signal to a thread */ +int send_thread_wakeup( struct thread *thread, int signaled ) { - int ret; - struct request_header *header = thread->buffer; - - header->error = thread->error; - - assert (thread->pass_fd == -1); - - ret = write( thread->reply_fd, header, 1 ); - if (ret > 0) - { - set_select_events( &thread->obj, POLLIN ); - return 1; - } - if (errno == EWOULDBLOCK) return 0; /* not a fatal error */ - if (errno == EPIPE) - { + int ret = write( thread->wait_fd, &signaled, sizeof(signaled) ); + if (ret == sizeof(signaled)) return 0; + if (ret >= 0) + fatal_protocol_error( thread, "partial wakeup write %d\n", ret ); + else if (errno == EPIPE) kill_thread( thread, 0 ); /* normal death */ - } else - { - perror("sendmsg"); - thread->exit_code = 1; - kill_thread( thread, 1 ); - } + fatal_protocol_perror( thread, "write" ); return -1; } @@ -283,9 +297,7 @@ int send_client_fd( struct thread *thread, int fd, handle_t handle ) } else { - perror("sendmsg"); - thread->exit_code = 1; - kill_thread( thread, 1 ); + fatal_protocol_perror( thread, "sendmsg" ); } return -1; } @@ -349,23 +361,20 @@ static void request_socket_poll_event( struct object *obj, int event ) else if (event & POLLIN) { struct thread *thread = sock->thread; + union generic_request req; int ret; - char dummy[1]; - ret = read( sock->obj.fd, &dummy, 1 ); - if (ret > 0) + if ((ret = read( sock->obj.fd, &req, sizeof(req) )) == sizeof(req)) { - call_req_handler( thread ); + call_req_handler( thread, &req ); return; } if (!ret) /* closed pipe */ - { kill_thread( thread, 0 ); - return; - } - perror("read"); - thread->exit_code = 1; - kill_thread( thread, 1 ); + else if (ret > 0) + fatal_protocol_error( thread, "partial read %d\n", ret ); + else + fatal_protocol_perror( thread, "read" ); } } @@ -384,6 +393,7 @@ struct object *create_request_socket( struct thread *thread ) 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; } diff --git a/server/request.h b/server/request.h index 9b8547db08d..39afc5f90a9 100644 --- a/server/request.h +++ b/server/request.h @@ -32,22 +32,16 @@ extern void fatal_error( const char *err, ... ) WINE_NORETURN; 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 int send_thread_wakeup( struct thread *thread, int signaled ); extern int send_client_fd( struct thread *thread, int fd, handle_t handle ); -extern void send_reply( 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( enum request req ); -extern void trace_reply( struct thread *thread ); - -/* get the request buffer */ -static inline void *get_req_ptr( struct thread *thread ) -{ - return thread->buffer; -} +extern void trace_request( struct thread *thread, const union generic_request *request ); +extern void trace_reply( struct thread *thread, const union generic_request *request ); /* get the request vararg data */ inline static void *get_req_data( const void *req ) diff --git a/server/thread.c b/server/thread.c index 31e3ff090dd..301c3b0cb92 100644 --- a/server/thread.c +++ b/server/thread.c @@ -40,7 +40,6 @@ struct thread_wait int flags; struct timeval timeout; struct timeout_user *user; - sleep_reply reply; /* function to build the reply */ struct wait_queue_entry queues[1]; }; @@ -88,14 +87,16 @@ static struct thread *booting_thread; /* allocate the buffer for the communication with the client */ static int alloc_client_buffer( struct thread *thread ) { - struct get_thread_buffer_request *req; - int fd, fd_pipe[2]; + 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, @@ -103,21 +104,30 @@ static int alloc_client_buffer( struct thread *thread ) 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]; + 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->pid = get_process_id( thread->process ); - req->tid = get_thread_id( thread ); - req->boot = (thread == booting_thread); - req->version = SERVER_PROTOCOL_VERSION; + 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 ); + send_reply( thread, req ); close( fd_pipe[0] ); + close( wait_pipe[0] ); close( fd ); + return 1; error: @@ -125,6 +135,8 @@ static int alloc_client_buffer( struct thread *thread ) 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; } @@ -155,6 +167,7 @@ struct thread *create_thread( int fd, struct process *process ) thread->pass_fd = -1; thread->request_fd = NULL; thread->reply_fd = -1; + thread->wait_fd = -1; thread->state = RUNNING; thread->attached = 0; thread->exit_code = 0; @@ -194,11 +207,7 @@ void thread_poll_event( struct object *obj, int event ) assert( obj->ops == &thread_ops ); if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 ); - else - { - if (event & POLLOUT) write_request( thread ); - if (event & POLLIN) read_request( thread ); - } + else if (event & POLLIN) read_request( thread ); } /* destroy a thread when its refcount is 0 */ @@ -218,6 +227,7 @@ static void destroy_thread( struct object *obj ) 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->wait_fd != -1) close( thread->wait_fd ); if (thread->pass_fd != -1) close( thread->pass_fd ); if (thread->request_fd) release_object( thread->request_fd ); } @@ -355,8 +365,7 @@ static void end_wait( struct thread *thread ) } /* build the thread wait structure */ -static int wait_on( int count, struct object *objects[], int flags, - int sec, int usec, sleep_reply func ) +static int wait_on( int count, struct object *objects[], int flags, int sec, int usec ) { struct thread_wait *wait; struct wait_queue_entry *entry; @@ -367,7 +376,6 @@ static int wait_on( int count, struct object *objects[], int flags, wait->count = count; wait->flags = flags; wait->user = NULL; - wait->reply = func; if (flags & SELECT_TIMEOUT) { wait->timeout.tv_sec = sec; @@ -389,14 +397,13 @@ static int wait_on( int count, struct object *objects[], int flags, } /* check if the thread waiting condition is satisfied */ -static int check_wait( struct thread *thread, struct object **object ) +static int check_wait( struct thread *thread ) { int i, signaled; struct thread_wait *wait = thread->wait; struct wait_queue_entry *entry = wait->queues; assert( wait ); - *object = NULL; if (wait->flags & SELECT_ALL) { int not_ok = 0; @@ -419,7 +426,6 @@ static int check_wait( struct thread *thread, struct object **object ) if (!entry->obj->ops->signaled( entry->obj, thread )) continue; /* Wait satisfied: tell it to the object */ signaled = i; - *object = entry->obj; if (entry->obj->ops->satisfied( entry->obj, thread )) signaled = i + STATUS_ABANDONED_WAIT_0; return signaled; @@ -438,23 +444,17 @@ static int check_wait( struct thread *thread, struct object **object ) return -1; } -/* build a reply to the select request */ -static void build_select_reply( struct thread *thread, struct object *obj, int signaled ) -{ - struct select_request *req = get_req_ptr( thread ); - req->signaled = signaled; -} - /* attempt to wake up a thread */ /* return 1 if OK, 0 if the wait condition is still not satisfied */ static int wake_thread( struct thread *thread ) { int signaled; - struct object *object; - if ((signaled = check_wait( thread, &object )) == -1) return 0; - thread->error = 0; - thread->wait->reply( thread, object, signaled ); + if ((signaled = check_wait( thread )) == -1) return 0; + + if (debug_level) fprintf( stderr, "%08x: *wakeup* object=%d\n", + (unsigned int)thread, signaled ); end_wait( thread ); + send_thread_wakeup( thread, signaled ); return 1; } @@ -462,21 +462,45 @@ static int wake_thread( struct thread *thread ) static void thread_timeout( void *ptr ) { struct thread *thread = ptr; + if (debug_level) fprintf( stderr, "%08x: *timeout*\n", (unsigned int)thread ); + assert( thread->wait ); - thread->error = 0; thread->wait->user = NULL; - thread->wait->reply( thread, NULL, STATUS_TIMEOUT ); end_wait( thread ); - send_reply( thread ); + send_thread_wakeup( thread, STATUS_TIMEOUT ); } -/* sleep on a list of objects */ -int sleep_on( int count, struct object *objects[], int flags, int sec, int usec, sleep_reply func ) +/* select on a list of handles */ +static void select_on( int count, handle_t *handles, int flags, int sec, int usec ) { + int ret, i; + struct object *objects[MAXIMUM_WAIT_OBJECTS]; + assert( !current->wait ); - if (!wait_on( count, objects, flags, sec, usec, func )) return 0; - if (wake_thread( current )) return 1; + + if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + for (i = 0; i < count; i++) + { + if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL ))) + break; + } + + if (i < count) goto done; + if (!wait_on( count, objects, flags, sec, usec )) goto done; + + if ((ret = check_wait( current )) != -1) + { + /* condition is already satisfied */ + end_wait( current ); + set_error( ret ); + goto done; + } + /* now we need to wait */ if (flags & SELECT_TIMEOUT) { @@ -484,32 +508,13 @@ int sleep_on( int count, struct object *objects[], int flags, int sec, int usec, thread_timeout, current ))) { end_wait( current ); - return 0; + goto done; } } - return 1; -} + set_error( STATUS_PENDING ); -/* select on a list of handles */ -static int select_on( int count, handle_t *handles, int flags, int sec, int usec ) -{ - int ret = 0; - int i; - struct object *objects[MAXIMUM_WAIT_OBJECTS]; - - if ((count < 0) || (count > MAXIMUM_WAIT_OBJECTS)) - { - set_error( STATUS_INVALID_PARAMETER ); - return 0; - } - for (i = 0; i < count; i++) - { - if (!(objects[i] = get_handle_obj( current->process, handles[i], SYNCHRONIZE, NULL ))) - break; - } - if (i == count) ret = sleep_on( count, objects, flags, sec, usec, build_select_reply ); +done: while (--i >= 0) release_object( objects[i] ); - return ret; } /* attempt to wake threads sleeping on the object wait queue */ @@ -523,7 +528,6 @@ void wake_up( struct object *obj, int max ) entry = entry->next; if (wake_thread( thread )) { - send_reply( thread ); if (max && !--max) break; } } @@ -558,7 +562,7 @@ int thread_queue_apc( struct thread *thread, struct object *owner, void *func, if (!apc->prev) /* first one */ { queue->head = apc; - if (thread->wait && wake_thread( thread )) send_reply( thread ); + if (thread->wait) wake_thread( thread ); } return 1; } @@ -648,9 +652,11 @@ void kill_thread( struct thread *thread, int violent_death ) remove_select_user( &thread->obj ); release_object( thread->request_fd ); close( thread->reply_fd ); + close( thread->wait_fd ); munmap( thread->buffer, MAX_REQUEST_LENGTH ); thread->request_fd = NULL; thread->reply_fd = -1; + thread->wait_fd = -1; thread->buffer = (void *)-1; release_object( thread ); } @@ -819,8 +825,7 @@ DECL_HANDLER(resume_thread) DECL_HANDLER(select) { int count = get_req_data_size(req) / sizeof(int); - if (!select_on( count, get_req_data(req), req->flags, req->sec, req->usec )) - req->signaled = -1; + select_on( count, get_req_data(req), req->flags, req->sec, req->usec ); } /* queue an APC for a thread */ diff --git a/server/thread.h b/server/thread.h index 4b5aa11fc05..83c3ad5f8bd 100644 --- a/server/thread.h +++ b/server/thread.h @@ -55,7 +55,8 @@ struct thread unsigned int error; /* current error code */ 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 */ + int reply_fd; /* fd to send a reply to a client */ + int wait_fd; /* fd to use to wake a sleeping client */ enum run_state state; /* running state */ int attached; /* is thread attached with ptrace? */ int exit_code; /* thread exit code */ @@ -77,9 +78,6 @@ struct thread_snapshot int priority; /* priority class */ }; -/* callback function for building the thread reply when sleep_on is finished */ -typedef void (*sleep_reply)( struct thread *thread, struct object *obj, int signaled ); - extern struct thread *current; /* thread functions */ @@ -96,8 +94,6 @@ extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); extern void kill_thread( struct thread *thread, int violent_death ); extern void wake_up( struct object *obj, int max ); -extern int sleep_on( int count, struct object *objects[], int flags, - int sec, int usec, sleep_reply func ); extern int thread_queue_apc( struct thread *thread, struct object *owner, void *func, enum apc_type type, int system, int nb_args, ... ); extern void thread_cancel_apc( struct thread *thread, struct object *owner, int system ); diff --git a/server/trace.c b/server/trace.c index f8bafa64887..61f83789c8f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -550,11 +550,6 @@ static void dump_select_request( const struct select_request *req ) cur_pos += dump_varargs_handles( req ); } -static void dump_select_reply( const struct select_request *req ) -{ - fprintf( stderr, " signaled=%d", req->signaled ); -} - static void dump_create_event_request( const struct create_event_request *req ) { fprintf( stderr, " manual_reset=%d,", req->manual_reset ); @@ -1625,7 +1620,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_handle_info_reply, (dump_func)dump_dup_handle_reply, (dump_func)dump_open_process_reply, - (dump_func)dump_select_reply, + (dump_func)0, (dump_func)dump_create_event_reply, (dump_func)0, (dump_func)dump_open_event_reply, @@ -1827,33 +1822,90 @@ static const char * const req_names[REQ_NB_REQUESTS] = { /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ -void trace_request( enum request req ) +static const char *get_status_name( unsigned int status ) { +#define NAME(status) { #status, STATUS_##status } + static const struct + { + const char *name; + unsigned int value; + } status_names[] = + { + NAME(ACCESS_DENIED), + NAME(ACCESS_VIOLATION), + NAME(BUFFER_OVERFLOW), + NAME(CHILD_MUST_BE_VOLATILE), + NAME(DIRECTORY_NOT_EMPTY), + NAME(DISK_FULL), + NAME(FILE_LOCK_CONFLICT), + NAME(INVALID_FILE_FOR_SECTION), + NAME(INVALID_HANDLE), + NAME(INVALID_PARAMETER), + NAME(KEY_DELETED), + NAME(MEDIA_WRITE_PROTECTED), + NAME(MUTANT_NOT_OWNED), + NAME(NOT_REGISTRY_FILE), + NAME(NO_MEMORY), + NAME(NO_MORE_ENTRIES), + NAME(NO_MORE_FILES), + NAME(NO_SUCH_FILE), + NAME(OBJECT_NAME_COLLISION), + NAME(OBJECT_NAME_INVALID), + NAME(OBJECT_NAME_NOT_FOUND), + NAME(OBJECT_PATH_INVALID), + NAME(OBJECT_TYPE_MISMATCH), + NAME(PENDING), + NAME(PIPE_BROKEN), + NAME(SEMAPHORE_LIMIT_EXCEEDED), + NAME(SHARING_VIOLATION), + NAME(SUSPEND_COUNT_EXCEEDED), + NAME(TIMEOUT), + NAME(TOO_MANY_OPENED_FILES), + NAME(UNSUCCESSFUL), + NAME(USER_APC), + { NULL, 0 } /* terminator */ + }; +#undef NAME + + int i; + static char buffer[10]; + + if (status) + { + for (i = 0; status_names[i].name; i++) + if (status_names[i].value == status) return status_names[i].name; + } + sprintf( buffer, "%x", status ); + return buffer; +} + +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)current, req_names[req] ); + fprintf( stderr, "%08x: %s(", (unsigned int)thread, req_names[req] ); cur_pos = 0; - req_dumpers[req]( current->buffer ); + req_dumpers[req]( request ); } else - fprintf( stderr, "%08x: %d(", (unsigned int)current, req ); - if (current->pass_fd != -1) fprintf( stderr, " ) fd=%d\n", current->pass_fd ); + fprintf( stderr, "%08x: %d(", (unsigned int)thread, req ); + if (thread->pass_fd != -1) fprintf( stderr, " ) fd=%d\n", thread->pass_fd ); else fprintf( stderr, " )\n" ); } -void trace_reply( struct thread *thread ) +void trace_reply( struct thread *thread, const union generic_request *request ) { - fprintf( stderr, "%08x: %s() = %x", - (unsigned int)thread, req_names[thread->last_req], thread->error ); + fprintf( stderr, "%08x: %s() = %s", + (unsigned int)thread, req_names[thread->last_req], get_status_name(thread->error) ); if (reply_dumpers[thread->last_req]) { fprintf( stderr, " {" ); cur_pos = 0; - reply_dumpers[thread->last_req]( thread->buffer ); + reply_dumpers[thread->last_req]( request ); fprintf( stderr, " }" ); } - if (thread->pass_fd != -1) fprintf( stderr, " fd=%d\n", thread->pass_fd ); - else fprintf( stderr, "\n" ); + fputc( '\n', stderr ); }