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.
oldstable
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
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

View File

@ -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 */

View File

@ -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 */

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 )
{
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;

View File

@ -5,10 +5,11 @@
*/
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#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;
}

View File

@ -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,

View File

@ -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;
}

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 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 )

View File

@ -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 */

View File

@ -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 );

View File

@ -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 );
}