Create the server pipes on the client side and transfer them to the

server on thread creation.
Use a single per-process socket instead of one per thread for
transferring file handles between client and server.
This commit is contained in:
Alexandre Julliard 2001-03-01 22:13:49 +00:00
parent afa36ce1f1
commit 8859d77279
14 changed files with 374 additions and 374 deletions

View File

@ -208,17 +208,27 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access )
int FILE_GetUnixHandle( HANDLE handle, DWORD access )
{
int ret, fd = -1;
SERVER_START_REQ( get_handle_fd )
do
{
req->handle = handle;
req->access = access;
if (!(ret = SERVER_CALL_ERR())) fd = req->fd;
}
SERVER_END_REQ;
if (!ret)
SERVER_START_REQ( get_handle_fd )
{
req->handle = handle;
req->access = access;
if (!(ret = SERVER_CALL_ERR())) fd = req->fd;
}
SERVER_END_REQ;
if (ret) return -1;
if (fd == -1) /* it wasn't in the cache, get it from the server */
fd = wine_server_recv_fd( handle );
} while (fd == -2); /* -2 means race condition, so restart from scratch */
if (fd != -1)
{
if (fd == -1) return wine_server_recv_fd( handle, 1 );
fd = dup(fd);
if ((fd = dup(fd)) == -1)
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
}
return fd;
}

View File

@ -163,6 +163,7 @@ struct new_thread_request
REQUEST_HEADER; /* request header */
IN int suspend; /* new thread should be suspended on creation */
IN int inherit; /* inherit flag */
IN int request_fd; /* fd for request pipe */
OUT void* tid; /* thread id */
OUT handle_t handle; /* thread handle (in the current process) */
};
@ -214,15 +215,8 @@ struct init_thread_request
IN int unix_pid; /* Unix pid of new thread */
IN void* teb; /* TEB of new thread (in thread address space) */
IN void* entry; /* thread entry point (in thread address space) */
};
/* Retrieve the thread buffer file descriptor */
/* The reply to this request is the first thing a newly */
/* created thread gets (without having to request it) */
struct get_thread_buffer_request
{
REQUEST_HEADER; /* request header */
IN int reply_fd; /* fd for reply pipe */
IN int wait_fd; /* fd for blocking calls pipe */
OUT void* pid; /* process id of the new thread's process */
OUT void* tid; /* thread id of the new thread */
OUT int boot; /* is this the boot thread? */
@ -230,6 +224,16 @@ struct get_thread_buffer_request
};
/* Set the shared buffer for a thread */
struct set_thread_buffer_request
{
REQUEST_HEADER;
IN int fd; /* fd to mmap as shared buffer */
OUT unsigned int offset; /* offset of buffer in file */
OUT unsigned int size; /* size of buffer */
};
/* Terminate a process */
struct terminate_process_request
{
@ -1379,7 +1383,7 @@ enum request
REQ_init_process,
REQ_init_process_done,
REQ_init_thread,
REQ_get_thread_buffer,
REQ_set_thread_buffer,
REQ_terminate_process,
REQ_terminate_thread,
REQ_get_process_info,
@ -1495,7 +1499,7 @@ union generic_request
struct init_process_request init_process;
struct init_process_done_request init_process_done;
struct init_thread_request init_thread;
struct get_thread_buffer_request get_thread_buffer;
struct set_thread_buffer_request set_thread_buffer;
struct terminate_process_request terminate_process;
struct terminate_thread_request terminate_thread;
struct get_process_info_request get_process_info;
@ -1599,7 +1603,7 @@ union generic_request
struct async_result_request async_result;
};
#define SERVER_PROTOCOL_VERSION 40
#define SERVER_PROTOCOL_VERSION 41
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */
@ -1622,7 +1626,7 @@ extern void server_protocol_error( const char *err, ... ) WINE_NORETURN;
extern void server_protocol_perror( const char *err ) WINE_NORETURN;
extern void wine_server_alloc_req( union generic_request *req, size_t size );
extern void wine_server_send_fd( int fd );
extern int wine_server_recv_fd( int handle, int cache );
extern int wine_server_recv_fd( handle_t handle );
extern const char *get_config_dir(void);
/* do a server call and set the last error code */
@ -1694,10 +1698,10 @@ struct __server_exception_frame
#define SERVER_CALL_ERR() (__server_call_err( &__req, sizeof(*req) ))
extern int CLIENT_InitServer(void);
extern int CLIENT_BootDone( int debug_level );
extern void CLIENT_InitServer(void);
extern void CLIENT_InitThread(void);
extern void CLIENT_BootDone( int debug_level );
extern int CLIENT_IsBootThread(void);
extern int CLIENT_InitThread(void);
#endif /* __WINE_SERVER__ */
#endif /* __WINE_SERVER_H */

View File

@ -92,19 +92,18 @@ typedef struct _TEB
/* The following are Wine-specific fields (NT: GDI stuff) */
DWORD cleanup; /* --3 1fc Cleanup service handle */
int socket; /* --3 200 Socket for server communication */
void *buffer; /* --3 204 Buffer shared with server */
unsigned int buffer_pos; /* --3 208 Buffer current position */
unsigned int buffer_size; /* --3 20c Buffer size */
int request_fd; /* --3 210 fd for sending server requests */
int reply_fd; /* --3 214 fd for receiving server replies */
int wait_fd; /* --3 218 fd for sleeping server requests */
void *debug_info; /* --3 21c Info for debugstr functions */
void *pthread_data; /* --3 220 Data for pthread emulation */
void *buffer; /* --3 200 Buffer shared with server */
unsigned int buffer_pos; /* --3 204 Buffer current position */
unsigned int buffer_size; /* --3 208 Buffer size */
int request_fd; /* --3 20c fd for sending server requests */
int reply_fd; /* --3 210 fd for receiving server replies */
int wait_fd; /* --3 214 fd for sleeping server requests */
void *debug_info; /* --3 218 Info for debugstr functions */
void *pthread_data; /* --3 21c Data for pthread emulation */
/* here is plenty space for wine specific fields (don't forget to change pad6!!) */
/* the following are nt specific fields */
DWORD pad6[629]; /* --n 224 */
DWORD pad6[630]; /* --n 220 */
UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */
USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */
DWORD pad7; /* --n e0c */

View File

@ -93,7 +93,7 @@ void server_protocol_error( const char *err, ... )
va_list args;
va_start( args, err );
fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid );
vfprintf( stderr, err, args );
va_end( args );
SYSDEPS_ExitThread(1);
@ -105,7 +105,7 @@ void server_protocol_error( const char *err, ... )
*/
void server_protocol_perror( const char *err )
{
fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
fprintf( stderr, "wine client error:%p: ", NtCurrentTeb()->tid );
perror( err );
SYSDEPS_ExitThread(1);
}
@ -252,49 +252,14 @@ void wine_server_send_fd( int fd )
/***********************************************************************
* set_handle_fd
*
* Store the fd for a given handle in the server
*/
static int set_handle_fd( int handle, int fd )
{
SERVER_START_REQ( set_handle_info )
{
req->handle = handle;
req->flags = 0;
req->mask = 0;
req->fd = fd;
if (!SERVER_CALL())
{
if (req->cur_fd != fd)
{
/* someone was here before us */
close( fd );
fd = req->cur_fd;
}
else fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
}
else
{
close( fd );
fd = -1;
}
}
SERVER_END_REQ;
return fd;
}
/***********************************************************************
* wine_server_recv_fd
* receive_fd
*
* Receive a file descriptor passed from the server.
* The file descriptor must be closed after use.
*/
int wine_server_recv_fd( int handle, int cache )
static int receive_fd( handle_t *handle )
{
struct iovec vec;
int ret, fd, server_handle;
int ret, fd;
#ifdef HAVE_MSGHDR_ACCRIGHTS
struct msghdr msghdr;
@ -319,24 +284,18 @@ int wine_server_recv_fd( int handle, int cache )
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
vec.iov_base = (void *)&server_handle;
vec.iov_len = sizeof(server_handle);
vec.iov_base = (void *)handle;
vec.iov_len = sizeof(*handle);
for (;;)
{
if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) > 0)
if ((ret = recvmsg( fd_socket, &msghdr, 0 )) > 0)
{
#ifndef HAVE_MSGHDR_ACCRIGHTS
fd = cmsg.fd;
#endif
if (handle != server_handle)
server_protocol_error( "recv_fd: got handle %d, expected %d\n",
server_handle, handle );
if (cache)
{
fd = set_handle_fd( handle, fd );
if (fd != -1) fd = dup(fd);
}
if (fd == -1) server_protocol_error( "no fd received for handle %d\n", *handle );
fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
return fd;
}
if (!ret) break;
@ -349,6 +308,50 @@ int wine_server_recv_fd( int handle, int cache )
}
/***********************************************************************
* wine_server_recv_fd
*
* Receive a file descriptor passed from the server.
* The file descriptor must be closed after use.
* Return -2 if a race condition stole our file descriptor.
*/
int wine_server_recv_fd( handle_t handle )
{
handle_t fd_handle;
int fd = receive_fd( &fd_handle );
/* now store it in the server fd cache for this handle */
SERVER_START_REQ( set_handle_info )
{
req->handle = fd_handle;
req->flags = 0;
req->mask = 0;
req->fd = fd;
if (!SERVER_CALL())
{
if (req->cur_fd != fd)
{
/* someone was here before us */
close( fd );
fd = req->cur_fd;
}
}
else
{
close( fd );
fd = -1;
}
}
SERVER_END_REQ;
if (handle != fd_handle) return -2; /* not the one we expected */
if (fd != -1) fd = dup(fd);
return fd;
}
/***********************************************************************
* get_config_dir
*
@ -520,12 +523,13 @@ static int server_connect( const char *oldcwd, const char *serverdir )
*
* Start the server and create the initial socket pair.
*/
int CLIENT_InitServer(void)
void CLIENT_InitServer(void)
{
int fd, size;
int size;
char hostname[64];
char *oldcwd, *serverdir;
const char *configdir;
handle_t dummy_handle;
/* retrieve the current directory */
for (size = 512; ; size *= 2)
@ -562,8 +566,7 @@ int CLIENT_InitServer(void)
strcat( serverdir, hostname );
/* connect to the server */
fd = server_connect( oldcwd, serverdir );
fd_socket = dup(fd);
fd_socket = server_connect( oldcwd, serverdir );
/* switch back to the starting directory */
if (oldcwd)
@ -579,7 +582,51 @@ int CLIENT_InitServer(void)
sigaddset( &block_set, SIGINT );
sigaddset( &block_set, SIGHUP );
return fd;
/* receive the first thread request fd on the main socket */
NtCurrentTeb()->request_fd = receive_fd( &dummy_handle );
CLIENT_InitThread();
}
/***********************************************************************
* set_request_buffer
*/
inline static void set_request_buffer(void)
{
char *name;
int fd, ret;
unsigned int offset, size;
/* create a temporary file */
do
{
if (!(name = tmpnam(NULL))) server_protocol_perror( "tmpnam" );
fd = open( name, O_CREAT | O_EXCL | O_RDWR, 0600 );
} while ((fd == -1) && (errno == EEXIST));
if (fd == -1) server_protocol_perror( "create" );
unlink( name );
wine_server_send_fd( fd );
SERVER_START_REQ( set_thread_buffer )
{
req->fd = fd;
ret = SERVER_CALL();
offset = req->offset;
size = req->size;
}
SERVER_END_REQ;
if (ret) server_protocol_error( "set_thread_buffer failed with status %x\n", ret );
if ((NtCurrentTeb()->buffer = mmap( 0, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, offset )) == (void*)-1)
server_protocol_perror( "mmap" );
close( fd );
NtCurrentTeb()->buffer_pos = 0;
NtCurrentTeb()->buffer_size = size;
}
@ -588,60 +635,54 @@ int CLIENT_InitServer(void)
*
* Send an init thread request. Return 0 if OK.
*/
int CLIENT_InitThread(void)
void CLIENT_InitThread(void)
{
struct get_thread_buffer_request *req;
TEB *teb = NtCurrentTeb();
int fd, ret;
int version, ret;
int reply_pipe[2], wait_pipe[2];
/* ignore SIGPIPE so that we get a EPIPE error instead */
signal( SIGPIPE, SIG_IGN );
teb->request_fd = wine_server_recv_fd( 0, 0 );
if (teb->request_fd == -1) server_protocol_error( "no request fd passed on first request\n" );
fcntl( teb->request_fd, F_SETFD, 1 ); /* set close on exec flag */
/* create the server->client communication pipes */
if (pipe( reply_pipe ) == -1) server_protocol_perror( "pipe" );
if (pipe( wait_pipe ) == -1) server_protocol_perror( "pipe" );
wine_server_send_fd( reply_pipe[1] );
wine_server_send_fd( wait_pipe[1] );
teb->reply_fd = reply_pipe[0];
teb->wait_fd = wait_pipe[0];
teb->reply_fd = wine_server_recv_fd( 0, 0 );
if (teb->reply_fd == -1) server_protocol_error( "no reply fd passed on first request\n" );
fcntl( teb->reply_fd, F_SETFD, 1 ); /* set close on exec flag */
/* set close on exec flag */
fcntl( teb->reply_fd, F_SETFD, 1 );
fcntl( teb->wait_fd, F_SETFD, 1 );
teb->wait_fd = wine_server_recv_fd( 0, 0 );
if (teb->wait_fd == -1) server_protocol_error( "no wait fd passed on first request\n" );
fcntl( teb->wait_fd, F_SETFD, 1 ); /* set close on exec flag */
SERVER_START_REQ( init_thread )
{
req->unix_pid = getpid();
req->teb = teb;
req->entry = teb->entry_point;
req->reply_fd = reply_pipe[1];
req->wait_fd = wait_pipe[1];
ret = SERVER_CALL();
teb->pid = req->pid;
teb->tid = req->tid;
version = req->version;
if (req->boot) boot_thread_id = teb->tid;
else if (boot_thread_id == teb->tid) boot_thread_id = 0;
close( reply_pipe[1] );
close( wait_pipe[1] );
}
SERVER_END_REQ;
fd = wine_server_recv_fd( 0, 0 );
if (fd == -1) server_protocol_error( "no fd received for thread buffer\n" );
if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) server_protocol_perror( "lseek" );
teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
teb->buffer_pos = 0;
close( fd );
if (teb->buffer == (void*)-1) server_protocol_perror( "mmap" );
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)
if (ret) server_protocol_error( "init_thread failed with status %x\n", ret );
if (version != SERVER_PROTOCOL_VERSION)
server_protocol_error( "version mismatch %d/%d.\n"
"Your %s binary was not upgraded correctly,\n"
"or you have an older one somewhere in your PATH.\n"
"Or maybe the wrong wineserver is still running?\n",
req->version, SERVER_PROTOCOL_VERSION,
(req->version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
if (req->boot) boot_thread_id = teb->tid;
else if (boot_thread_id == teb->tid) boot_thread_id = 0;
SERVER_START_REQ( init_thread )
{
req->unix_pid = getpid();
req->teb = teb;
req->entry = teb->entry_point;
ret = SERVER_CALL();
}
SERVER_END_REQ;
return ret;
version, SERVER_PROTOCOL_VERSION,
(version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
set_request_buffer();
}
@ -650,16 +691,14 @@ int CLIENT_InitThread(void)
*
* Signal that we have finished booting, and set debug level.
*/
int CLIENT_BootDone( int debug_level )
void CLIENT_BootDone( int debug_level )
{
int ret;
SERVER_START_REQ( boot_done )
{
req->debug_level = debug_level;
ret = SERVER_CALL();
SERVER_CALL();
}
SERVER_END_REQ;
return ret;
}

View File

@ -269,8 +269,7 @@ static BOOL process_init( char *argv[] )
current_process.priority = 8; /* Normal */
/* Setup the server connection */
NtCurrentTeb()->socket = CLIENT_InitServer();
if (CLIENT_InitThread()) return FALSE;
CLIENT_InitServer();
/* Retrieve startup info from the server */
SERVER_START_VAR_REQ( init_process, sizeof(main_exe_name)-1 )

View File

@ -95,7 +95,7 @@ int SYSDEPS_SpawnThread( TEB *teb )
const int flags = CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD;
if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top, flags, teb ) < 0)
return -1;
if (!(flags & CLONE_FILES)) close( teb->socket ); /* close the child socket in the parent */
if (!(flags & CLONE_FILES)) close( teb->request_fd ); /* close the child socket in the parent */
return 0;
#endif
@ -118,7 +118,7 @@ int SYSDEPS_SpawnThread( TEB *teb )
"addl $8,%%esp" :
: "r" (sp), "g" (SYS_rfork), "g" (flags)
: "eax", "edx");
if (flags & RFFDG) close( teb->socket ); /* close the child socket in the parent */
if (flags & RFFDG) close( teb->request_fd ); /* close the child socket in the parent */
return 0;
#endif
@ -146,9 +146,9 @@ int SYSDEPS_SpawnThread( TEB *teb )
*/
void SYSDEPS_ExitThread( int status )
{
int socket = NtCurrentTeb()->socket;
NtCurrentTeb()->socket = -1;
close( socket );
int fd = NtCurrentTeb()->request_fd;
NtCurrentTeb()->request_fd = -1;
close( fd );
#ifdef HAVE__LWP_CREATE
_lwp_exit();
#endif

View File

@ -89,7 +89,6 @@ static BOOL THREAD_InitTEB( TEB *teb )
teb->tibflags = TEBF_WIN32;
teb->tls_ptr = teb->tls_array;
teb->exit_code = STILL_ACTIVE;
teb->socket = -1;
teb->request_fd = -1;
teb->reply_fd = -1;
teb->wait_fd = -1;
@ -114,7 +113,6 @@ static void CALLBACK THREAD_FreeTEB( TEB *teb )
/* Free the associated memory */
if (teb->socket != -1) close( teb->socket );
close( teb->request_fd );
close( teb->reply_fd );
close( teb->wait_fd );
@ -285,38 +283,46 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
LPTHREAD_START_ROUTINE start, LPVOID param,
DWORD flags, LPDWORD id )
{
int socket = -1;
HANDLE handle = 0;
TEB *teb;
void *tid = 0;
int request_pipe[2];
if (pipe( request_pipe ) == -1)
{
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
return 0;
}
fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
wine_server_send_fd( request_pipe[0] );
SERVER_START_REQ( new_thread )
{
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
req->request_fd = request_pipe[0];
if (!SERVER_CALL_ERR())
{
handle = req->handle;
tid = req->tid;
socket = wine_server_recv_fd( handle, 0 );
}
close( request_pipe[0] );
}
SERVER_END_REQ;
if (!handle) return 0;
if (!(teb = THREAD_InitStack( NULL, stack )))
if (!handle || !(teb = THREAD_InitStack( NULL, stack )))
{
close( socket );
close( request_pipe[1] );
return 0;
}
teb->process = NtCurrentTeb()->process;
teb->socket = socket;
teb->tid = tid;
teb->request_fd = request_pipe[1];
teb->entry_point = start;
teb->entry_arg = param;
teb->startup = THREAD_Start;
teb->htask16 = GetCurrentTask();
fcntl( socket, F_SETFD, 1 ); /* set close on exec flag */
if (id) *id = (DWORD)tid;
if (SYSDEPS_SpawnThread( teb ) == -1)

View File

@ -487,7 +487,7 @@ DECL_HANDLER(get_handle_fd)
else if (!get_error())
{
if ((fd = obj->ops->get_fd( obj )) != -1)
send_client_fd( current, fd, req->handle );
send_client_fd( current->process, fd, req->handle );
}
release_object( obj );
}

View File

@ -147,6 +147,7 @@ struct thread *create_process( int fd )
{
struct process *process;
struct thread *thread = NULL;
int request_pipe[2];
if (!(process = alloc_object( &process_ops, fd ))) return NULL;
process->next = NULL;
@ -180,7 +181,14 @@ struct thread *create_process( int fd )
if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error;
/* create the main thread */
if (!(thread = create_thread( dup(fd), process ))) goto error;
if (pipe( request_pipe ) == -1)
{
file_set_error();
goto error;
}
send_client_fd( process, request_pipe[1], 0 );
close( request_pipe[1] );
if (!(thread = create_thread( request_pipe[0], process ))) goto error;
set_select_events( &process->obj, POLLIN ); /* start listening to events */
release_object( process );

View File

@ -71,32 +71,6 @@ static const struct object_ops master_socket_ops =
};
struct request_socket
{
struct object obj; /* object header */
struct thread *thread; /* owning thread */
};
static void request_socket_dump( struct object *obj, int verbose );
static void request_socket_poll_event( struct object *obj, int event );
static const struct object_ops request_socket_ops =
{
sizeof(struct request_socket), /* size */
request_socket_dump, /* dump */
no_add_queue, /* add_queue */
NULL, /* remove_queue */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* get_poll_events */
request_socket_poll_event, /* poll_event */
no_get_fd, /* get_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
no_destroy /* destroy */
};
struct thread *current = NULL; /* thread handling the current request */
unsigned int global_error = 0; /* global error code for when no thread is current */
@ -199,6 +173,25 @@ static inline void call_req_handler( struct thread *thread, union generic_reques
fatal_protocol_error( current, "bad request %d\n", req );
}
/* read a request from a thread */
void read_request( struct thread *thread )
{
union generic_request req;
int ret;
if ((ret = read( thread->obj.fd, &req, sizeof(req) )) == sizeof(req))
{
call_req_handler( thread, &req );
return;
}
if (!ret) /* closed pipe */
kill_thread( thread, 0 );
else if (ret > 0)
fatal_protocol_error( thread, "partial read %d\n", ret );
else
fatal_protocol_perror( thread, "read" );
}
/* send a reply to a thread */
void send_reply( struct thread *thread, union generic_request *request )
{
@ -215,7 +208,7 @@ void send_reply( struct thread *thread, union generic_request *request )
else if (errno == EPIPE)
kill_thread( thread, 0 ); /* normal death */
else
fatal_protocol_perror( thread, "sendmsg" );
fatal_protocol_perror( thread, "reply write" );
}
}
@ -244,7 +237,11 @@ int receive_fd( struct process *process )
if (ret == sizeof(data))
{
struct thread *thread = get_thread_from_id( data.tid );
struct thread *thread;
if (data.tid) thread = get_thread_from_id( data.tid );
else thread = (struct thread *)grab_object( process->thread_list );
if (!thread || thread->process != process)
{
if (debug_level)
@ -259,19 +256,16 @@ int receive_fd( struct process *process )
(unsigned int)thread, data.fd, fd );
thread_add_inflight_fd( thread, data.fd, fd );
}
if (thread) release_object( thread );
return 0;
}
if (!ret)
{
set_select_events( &process->obj, -1 ); /* stop waiting on it */
}
else if (ret > 0)
if (ret >= 0)
{
fprintf( stderr, "Protocol error: process %p: partial recvmsg %d for fd\n", process, ret );
kill_process( process, NULL, 1 );
}
else if (ret < 0)
else
{
if (errno != EWOULDBLOCK && errno != EAGAIN)
{
@ -298,12 +292,12 @@ int send_thread_wakeup( struct thread *thread, int signaled )
}
/* send an fd to a client */
int send_client_fd( struct thread *thread, int fd, handle_t handle )
int send_client_fd( struct process *process, int fd, handle_t handle )
{
int ret;
if (debug_level)
fprintf( stderr, "%08x: *fd* %d -> %d\n", (unsigned int)thread, handle, fd );
fprintf( stderr, "%08x: *fd* %d -> %d\n", (unsigned int)current, handle, fd );
#ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(fd);
@ -317,16 +311,20 @@ int send_client_fd( struct thread *thread, int fd, handle_t handle )
myiovec.iov_base = (void *)&handle;
myiovec.iov_len = sizeof(handle);
ret = sendmsg( thread->obj.fd, &msghdr, 0 );
ret = sendmsg( process->obj.fd, &msghdr, 0 );
if (ret > 0) return 0;
if (errno == EPIPE)
if (ret == sizeof(handle)) return 0;
if (ret >= 0)
{
kill_thread( thread, 0 ); /* normal death */
fprintf( stderr, "Protocol error: process %p: partial sendmsg %d\n", process, ret );
kill_process( process, NULL, 1 );
}
else
{
fatal_protocol_perror( thread, "sendmsg" );
fprintf( stderr, "Protocol error: process %p: ", process );
perror( "sendmsg" );
kill_process( process, NULL, 1 );
}
return -1;
}
@ -373,60 +371,6 @@ static void master_socket_destroy( struct object *obj )
socket_cleanup();
}
static void request_socket_dump( struct object *obj, int verbose )
{
struct request_socket *sock = (struct request_socket *)obj;
assert( obj->ops == &request_socket_ops );
fprintf( stderr, "Request socket fd=%d thread=%p\n", sock->obj.fd, sock->thread );
}
/* handle a request socket event */
static void request_socket_poll_event( struct object *obj, int event )
{
struct request_socket *sock = (struct request_socket *)obj;
assert( obj->ops == &request_socket_ops );
if (event & (POLLERR | POLLHUP)) kill_thread( sock->thread, 0 );
else if (event & POLLIN)
{
struct thread *thread = sock->thread;
union generic_request req;
int ret;
if ((ret = read( sock->obj.fd, &req, sizeof(req) )) == sizeof(req))
{
call_req_handler( thread, &req );
return;
}
if (!ret) /* closed pipe */
kill_thread( thread, 0 );
else if (ret > 0)
fatal_protocol_error( thread, "partial read %d\n", ret );
else
fatal_protocol_perror( thread, "read" );
}
}
/* create a request socket and send the fd to the client thread */
struct object *create_request_socket( struct thread *thread )
{
struct request_socket *sock;
int fd[2];
if (pipe( fd )) return NULL;
if (!(sock = alloc_object( &request_socket_ops, fd[0] )))
{
close( fd[1] );
return NULL;
}
sock->thread = thread;
send_client_fd( thread, fd[1], 0 );
close( fd[1] );
fcntl( fd[0], F_SETFL, O_NONBLOCK );
set_select_events( &sock->obj, POLLIN );
return &sock->obj;
}
/* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
const char *get_config_dir(void)
{

View File

@ -33,12 +33,12 @@ extern void fatal_perror( const char *err, ... ) WINE_NORETURN;
extern const char *get_config_dir(void);
extern int receive_fd( struct process *process );
extern int send_thread_wakeup( struct thread *thread, int signaled );
extern int send_client_fd( struct thread *thread, int fd, handle_t handle );
extern int send_client_fd( struct process *process, int fd, handle_t handle );
extern void read_request( struct thread *thread );
extern void send_reply( struct thread *thread, union generic_request *request );
extern void open_master_socket(void);
extern void close_master_socket(void);
extern void lock_master_socket( int locked );
extern struct object *create_request_socket( struct thread *thread );
extern void trace_request( struct thread *thread, const union generic_request *request );
extern void trace_reply( struct thread *thread, const union generic_request *request );
@ -71,7 +71,7 @@ DECL_HANDLER(boot_done);
DECL_HANDLER(init_process);
DECL_HANDLER(init_process_done);
DECL_HANDLER(init_thread);
DECL_HANDLER(get_thread_buffer);
DECL_HANDLER(set_thread_buffer);
DECL_HANDLER(terminate_process);
DECL_HANDLER(terminate_thread);
DECL_HANDLER(get_process_info);
@ -186,7 +186,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_init_process,
(req_handler)req_init_process_done,
(req_handler)req_init_thread,
(req_handler)req_get_thread_buffer,
(req_handler)req_set_thread_buffer,
(req_handler)req_terminate_process,
(req_handler)req_terminate_thread,
(req_handler)req_get_process_info,

View File

@ -17,10 +17,6 @@
#include <sys/mman.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#include <sys/uio.h>
#include <unistd.h>
#include <stdarg.h>
@ -84,61 +80,6 @@ static const struct object_ops thread_ops =
static struct thread *first_thread;
static struct thread *booting_thread;
/* allocate the buffer for the communication with the client */
static int alloc_client_buffer( struct thread *thread )
{
union generic_request *req;
int fd = -1, fd_pipe[2], wait_pipe[2];
wait_pipe[0] = wait_pipe[1] = -1;
if (pipe( fd_pipe ) == -1)
{
file_set_error();
return 0;
}
if (pipe( wait_pipe ) == -1) goto error;
if ((fd = create_anonymous_file()) == -1) goto error;
if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error;
if ((thread->buffer = mmap( 0, MAX_REQUEST_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0 )) == (void*)-1) goto error;
if (!(thread->request_fd = create_request_socket( thread ))) goto error;
thread->reply_fd = fd_pipe[1];
thread->wait_fd = wait_pipe[1];
/* make the pipes non-blocking */
fcntl( fd_pipe[1], F_SETFL, O_NONBLOCK );
fcntl( wait_pipe[1], F_SETFL, O_NONBLOCK );
/* build the first request into the buffer and send it */
req = thread->buffer;
req->get_thread_buffer.pid = get_process_id( thread->process );
req->get_thread_buffer.tid = get_thread_id( thread );
req->get_thread_buffer.boot = (thread == booting_thread);
req->get_thread_buffer.version = SERVER_PROTOCOL_VERSION;
/* add it here since send_client_fd may call kill_thread */
add_process_thread( thread->process, thread );
send_client_fd( thread, fd_pipe[0], 0 );
send_client_fd( thread, wait_pipe[0], 0 );
send_client_fd( thread, fd, 0 );
send_reply( thread, req );
close( fd_pipe[0] );
close( wait_pipe[0] );
close( fd );
return 1;
error:
file_set_error();
if (fd != -1) close( fd );
close( fd_pipe[0] );
close( fd_pipe[1] );
if (wait_pipe[0] != -1) close( wait_pipe[0] );
if (wait_pipe[1] != -1) close( wait_pipe[1] );
return 0;
}
/* initialize the structure for a newly allocated thread */
inline static void init_thread_structure( struct thread *thread )
{
@ -170,7 +111,6 @@ inline static void init_thread_structure( struct thread *thread )
thread->affinity = 1;
thread->suspend = 0;
thread->buffer = (void *)-1;
thread->last_req = REQ_get_thread_buffer;
for (i = 0; i < MAX_INFLIGHT_FDS; i++)
thread->inflight[i].server = thread->inflight[i].client = -1;
@ -181,9 +121,6 @@ struct thread *create_thread( int fd, struct process *process )
{
struct thread *thread;
int flags = fcntl( fd, F_GETFL, 0 );
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
init_thread_structure( thread );
@ -200,15 +137,10 @@ struct thread *create_thread( int fd, struct process *process )
if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
first_thread = thread;
#if 0
fcntl( fd, F_SETFL, O_NONBLOCK );
set_select_events( &thread->obj, POLLIN ); /* start listening to events */
#endif
if (!alloc_client_buffer( thread )) goto error;
add_process_thread( thread->process, thread );
return thread;
error:
release_object( thread );
return NULL;
}
/* handle a client event */
@ -218,9 +150,7 @@ static void thread_poll_event( struct object *obj, int event )
assert( obj->ops == &thread_ops );
if (event & (POLLERR | POLLHUP)) kill_thread( thread, 0 );
#if 0
else if (event & POLLIN) read_request( thread );
#endif
}
/* cleanup everything that is no longer needed by a dead thread */
@ -773,8 +703,6 @@ struct thread_snapshot *thread_snap( int *count )
DECL_HANDLER(boot_done)
{
debug_level = max( debug_level, req->debug_level );
/* Make sure last_req is initialized */
current->last_req = REQ_boot_done;
if (current == booting_thread)
{
booting_thread = (struct thread *)~0UL; /* make sure it doesn't match other threads */
@ -786,48 +714,97 @@ DECL_HANDLER(boot_done)
DECL_HANDLER(new_thread)
{
struct thread *thread;
int sock[2];
int request_fd = thread_get_inflight_fd( current, req->request_fd );
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1)
if (request_fd == -1)
{
if ((thread = create_thread( sock[0], current->process )))
{
if (req->suspend) thread->suspend++;
req->tid = thread;
if ((req->handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, req->inherit )))
{
send_client_fd( current, sock[1], req->handle );
close( sock[1] );
/* thread object will be released when the thread gets killed */
return;
}
kill_thread( thread, 1 );
}
close( sock[1] );
set_error( STATUS_INVALID_HANDLE );
return;
}
else file_set_error();
}
/* retrieve the thread buffer file descriptor */
DECL_HANDLER(get_thread_buffer)
{
fatal_protocol_error( current, "get_thread_buffer: should never get called directly\n" );
if ((thread = create_thread( request_fd, current->process )))
{
if (req->suspend) thread->suspend++;
req->tid = thread;
if ((req->handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, req->inherit )))
{
/* thread object will be released when the thread gets killed */
return;
}
kill_thread( thread, 1 );
request_fd = -1;
}
}
/* initialize a new thread */
DECL_HANDLER(init_thread)
{
int reply_fd = thread_get_inflight_fd( current, req->reply_fd );
int wait_fd = thread_get_inflight_fd( current, req->wait_fd );
if (current->unix_pid)
{
fatal_protocol_error( current, "init_thread: already running\n" );
return;
goto error;
}
if (reply_fd == -1)
{
fatal_protocol_error( current, "bad reply fd\n" );
goto error;
}
if (wait_fd == -1)
{
fatal_protocol_error( current, "bad wait fd\n" );
goto error;
}
current->unix_pid = req->unix_pid;
current->teb = req->teb;
current->reply_fd = reply_fd;
current->wait_fd = wait_fd;
if (current->suspend + current->process->suspend > 0) stop_thread( current );
if (current->process->running_threads > 1)
generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, req->entry );
req->pid = get_process_id( current->process );
req->tid = get_thread_id( current );
req->boot = (current == booting_thread);
req->version = SERVER_PROTOCOL_VERSION;
return;
error:
if (reply_fd != -1) close( reply_fd );
if (wait_fd != -1) close( wait_fd );
}
/* set the shared buffer for a thread */
DECL_HANDLER(set_thread_buffer)
{
unsigned int size = MAX_REQUEST_LENGTH;
unsigned int offset = 0;
int fd = thread_get_inflight_fd( current, req->fd );
req->size = size;
req->offset = offset;
if (fd != -1)
{
if (ftruncate( fd, size ) == -1) file_set_error();
else
{
void *buffer = mmap( 0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset );
if (buffer == (void *)-1) file_set_error();
else
{
if (current->buffer != (void *)-1) munmap( current->buffer, size );
current->buffer = buffer;
}
}
close( fd );
}
else set_error( STATUS_INVALID_HANDLE );
}
/* terminate a thread */

