mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-03 01:51:48 +00:00
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:
parent
e187b3ff46
commit
d90e964cee
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
130
server/request.c
130
server/request.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
131
server/thread.c
131
server/thread.c
|
@ -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 */
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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" );
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue