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.
This commit is contained in:
Alexandre Julliard 2001-02-21 04:21:50 +00:00
parent e187b3ff46
commit d90e964cee
11 changed files with 292 additions and 201 deletions

View file

@ -369,8 +369,8 @@ owner kernel32
457 pascal CreateW32Event(long long) WIN16_CreateEvent 457 pascal CreateW32Event(long long) WIN16_CreateEvent
458 pascal SetW32Event(long) SetEvent 458 pascal SetW32Event(long) SetEvent
459 pascal ResetW32Event(long) ResetEvent 459 pascal ResetW32Event(long) ResetEvent
460 pascal WaitForSingleObject(long long) WIN16_WaitForSingleObject 460 pascal WaitForSingleObject(long long) WaitForSingleObject16
461 pascal WaitForMultipleObjects(long ptr long long) WIN16_WaitForMultipleObjects 461 pascal WaitForMultipleObjects(long ptr long long) WaitForMultipleObjects16
462 pascal GetCurrentThreadId() GetCurrentThreadId 462 pascal GetCurrentThreadId() GetCurrentThreadId
463 pascal SetThreadQueue(long word) SetThreadQueue16 463 pascal SetThreadQueue(long word) SetThreadQueue16
464 pascal GetThreadQueue(long) GetThreadQueue16 464 pascal GetThreadQueue(long) GetThreadQueue16
@ -406,7 +406,7 @@ owner kernel32
494 stub KERNEL_494 494 stub KERNEL_494
# 495 is present only in Win98 # 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 # 500-544 are WinNT extensions; some are also available in Win95

View file

@ -417,7 +417,6 @@ struct select_request
IN int flags; /* wait flags (see below) */ IN int flags; /* wait flags (see below) */
IN int sec; /* absolute timeout */ IN int sec; /* absolute timeout */
IN int usec; /* absolute timeout */ IN int usec; /* absolute timeout */
OUT int signaled; /* signaled handle */
IN VARARG(handles,handles); /* handles to select on */ IN VARARG(handles,handles); /* handles to select on */
}; };
#define SELECT_ALL 1 #define SELECT_ALL 1
@ -1593,7 +1592,7 @@ union generic_request
struct async_result_request async_result; struct async_result_request async_result;
}; };
#define SERVER_PROTOCOL_VERSION 38 #define SERVER_PROTOCOL_VERSION 39
/* ### make_requests end ### */ /* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */ /* Everything above this line is generated automatically by tools/make_requests */

View file

@ -96,13 +96,14 @@ typedef struct _TEB
void *buffer; /* --3 204 Buffer shared with server */ void *buffer; /* --3 204 Buffer shared with server */
int request_fd; /* --3 208 fd for sending server requests */ int request_fd; /* --3 208 fd for sending server requests */
int reply_fd; /* --3 20c fd for receiving server replies */ int reply_fd; /* --3 20c fd for receiving server replies */
struct server_buffer_info *buffer_info; /* --3 210 Buffer information */ int wait_fd; /* --3 210 fd for sleeping server requests */
void *debug_info; /* --3 214 Info for debugstr functions */ struct server_buffer_info *buffer_info; /* --3 214 Buffer information */
void *pthread_data; /* --3 218 Data for pthread emulation */ 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!!) */ /* here is plenty space for wine specific fields (don't forget to change pad6!!) */
/* the following are nt specific fields */ /* the following are nt specific fields */
DWORD pad6[631]; /* --n 21c */ DWORD pad6[630]; /* --n 220 */
UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */ UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */
USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */ USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */
DWORD pad7; /* --n e0c */ DWORD pad7; /* --n e0c */

View file

@ -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 ) static void send_request( enum request req, union generic_request *request )
{ {
int ret;
request->header.req = req; request->header.req = req;
NtCurrentTeb()->buffer_info->cur_req = (char *)request - (char *)NtCurrentTeb()->buffer; NtCurrentTeb()->buffer_info->cur_req = (char *)request - (char *)NtCurrentTeb()->buffer;
/* write a single byte; the value is ignored anyway */ if ((ret = write( NtCurrentTeb()->request_fd, request, sizeof(*request) )) == sizeof(*request))
if (write( NtCurrentTeb()->request_fd, request, 1 ) == -1) return;
{ if (ret >= 0) server_protocol_error( "partial write %d\n", ret );
if (errno == EPIPE) SYSDEPS_ExitThread(0); if (errno == EPIPE) SYSDEPS_ExitThread(0);
server_protocol_perror( "sendmsg" ); server_protocol_perror( "sendmsg" );
}
} }
/*********************************************************************** /***********************************************************************
@ -176,10 +177,10 @@ static void send_request_fd( enum request req, union generic_request *request, i
#endif #endif
struct msghdr msghdr; struct msghdr msghdr;
struct iovec vec; struct iovec vec;
int ret;
/* write a single byte; the value is ignored anyway */
vec.iov_base = (void *)request; vec.iov_base = (void *)request;
vec.iov_len = 1; vec.iov_len = sizeof(*request);
msghdr.msg_name = NULL; msghdr.msg_name = NULL;
msghdr.msg_namelen = 0; 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; request->header.req = req;
if (sendmsg( NtCurrentTeb()->socket, &msghdr, 0 ) == -1) 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); if (errno == EPIPE) SYSDEPS_ExitThread(0);
server_protocol_perror( "sendmsg" ); 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. * Wait for a reply from the server.
*/ */
static void wait_reply(void) static void wait_reply( union generic_request *req )
{ {
int ret; int ret;
char dummy[1];
for (;;) 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) break;
if (ret > 0) server_protocol_error( "partial read %d\n", ret );
if (errno == EINTR) continue; if (errno == EINTR) continue;
if (errno == EPIPE) break; if (errno == EPIPE) break;
server_protocol_perror("read"); server_protocol_perror("read");
@ -240,7 +241,7 @@ unsigned int wine_server_call( enum request req )
{ {
union generic_request *req_ptr = NtCurrentTeb()->buffer; union generic_request *req_ptr = NtCurrentTeb()->buffer;
send_request( req, req_ptr ); send_request( req, req_ptr );
wait_reply(); wait_reply( req_ptr );
return req_ptr->header.error; 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; union generic_request *req_ptr = NtCurrentTeb()->buffer;
send_request_fd( req, req_ptr, fd_out ); send_request_fd( req, req_ptr, fd_out );
wait_reply(); wait_reply( req_ptr );
if ((res = req_ptr->header.error)) SetLastError( RtlNtStatusToDosError(res) ); if ((res = req_ptr->header.error)) SetLastError( RtlNtStatusToDosError(res) );
return res; /* error code */ 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" ); 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 */ 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 ); fd = wine_server_recv_fd( 0, 0 );
if (fd == -1) server_protocol_error( "no fd received for thread buffer\n" ); 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" ); if (teb->buffer == (void*)-1) server_protocol_perror( "mmap" );
teb->buffer_info = (struct server_buffer_info *)((char *)teb->buffer + size) - 1; teb->buffer_info = (struct server_buffer_info *)((char *)teb->buffer + size) - 1;
wait_reply();
req = (struct get_thread_buffer_request *)teb->buffer; req = (struct get_thread_buffer_request *)teb->buffer;
wait_reply( (union generic_request *)req );
teb->pid = req->pid; teb->pid = req->pid;
teb->tid = req->tid; teb->tid = req->tid;
if (req->version != SERVER_PROTOCOL_VERSION) if (req->version != SERVER_PROTOCOL_VERSION)
server_protocol_error( "version mismatch %d/%d.\n" server_protocol_error( "version mismatch %d/%d.\n"
"Your %s binary was not upgraded correctly,\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,
(req->version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); (req->version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
if (req->boot) boot_thread_id = teb->tid; if (req->boot) boot_thread_id = teb->tid;

View file

@ -5,10 +5,11 @@
*/ */
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <signal.h> #include <signal.h>
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
#include "heap.h"
#include "file.h" /* for DOSFS_UnixTimeToFileTime */ #include "file.h" /* for DOSFS_UnixTimeToFileTime */
#include "thread.h" #include "thread.h"
#include "winerror.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 * call_apcs
* *
@ -166,22 +190,27 @@ DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
if (alertable) req->flags |= SELECT_ALERTABLE; if (alertable) req->flags |= SELECT_ALERTABLE;
if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT; if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT;
server_call( REQ_SELECT ); ret = server_call_noerr( REQ_SELECT );
ret = req->signaled;
} }
SERVER_END_REQ; SERVER_END_REQ;
if (ret == STATUS_PENDING) ret = wait_reply();
if (ret != STATUS_USER_APC) break; if (ret != STATUS_USER_APC) break;
call_apcs( alertable ); call_apcs( alertable );
if (alertable) break; if (alertable) break;
} }
if (HIWORD(ret)) /* is it an error code? */
{
SetLastError( RtlNtStatusToDosError(ret) );
ret = WAIT_FAILED;
}
return ret; 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; 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, DWORD WINAPI WaitForMultipleObjects16( DWORD count, const HANDLE *handles,
BOOL wait_all, DWORD timeout ) BOOL wait_all, DWORD timeout )
{ {
DWORD retval, mutex_count; DWORD retval, mutex_count;
ReleaseThunkLock( &mutex_count ); ReleaseThunkLock( &mutex_count );
retval = WaitForMultipleObjects( count, handles, wait_all, timeout ); retval = WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
RestoreThunkLock( mutex_count ); RestoreThunkLock( mutex_count );
return retval; return retval;
} }
/*********************************************************************** /***********************************************************************
* WIN16_WaitForMultipleObjectsEx (KERNEL.495) * WaitForMultipleObjectsEx16 (KERNEL.495)
*/ */
DWORD WINAPI WIN16_WaitForMultipleObjectsEx( DWORD count, DWORD WINAPI WaitForMultipleObjectsEx16( DWORD count, const HANDLE *handles,
const HANDLE *handles, BOOL wait_all, DWORD timeout, BOOL alertable )
BOOL wait_all, DWORD timeout,
BOOL alertable )
{ {
DWORD retval, mutex_count; DWORD retval, mutex_count;
@ -220,4 +247,3 @@ DWORD WINAPI WIN16_WaitForMultipleObjectsEx( DWORD count,
RestoreThunkLock( mutex_count ); RestoreThunkLock( mutex_count );
return retval; return retval;
} }

View file

@ -93,6 +93,7 @@ static BOOL THREAD_InitTEB( TEB *teb )
teb->socket = -1; teb->socket = -1;
teb->request_fd = -1; teb->request_fd = -1;
teb->reply_fd = -1; teb->reply_fd = -1;
teb->wait_fd = -1;
teb->stack_top = (void *)~0UL; teb->stack_top = (void *)~0UL;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
teb->StaticUnicodeString.Buffer = (PWSTR)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 ); if (teb->socket != -1) close( teb->socket );
close( teb->request_fd ); close( teb->request_fd );
close( teb->reply_fd ); close( teb->reply_fd );
close( teb->wait_fd );
if (teb->stack_sel) FreeSelector16( teb->stack_sel ); if (teb->stack_sel) FreeSelector16( teb->stack_sel );
FreeSelector16( teb->teb_sel ); FreeSelector16( teb->teb_sel );
if (teb->buffer) munmap( (void *)teb->buffer, if (teb->buffer) munmap( (void *)teb->buffer,

View file

@ -129,6 +129,20 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
kill_thread( thread, 1 ); 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 */ /* die on a fatal error */
void fatal_error( const char *err, ... ) void fatal_error( const char *err, ... )
{ {
@ -155,20 +169,24 @@ void fatal_perror( const char *err, ... )
} }
/* call a request handler */ /* 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; current = thread;
clear_error(); clear_error();
req = ((struct request_header *)current->buffer)->req; if (debug_level) trace_request( thread, request );
if (debug_level) trace_request( req ); if ((unsigned int)request->header.var_offset + request->header.var_size > MAX_REQUEST_LENGTH)
if (req < REQ_NB_REQUESTS)
{ {
req_handlers[req]( current->buffer ); fatal_protocol_error( current, "bad request offset/size %d/%d\n",
if (current && !current->wait) send_reply( current ); 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; current = NULL;
return; return;
} }
@ -176,18 +194,32 @@ static inline void call_req_handler( struct thread *thread )
} }
/* send a reply to a 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 ); int ret;
if (debug_level) trace_reply( thread );
if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT ); 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 */ /* read a message from a client that has something to say */
void read_request( struct thread *thread ) void read_request( struct thread *thread )
{ {
union generic_request req;
int ret; int ret;
char dummy[1];
#ifdef HAVE_MSGHDR_ACCRIGHTS #ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(int); msghdr.msg_accrightslen = sizeof(int);
@ -200,57 +232,39 @@ void read_request( struct thread *thread )
assert( thread->pass_fd == -1 ); assert( thread->pass_fd == -1 );
myiovec.iov_base = dummy; myiovec.iov_base = &req;
myiovec.iov_len = 1; myiovec.iov_len = sizeof(req);
ret = recvmsg( thread->obj.fd, &msghdr, 0 ); ret = recvmsg( thread->obj.fd, &msghdr, 0 );
#ifndef HAVE_MSGHDR_ACCRIGHTS #ifndef HAVE_MSGHDR_ACCRIGHTS
thread->pass_fd = cmsg.fd; thread->pass_fd = cmsg.fd;
#endif #endif
if (ret > 0) if (ret == sizeof(req))
{ {
call_req_handler( thread ); call_req_handler( thread, &req );
thread->pass_fd = -1; thread->pass_fd = -1;
return; return;
} }
if (!ret) /* closed pipe */ if (!ret) /* closed pipe */
{
kill_thread( thread, 0 ); kill_thread( thread, 0 );
return; else if (ret > 0)
} fatal_protocol_error( thread, "partial recvmsg %d\n", ret );
perror("recvmsg"); else
thread->exit_code = 1; fatal_protocol_perror( thread, "recvmsg" );
kill_thread( thread, 1 );
} }
/* send a message to a client that is ready to receive something */ /* send the wakeup signal to a thread */
int write_request( struct thread *thread ) int send_thread_wakeup( struct thread *thread, int signaled )
{ {
int ret; int ret = write( thread->wait_fd, &signaled, sizeof(signaled) );
struct request_header *header = thread->buffer; if (ret == sizeof(signaled)) return 0;
if (ret >= 0)
header->error = thread->error; fatal_protocol_error( thread, "partial wakeup write %d\n", ret );
else if (errno == EPIPE)
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)
{
kill_thread( thread, 0 ); /* normal death */ kill_thread( thread, 0 ); /* normal death */
}
else else
{ fatal_protocol_perror( thread, "write" );
perror("sendmsg");
thread->exit_code = 1;
kill_thread( thread, 1 );
}
return -1; return -1;
} }
@ -283,9 +297,7 @@ int send_client_fd( struct thread *thread, int fd, handle_t handle )
} }
else else
{ {
perror("sendmsg"); fatal_protocol_perror( thread, "sendmsg" );
thread->exit_code = 1;
kill_thread( thread, 1 );
} }
return -1; return -1;
} }
@ -349,23 +361,20 @@ static void request_socket_poll_event( struct object *obj, int event )
else if (event & POLLIN) else if (event & POLLIN)
{ {
struct thread *thread = sock->thread; struct thread *thread = sock->thread;
union generic_request req;
int ret; int ret;
char dummy[1];
ret = read( sock->obj.fd, &dummy, 1 ); if ((ret = read( sock->obj.fd, &req, sizeof(req) )) == sizeof(req))
if (ret > 0)
{ {
call_req_handler( thread ); call_req_handler( thread, &req );
return; return;
} }
if (!ret) /* closed pipe */ if (!ret) /* closed pipe */
{
kill_thread( thread, 0 ); kill_thread( thread, 0 );
return; else if (ret > 0)
} fatal_protocol_error( thread, "partial read %d\n", ret );
perror("read"); else
thread->exit_code = 1; fatal_protocol_perror( thread, "read" );
kill_thread( thread, 1 );
} }
} }
@ -384,6 +393,7 @@ struct object *create_request_socket( struct thread *thread )
sock->thread = thread; sock->thread = thread;
send_client_fd( thread, fd[1], 0 ); send_client_fd( thread, fd[1], 0 );
close( fd[1] ); close( fd[1] );
fcntl( fd[0], F_SETFL, O_NONBLOCK );
set_select_events( &sock->obj, POLLIN ); set_select_events( &sock->obj, POLLIN );
return &sock->obj; return &sock->obj;
} }