View File

@ -75,7 +75,6 @@ struct thread
int affinity; /* affinity mask */
int suspend; /* suspend count */
void *buffer; /* buffer for communication with the client */
enum request last_req; /* last request received (for debugging) */
};
struct thread_snapshot

View File

@ -299,7 +299,8 @@ static void dump_get_new_process_info_reply( const struct get_new_process_info_r
static void dump_new_thread_request( const struct new_thread_request *req )
{
fprintf( stderr, " suspend=%d,", req->suspend );
fprintf( stderr, " inherit=%d", req->inherit );
fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " request_fd=%d", req->request_fd );
}
static void dump_new_thread_reply( const struct new_thread_request *req )
@ -351,14 +352,12 @@ static void dump_init_thread_request( const struct init_thread_request *req )
{
fprintf( stderr, " unix_pid=%d,", req->unix_pid );
fprintf( stderr, " teb=%p,", req->teb );
fprintf( stderr, " entry=%p", req->entry );
fprintf( stderr, " entry=%p,", req->entry );
fprintf( stderr, " reply_fd=%d,", req->reply_fd );
fprintf( stderr, " wait_fd=%d", req->wait_fd );
}
static void dump_get_thread_buffer_request( const struct get_thread_buffer_request *req )
{
}
static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request *req )
static void dump_init_thread_reply( const struct init_thread_request *req )
{
fprintf( stderr, " pid=%p,", req->pid );
fprintf( stderr, " tid=%p,", req->tid );
@ -366,6 +365,17 @@ static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request
fprintf( stderr, " version=%d", req->version );
}
static void dump_set_thread_buffer_request( const struct set_thread_buffer_request *req )
{
fprintf( stderr, " fd=%d", req->fd );
}
static void dump_set_thread_buffer_reply( const struct set_thread_buffer_request *req )
{
fprintf( stderr, " offset=%08x,", req->offset );
fprintf( stderr, " size=%08x", req->size );
}
static void dump_terminate_process_request( const struct terminate_process_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
@ -1492,7 +1502,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_init_process_request,
(dump_func)dump_init_process_done_request,
(dump_func)dump_init_thread_request,
(dump_func)dump_get_thread_buffer_request,
(dump_func)dump_set_thread_buffer_request,
(dump_func)dump_terminate_process_request,
(dump_func)dump_terminate_thread_request,
(dump_func)dump_get_process_info_request,
@ -1603,8 +1613,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0,
(dump_func)dump_init_process_reply,
(dump_func)dump_init_process_done_reply,
(dump_func)0,
(dump_func)dump_get_thread_buffer_reply,
(dump_func)dump_init_thread_reply,
(dump_func)dump_set_thread_buffer_reply,
(dump_func)dump_terminate_process_reply,
(dump_func)dump_terminate_thread_reply,
(dump_func)dump_get_process_info_reply,
@ -1716,7 +1726,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"init_process",
"init_process_done",
"init_thread",
"get_thread_buffer",
"set_thread_buffer",
"terminate_process",
"terminate_thread",
"get_process_info",
@ -1884,7 +1894,6 @@ void trace_request( struct thread *thread, const union generic_request *request
{
enum request req = request->header.req;
cur_pos = 0;
current->last_req = req;
if (req < REQ_NB_REQUESTS)
{
fprintf( stderr, "%08x: %s(", (unsigned int)thread, req_names[req] );
@ -1897,14 +1906,20 @@ void trace_request( struct thread *thread, const union generic_request *request
void trace_reply( struct thread *thread, const union generic_request *request )
{
fprintf( stderr, "%08x: %s() = %s",
(unsigned int)thread, req_names[thread->last_req], get_status_name(thread->error) );
if (reply_dumpers[thread->last_req])
enum request req = request->header.req;
if (req < REQ_NB_REQUESTS)
{
fprintf( stderr, " {" );
cur_pos = 0;
reply_dumpers[thread->last_req]( request );
fprintf( stderr, " }" );
fprintf( stderr, "%08x: %s() = %s",
(unsigned int)thread, req_names[req], get_status_name(thread->error) );
if (reply_dumpers[req])
{
fprintf( stderr, " {" );
cur_pos = 0;
reply_dumpers[req]( request );
fprintf( stderr, " }" );
}
fputc( '\n', stderr );
}
fputc( '\n', stderr );
else fprintf( stderr, "%08x: %d() = %s\n",
(unsigned int)thread, req, get_status_name(thread->error) );
}