View file

@ -32,22 +32,16 @@ extern void fatal_error( const char *err, ... ) WINE_NORETURN;
extern void fatal_perror( const char *err, ... ) WINE_NORETURN; extern void fatal_perror( const char *err, ... ) WINE_NORETURN;
extern const char *get_config_dir(void); extern const char *get_config_dir(void);
extern void read_request( struct thread *thread ); 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 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 open_master_socket(void);
extern void close_master_socket(void); extern void close_master_socket(void);
extern void lock_master_socket( int locked ); extern void lock_master_socket( int locked );
extern struct object *create_request_socket( struct thread *thread ); extern struct object *create_request_socket( struct thread *thread );
extern void trace_request( enum request req ); extern void trace_request( struct thread *thread, const union generic_request *request );
extern void trace_reply( struct thread *thread ); extern void trace_reply( struct thread *thread, const union generic_request *request );
/* get the request buffer */
static inline void *get_req_ptr( struct thread *thread )
{
return thread->buffer;
}
/* get the request vararg data */ /* get the request vararg data */
inline static void *get_req_data( const void *req ) inline static void *get_req_data( const void *req )

View file

@ -40,7 +40,6 @@ struct thread_wait
int flags; int flags;
struct timeval timeout; struct timeval timeout;
struct timeout_user *user; struct timeout_user *user;
sleep_reply reply; /* function to build the reply */
struct wait_queue_entry queues[1]; struct wait_queue_entry queues[1];
}; };
@ -88,14 +87,16 @@ static struct thread *booting_thread;
/* allocate the buffer for the communication with the client */ /* allocate the buffer for the communication with the client */
static int alloc_client_buffer( struct thread *thread ) static int alloc_client_buffer( struct thread *thread )
{ {
struct get_thread_buffer_request *req; union generic_request *req;
int fd, fd_pipe[2]; int fd = -1, fd_pipe[2], wait_pipe[2];
wait_pipe[0] = wait_pipe[1] = -1;
if (pipe( fd_pipe ) == -1) if (pipe( fd_pipe ) == -1)
{ {
file_set_error(); file_set_error();
return 0; return 0;
} }
if (pipe( wait_pipe ) == -1) goto error;
if ((fd = create_anonymous_file()) == -1) goto error; if ((fd = create_anonymous_file()) == -1) goto error;
if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error; if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error;
if ((thread->buffer = mmap( 0, MAX_REQUEST_LENGTH, PROT_READ | PROT_WRITE, 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; thread->buffer_info = (struct server_buffer_info *)((char *)thread->buffer + MAX_REQUEST_LENGTH) - 1;
if (!(thread->request_fd = create_request_socket( thread ))) goto error; if (!(thread->request_fd = create_request_socket( thread ))) goto error;
thread->reply_fd = fd_pipe[1]; 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 */ /* build the first request into the buffer and send it */
req = thread->buffer; req = thread->buffer;
req->pid = get_process_id( thread->process ); req->get_thread_buffer.pid = get_process_id( thread->process );
req->tid = get_thread_id( thread ); req->get_thread_buffer.tid = get_thread_id( thread );
req->boot = (thread == booting_thread); req->get_thread_buffer.boot = (thread == booting_thread);
req->version = SERVER_PROTOCOL_VERSION; req->get_thread_buffer.version = SERVER_PROTOCOL_VERSION;
/* add it here since send_client_fd may call kill_thread */ /* add it here since send_client_fd may call kill_thread */
add_process_thread( thread->process, thread ); add_process_thread( thread->process, thread );
send_client_fd( thread, fd_pipe[0], 0 ); send_client_fd( thread, fd_pipe[0], 0 );
send_client_fd( thread, wait_pipe[0], 0 );
send_client_fd( thread, fd, 0 ); send_client_fd( thread, fd, 0 );
send_reply( thread ); send_reply( thread, req );
close( fd_pipe[0] ); close( fd_pipe[0] );
close( wait_pipe[0] );
close( fd ); close( fd );
return 1; return 1;
error: error:
@ -125,6 +135,8 @@ static int alloc_client_buffer( struct thread *thread )
if (fd != -1) close( fd ); if (fd != -1) close( fd );
close( fd_pipe[0] ); close( fd_pipe[0] );
close( fd_pipe[1] ); close( fd_pipe[1] );
if (wait_pipe[0] != -1) close( wait_pipe[0] );
if (wait_pipe[1] != -1) close( wait_pipe[1] );
return 0; return 0;
} }
@ -155,6 +167,7 @@ struct thread *create_thread( int fd, struct process *process )
thread->pass_fd = -1; thread->pass_fd = -1;
thread->request_fd = NULL; thread->request_fd = NULL;
thread->reply_fd = -1; thread->reply_fd = -1;
thread->wait_fd = -1;
thread->state = RUNNING; thread->state = RUNNING;
thread->attached = 0; thread->attached = 0;
thread->exit_code = 0; thread->exit_code = 0;
@ -194,11 +207,7 @@ void thread_poll_event( struct object *obj, int event )
assert( obj->ops == &thread_ops ); assert( obj->ops == &thread_ops );
if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 ); if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
else else if (event & POLLIN) read_request( thread );
{
if (event & POLLOUT) write_request( thread );
if (event & POLLIN) read_request( thread );
}
} }
/* destroy a thread when its refcount is 0 */ /* 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->queue) release_object( thread->queue );
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH ); if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
if (thread->reply_fd != -1) close( thread->reply_fd ); 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->pass_fd != -1) close( thread->pass_fd );
if (thread->request_fd) release_object( thread->request_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 */ /* build the thread wait structure */
static int wait_on( int count, struct object *objects[], int flags, static int wait_on( int count, struct object *objects[], int flags, int sec, int usec )
int sec, int usec, sleep_reply func )
{ {
struct thread_wait *wait; struct thread_wait *wait;
struct wait_queue_entry *entry; struct wait_queue_entry *entry;
@ -367,7 +376,6 @@ static int wait_on( int count, struct object *objects[], int flags,
wait->count = count; wait->count = count;
wait->flags = flags; wait->flags = flags;
wait->user = NULL; wait->user = NULL;
wait->reply = func;
if (flags & SELECT_TIMEOUT) if (flags & SELECT_TIMEOUT)
{ {
wait->timeout.tv_sec = sec; 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 */ /* 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; int i, signaled;
struct thread_wait *wait = thread->wait; struct thread_wait *wait = thread->wait;
struct wait_queue_entry *entry = wait->queues; struct wait_queue_entry *entry = wait->queues;
assert( wait ); assert( wait );
*object = NULL;
if (wait->flags & SELECT_ALL) if (wait->flags & SELECT_ALL)
{ {
int not_ok = 0; 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; if (!entry->obj->ops->signaled( entry->obj, thread )) continue;
/* Wait satisfied: tell it to the object */ /* Wait satisfied: tell it to the object */
signaled = i; signaled = i;
*object = entry->obj;
if (entry->obj->ops->satisfied( entry->obj, thread )) if (entry->obj->ops->satisfied( entry->obj, thread ))
signaled = i + STATUS_ABANDONED_WAIT_0; signaled = i + STATUS_ABANDONED_WAIT_0;
return signaled; return signaled;
@ -438,23 +444,17 @@ static int check_wait( struct thread *thread, struct object **object )
return -1; 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 */ /* attempt to wake up a thread */
/* return 1 if OK, 0 if the wait condition is still not satisfied */ /* return 1 if OK, 0 if the wait condition is still not satisfied */
static int wake_thread( struct thread *thread ) static int wake_thread( struct thread *thread )
{ {
int signaled; int signaled;
struct object *object; if ((signaled = check_wait( thread )) == -1) return 0;
if ((signaled = check_wait( thread, &object )) == -1) return 0;
thread->error = 0; if (debug_level) fprintf( stderr, "%08x: *wakeup* object=%d\n",
thread->wait->reply( thread, object, signaled ); (unsigned int)thread, signaled );
end_wait( thread ); end_wait( thread );
send_thread_wakeup( thread, signaled );
return 1; return 1;
} }
@ -462,21 +462,45 @@ static int wake_thread( struct thread *thread )
static void thread_timeout( void *ptr ) static void thread_timeout( void *ptr )
{ {
struct thread *thread = ptr; struct thread *thread = ptr;
if (debug_level) fprintf( stderr, "%08x: *timeout*\n", (unsigned int)thread ); if (debug_level) fprintf( stderr, "%08x: *timeout*\n", (unsigned int)thread );
assert( thread->wait ); assert( thread->wait );
thread->error = 0;
thread->wait->user = NULL; thread->wait->user = NULL;
thread->wait->reply( thread, NULL, STATUS_TIMEOUT );
end_wait( thread ); end_wait( thread );
send_reply( thread ); send_thread_wakeup( thread, STATUS_TIMEOUT );
} }
/* sleep on a list of objects */ /* select on a list of handles */
int sleep_on( int count, struct object *objects[], int flags, int sec, int usec, sleep_reply func ) 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 ); 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 */ /* now we need to wait */
if (flags & SELECT_TIMEOUT) 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 ))) thread_timeout, current )))
{ {
end_wait( current ); end_wait( current );
return 0; goto done;
} }
} }
return 1; set_error( STATUS_PENDING );
}
/* select on a list of handles */ done:
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 );
while (--i >= 0) release_object( objects[i] ); while (--i >= 0) release_object( objects[i] );
return ret;
} }
/* attempt to wake threads sleeping on the object wait queue */ /* 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; entry = entry->next;
if (wake_thread( thread )) if (wake_thread( thread ))
{ {
send_reply( thread );
if (max && !--max) break; 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 */ if (!apc->prev) /* first one */
{ {
queue->head = apc; queue->head = apc;
if (thread->wait && wake_thread( thread )) send_reply( thread ); if (thread->wait) wake_thread( thread );
} }
return 1; return 1;
} }
@ -648,9 +652,11 @@ void kill_thread( struct thread *thread, int violent_death )
remove_select_user( &thread->obj ); remove_select_user( &thread->obj );
release_object( thread->request_fd ); release_object( thread->request_fd );
close( thread->reply_fd ); close( thread->reply_fd );
close( thread->wait_fd );
munmap( thread->buffer, MAX_REQUEST_LENGTH ); munmap( thread->buffer, MAX_REQUEST_LENGTH );
thread->request_fd = NULL; thread->request_fd = NULL;
thread->reply_fd = -1; thread->reply_fd = -1;
thread->wait_fd = -1;
thread->buffer = (void *)-1; thread->buffer = (void *)-1;
release_object( thread ); release_object( thread );
} }
@ -819,8 +825,7 @@ DECL_HANDLER(resume_thread)
DECL_HANDLER(select) DECL_HANDLER(select)
{ {
int count = get_req_data_size(req) / sizeof(int); int count = get_req_data_size(req) / sizeof(int);
if (!select_on( count, get_req_data(req), req->flags, req->sec, req->usec )) select_on( count, get_req_data(req), req->flags, req->sec, req->usec );
req->signaled = -1;
} }
/* queue an APC for a thread */ /* queue an APC for a thread */

View file

@ -55,7 +55,8 @@ struct thread
unsigned int error; /* current error code */ unsigned int error; /* current error code */
struct object *request_fd; /* fd for receiving client requests */ struct object *request_fd; /* fd for receiving client requests */
int pass_fd; /* fd to pass to the client */ 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 */ enum run_state state; /* running state */
int attached; /* is thread attached with ptrace? */ int attached; /* is thread attached with ptrace? */
int exit_code; /* thread exit code */ int exit_code; /* thread exit code */
@ -77,9 +78,6 @@ struct thread_snapshot
int priority; /* priority class */ 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; extern struct thread *current;
/* thread functions */ /* 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 remove_queue( struct object *obj, struct wait_queue_entry *entry );
extern void kill_thread( struct thread *thread, int violent_death ); extern void kill_thread( struct thread *thread, int violent_death );
extern void wake_up( struct object *obj, int max ); 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, extern int thread_queue_apc( struct thread *thread, struct object *owner, void *func,
enum apc_type type, int system, int nb_args, ... ); enum apc_type type, int system, int nb_args, ... );
extern void thread_cancel_apc( struct thread *thread, struct object *owner, int system ); extern void thread_cancel_apc( struct thread *thread, struct object *owner, int system );

View file

@ -550,11 +550,6 @@ static void dump_select_request( const struct select_request *req )
cur_pos += dump_varargs_handles( 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 ) static void dump_create_event_request( const struct create_event_request *req )
{ {
fprintf( stderr, " manual_reset=%d,", req->manual_reset ); 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_set_handle_info_reply,
(dump_func)dump_dup_handle_reply, (dump_func)dump_dup_handle_reply,
(dump_func)dump_open_process_reply, (dump_func)dump_open_process_reply,
(dump_func)dump_select_reply, (dump_func)0,
(dump_func)dump_create_event_reply, (dump_func)dump_create_event_reply,
(dump_func)0, (dump_func)0,
(dump_func)dump_open_event_reply, (dump_func)dump_open_event_reply,
@ -1827,33 +1822,90 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
/* ### make_requests end ### */ /* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */ /* 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; cur_pos = 0;
current->last_req = req; current->last_req = req;
if (req < REQ_NB_REQUESTS) 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; cur_pos = 0;
req_dumpers[req]( current->buffer ); req_dumpers[req]( request );
} }
else else
fprintf( stderr, "%08x: %d(", (unsigned int)current, req ); fprintf( stderr, "%08x: %d(", (unsigned int)thread, req );
if (current->pass_fd != -1) fprintf( stderr, " ) fd=%d\n", current->pass_fd ); if (thread->pass_fd != -1) fprintf( stderr, " ) fd=%d\n", thread->pass_fd );
else fprintf( stderr, " )\n" ); 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", fprintf( stderr, "%08x: %s() = %s",
(unsigned int)thread, req_names[thread->last_req], thread->error ); (unsigned int)thread, req_names[thread->last_req], get_status_name(thread->error) );
if (reply_dumpers[thread->last_req]) if (reply_dumpers[thread->last_req])
{ {
fprintf( stderr, " {" ); fprintf( stderr, " {" );
cur_pos = 0; cur_pos = 0;
reply_dumpers[thread->last_req]( thread->buffer ); reply_dumpers[thread->last_req]( request );
fprintf( stderr, " }" ); fprintf( stderr, " }" );
} }
if (thread->pass_fd != -1) fprintf( stderr, " fd=%d\n", thread->pass_fd ); fputc( '\n', stderr );
else fprintf( stderr, "\n" );
} }