Commit 8859d772 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent afa36ce1
...@@ -208,17 +208,27 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access ) ...@@ -208,17 +208,27 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access )
int FILE_GetUnixHandle( HANDLE handle, DWORD access ) int FILE_GetUnixHandle( HANDLE handle, DWORD access )
{ {
int ret, fd = -1; int ret, fd = -1;
SERVER_START_REQ( get_handle_fd )
do
{ {
req->handle = handle; SERVER_START_REQ( get_handle_fd )
req->access = access; {
if (!(ret = SERVER_CALL_ERR())) fd = req->fd; req->handle = handle;
} req->access = access;
SERVER_END_REQ; if (!(ret = SERVER_CALL_ERR())) fd = req->fd;
if (!ret) }
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 ); if ((fd = dup(fd)) == -1)
fd = dup(fd); SetLastError( ERROR_TOO_MANY_OPEN_FILES );
} }
return fd; return fd;
} }
......
...@@ -163,6 +163,7 @@ struct new_thread_request ...@@ -163,6 +163,7 @@ struct new_thread_request
REQUEST_HEADER; /* request header */ REQUEST_HEADER; /* request header */
IN int suspend; /* new thread should be suspended on creation */ IN int suspend; /* new thread should be suspended on creation */
IN int inherit; /* inherit flag */ IN int inherit; /* inherit flag */
IN int request_fd; /* fd for request pipe */
OUT void* tid; /* thread id */ OUT void* tid; /* thread id */
OUT handle_t handle; /* thread handle (in the current process) */ OUT handle_t handle; /* thread handle (in the current process) */
}; };
...@@ -214,15 +215,8 @@ struct init_thread_request ...@@ -214,15 +215,8 @@ struct init_thread_request
IN int unix_pid; /* Unix pid of new thread */ IN int unix_pid; /* Unix pid of new thread */
IN void* teb; /* TEB of new thread (in thread address space) */ IN void* teb; /* TEB of new thread (in thread address space) */
IN void* entry; /* thread entry point (in thread address space) */ IN void* entry; /* thread entry point (in thread address space) */
}; IN int reply_fd; /* fd for reply pipe */
IN int wait_fd; /* fd for blocking calls pipe */
/* 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 */
OUT void* pid; /* process id of the new thread's process */ OUT void* pid; /* process id of the new thread's process */
OUT void* tid; /* thread id of the new thread */ OUT void* tid; /* thread id of the new thread */
OUT int boot; /* is this the boot thread? */ OUT int boot; /* is this the boot thread? */
...@@ -230,6 +224,16 @@ struct get_thread_buffer_request ...@@ -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 */ /* Terminate a process */
struct terminate_process_request struct terminate_process_request
{ {
...@@ -1379,7 +1383,7 @@ enum request ...@@ -1379,7 +1383,7 @@ enum request
REQ_init_process, REQ_init_process,
REQ_init_process_done, REQ_init_process_done,
REQ_init_thread, REQ_init_thread,
REQ_get_thread_buffer, REQ_set_thread_buffer,
REQ_terminate_process, REQ_terminate_process,
REQ_terminate_thread, REQ_terminate_thread,
REQ_get_process_info, REQ_get_process_info,
...@@ -1495,7 +1499,7 @@ union generic_request ...@@ -1495,7 +1499,7 @@ union generic_request
struct init_process_request init_process; struct init_process_request init_process;
struct init_process_done_request init_process_done; struct init_process_done_request init_process_done;
struct init_thread_request init_thread; 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_process_request terminate_process;
struct terminate_thread_request terminate_thread; struct terminate_thread_request terminate_thread;
struct get_process_info_request get_process_info; struct get_process_info_request get_process_info;
...@@ -1599,7 +1603,7 @@ union generic_request ...@@ -1599,7 +1603,7 @@ union generic_request
struct async_result_request async_result; struct async_result_request async_result;
}; };
#define SERVER_PROTOCOL_VERSION 40 #define SERVER_PROTOCOL_VERSION 41
/* ### 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 */
...@@ -1622,7 +1626,7 @@ extern void server_protocol_error( const char *err, ... ) WINE_NORETURN; ...@@ -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 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_alloc_req( union generic_request *req, size_t size );
extern void wine_server_send_fd( int fd ); 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); extern const char *get_config_dir(void);
/* do a server call and set the last error code */ /* do a server call and set the last error code */
...@@ -1694,10 +1698,10 @@ struct __server_exception_frame ...@@ -1694,10 +1698,10 @@ struct __server_exception_frame
#define SERVER_CALL_ERR() (__server_call_err( &__req, sizeof(*req) )) #define SERVER_CALL_ERR() (__server_call_err( &__req, sizeof(*req) ))
extern int CLIENT_InitServer(void); extern void CLIENT_InitServer(void);
extern int CLIENT_BootDone( int debug_level ); extern void CLIENT_InitThread(void);
extern void CLIENT_BootDone( int debug_level );
extern int CLIENT_IsBootThread(void); extern int CLIENT_IsBootThread(void);
extern int CLIENT_InitThread(void);
#endif /* __WINE_SERVER__ */ #endif /* __WINE_SERVER__ */
#endif /* __WINE_SERVER_H */ #endif /* __WINE_SERVER_H */
...@@ -92,19 +92,18 @@ typedef struct _TEB ...@@ -92,19 +92,18 @@ typedef struct _TEB
/* The following are Wine-specific fields (NT: GDI stuff) */ /* The following are Wine-specific fields (NT: GDI stuff) */
DWORD cleanup; /* --3 1fc Cleanup service handle */ DWORD cleanup; /* --3 1fc Cleanup service handle */
int socket; /* --3 200 Socket for server communication */ void *buffer; /* --3 200 Buffer shared with server */
void *buffer; /* --3 204 Buffer shared with server */ unsigned int buffer_pos; /* --3 204 Buffer current position */
unsigned int buffer_pos; /* --3 208 Buffer current position */ unsigned int buffer_size; /* --3 208 Buffer size */
unsigned int buffer_size; /* --3 20c Buffer size */ int request_fd; /* --3 20c fd for sending server requests */
int request_fd; /* --3 210 fd for sending server requests */ int reply_fd; /* --3 210 fd for receiving server replies */
int reply_fd; /* --3 214 fd for receiving server replies */ int wait_fd; /* --3 214 fd for sleeping server requests */
int wait_fd; /* --3 218 fd for sleeping server requests */ void *debug_info; /* --3 218 Info for debugstr functions */
void *debug_info; /* --3 21c Info for debugstr functions */ void *pthread_data; /* --3 21c Data for pthread emulation */
void *pthread_data; /* --3 220 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[629]; /* --n 224 */ 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 */
......
...@@ -269,8 +269,7 @@ static BOOL process_init( char *argv[] ) ...@@ -269,8 +269,7 @@ static BOOL process_init( char *argv[] )
current_process.priority = 8; /* Normal */ current_process.priority = 8; /* Normal */
/* Setup the server connection */ /* Setup the server connection */
NtCurrentTeb()->socket = CLIENT_InitServer(); CLIENT_InitServer();
if (CLIENT_InitThread()) return FALSE;
/* Retrieve startup info from the server */ /* Retrieve startup info from the server */
SERVER_START_VAR_REQ( init_process, sizeof(main_exe_name)-1 ) SERVER_START_VAR_REQ( init_process, sizeof(main_exe_name)-1 )
......
...@@ -95,7 +95,7 @@ int SYSDEPS_SpawnThread( TEB *teb ) ...@@ -95,7 +95,7 @@ int SYSDEPS_SpawnThread( TEB *teb )
const int flags = CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD; const int flags = CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD;
if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top, flags, teb ) < 0) if (clone( (int (*)(void *))SYSDEPS_StartThread, teb->stack_top, flags, teb ) < 0)
return -1; 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; return 0;
#endif #endif
...@@ -118,7 +118,7 @@ int SYSDEPS_SpawnThread( TEB *teb ) ...@@ -118,7 +118,7 @@ int SYSDEPS_SpawnThread( TEB *teb )
"addl $8,%%esp" : "addl $8,%%esp" :
: "r" (sp), "g" (SYS_rfork), "g" (flags) : "r" (sp), "g" (SYS_rfork), "g" (flags)
: "eax", "edx"); : "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; return 0;
#endif #endif
...@@ -146,9 +146,9 @@ int SYSDEPS_SpawnThread( TEB *teb ) ...@@ -146,9 +146,9 @@ int SYSDEPS_SpawnThread( TEB *teb )
*/ */
void SYSDEPS_ExitThread( int status ) void SYSDEPS_ExitThread( int status )
{ {
int socket = NtCurrentTeb()->socket; int fd = NtCurrentTeb()->request_fd;
NtCurrentTeb()->socket = -1; NtCurrentTeb()->request_fd = -1;
close( socket ); close( fd );
#ifdef HAVE__LWP_CREATE #ifdef HAVE__LWP_CREATE
_lwp_exit(); _lwp_exit();
#endif #endif
......
...@@ -89,7 +89,6 @@ static BOOL THREAD_InitTEB( TEB *teb ) ...@@ -89,7 +89,6 @@ static BOOL THREAD_InitTEB( TEB *teb )
teb->tibflags = TEBF_WIN32; teb->tibflags = TEBF_WIN32;
teb->tls_ptr = teb->tls_array; teb->tls_ptr = teb->tls_array;
teb->exit_code = STILL_ACTIVE; teb->exit_code = STILL_ACTIVE;
teb->socket = -1;
teb->request_fd = -1; teb->request_fd = -1;
teb->reply_fd = -1; teb->reply_fd = -1;
teb->wait_fd = -1; teb->wait_fd = -1;
...@@ -114,7 +113,6 @@ static void CALLBACK THREAD_FreeTEB( TEB *teb ) ...@@ -114,7 +113,6 @@ static void CALLBACK THREAD_FreeTEB( TEB *teb )
/* Free the associated memory */ /* Free the associated memory */
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 ); close( teb->wait_fd );
...@@ -285,38 +283,46 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack, ...@@ -285,38 +283,46 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
LPTHREAD_START_ROUTINE start, LPVOID param, LPTHREAD_START_ROUTINE start, LPVOID param,
DWORD flags, LPDWORD id ) DWORD flags, LPDWORD id )
{ {
int socket = -1;
HANDLE handle = 0; HANDLE handle = 0;
TEB *teb; TEB *teb;
void *tid = 0; 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 ) SERVER_START_REQ( new_thread )
{ {
req->suspend = ((flags & CREATE_SUSPENDED) != 0); req->suspend = ((flags & CREATE_SUSPENDED) != 0);
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
req->request_fd = request_pipe[0];
if (!SERVER_CALL_ERR()) if (!SERVER_CALL_ERR())
{ {
handle = req->handle; handle = req->handle;
tid = req->tid; tid = req->tid;
socket = wine_server_recv_fd( handle, 0 );
} }
close( request_pipe[0] );
} }
SERVER_END_REQ; 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; return 0;
} }
teb->process = NtCurrentTeb()->process; teb->process = NtCurrentTeb()->process;
teb->socket = socket; teb->tid = tid;
teb->request_fd = request_pipe[1];
teb->entry_point = start; teb->entry_point = start;
teb->entry_arg = param; teb->entry_arg = param;
teb->startup = THREAD_Start; teb->startup = THREAD_Start;
teb->htask16 = GetCurrentTask(); teb->htask16 = GetCurrentTask();
fcntl( socket, F_SETFD, 1 ); /* set close on exec flag */
if (id) *id = (DWORD)tid; if (id) *id = (DWORD)tid;
if (SYSDEPS_SpawnThread( teb ) == -1) if (SYSDEPS_SpawnThread( teb ) == -1)
......
...@@ -487,7 +487,7 @@ DECL_HANDLER(get_handle_fd) ...@@ -487,7 +487,7 @@ DECL_HANDLER(get_handle_fd)
else if (!get_error()) else if (!get_error())
{ {
if ((fd = obj->ops->get_fd( obj )) != -1) 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 ); release_object( obj );
} }
......
...@@ -147,6 +147,7 @@ struct thread *create_process( int fd ) ...@@ -147,6 +147,7 @@ struct thread *create_process( int fd )
{ {
struct process *process; struct process *process;
struct thread *thread = NULL; struct thread *thread = NULL;
int request_pipe[2];
if (!(process = alloc_object( &process_ops, fd ))) return NULL; if (!(process = alloc_object( &process_ops, fd ))) return NULL;
process->next = NULL; process->next = NULL;
...@@ -180,7 +181,14 @@ struct thread *create_process( int fd ) ...@@ -180,7 +181,14 @@ struct thread *create_process( int fd )
if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error; if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error;
/* create the main thread */ /* 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 */ set_select_events( &process->obj, POLLIN ); /* start listening to events */
release_object( process ); release_object( process );
......
...@@ -71,32 +71,6 @@ static const struct object_ops master_socket_ops = ...@@ -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 */ struct thread *current = NULL; /* thread handling the current request */
unsigned int global_error = 0; /* global error code for when no thread is current */ 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 ...@@ -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 ); 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 */ /* send a reply to a thread */
void send_reply( struct thread *thread, union generic_request *request ) void send_reply( struct thread *thread, union generic_request *request )
{ {
...@@ -215,7 +208,7 @@ 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) else if (errno == EPIPE)
kill_thread( thread, 0 ); /* normal death */ kill_thread( thread, 0 ); /* normal death */
else else
fatal_protocol_perror( thread, "sendmsg" ); fatal_protocol_perror( thread, "reply write" );
} }
} }
...@@ -244,7 +237,11 @@ int receive_fd( struct process *process ) ...@@ -244,7 +237,11 @@ int receive_fd( struct process *process )
if (ret == sizeof(data)) 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 (!thread || thread->process != process)
{ {
if (debug_level) if (debug_level)
...@@ -259,19 +256,16 @@ int receive_fd( struct process *process ) ...@@ -259,19 +256,16 @@ int receive_fd( struct process *process )
(unsigned int)thread, data.fd, fd ); (unsigned int)thread, data.fd, fd );
thread_add_inflight_fd( thread, data.fd, fd ); thread_add_inflight_fd( thread, data.fd, fd );
} }
if (thread) release_object( thread );
return 0; return 0;
} }
if (!ret) if (ret >= 0)
{
set_select_events( &process->obj, -1 ); /* stop waiting on it */
}
else if (ret > 0)
{ {
fprintf( stderr, "Protocol error: process %p: partial recvmsg %d for fd\n", process, ret ); fprintf( stderr, "Protocol error: process %p: partial recvmsg %d for fd\n", process, ret );
kill_process( process, NULL, 1 ); kill_process( process, NULL, 1 );
} }
else if (ret < 0) else
{ {
if (errno != EWOULDBLOCK && errno != EAGAIN) if (errno != EWOULDBLOCK && errno != EAGAIN)
{ {
...@@ -298,12 +292,12 @@ int send_thread_wakeup( struct thread *thread, int signaled ) ...@@ -298,12 +292,12 @@ int send_thread_wakeup( struct thread *thread, int signaled )
} }
/* send an fd to a client */ /* 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; int ret;
if (debug_level) 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 #ifdef HAVE_MSGHDR_ACCRIGHTS
msghdr.msg_accrightslen = sizeof(fd); msghdr.msg_accrightslen = sizeof(fd);
...@@ -317,16 +311,20 @@ int send_client_fd( struct thread *thread, int fd, handle_t handle ) ...@@ -317,16 +311,20 @@ int send_client_fd( struct thread *thread, int fd, handle_t handle )
myiovec.iov_base = (void *)&handle; myiovec.iov_base = (void *)&handle;
myiovec.iov_len = sizeof(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 (ret == sizeof(handle)) return 0;
if (errno == EPIPE)
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 else
{ {
fatal_protocol_perror( thread, "sendmsg" ); fprintf( stderr, "Protocol error: process %p: ", process );
perror( "sendmsg" );
kill_process( process, NULL, 1 );
} }
return -1; return -1;
} }
...@@ -373,60 +371,6 @@ static void master_socket_destroy( struct object *obj ) ...@@ -373,60 +371,6 @@ static void master_socket_destroy( struct object *obj )
socket_cleanup(); 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) */ /* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
const char *get_config_dir(void) const char *get_config_dir(void)
{ {
......
...@@ -33,12 +33,12 @@ extern void fatal_perror( const char *err, ... ) WINE_NORETURN; ...@@ -33,12 +33,12 @@ extern void fatal_perror( const char *err, ... ) WINE_NORETURN;
extern const char *get_config_dir(void); extern const char *get_config_dir(void);
extern int receive_fd( struct process *process ); extern int receive_fd( struct process *process );
extern int send_thread_wakeup( struct thread *thread, int signaled ); 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 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 void trace_request( struct thread *thread, const union generic_request *request ); extern void trace_request( struct thread *thread, const union generic_request *request );
extern void trace_reply( 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); ...@@ -71,7 +71,7 @@ DECL_HANDLER(boot_done);
DECL_HANDLER(init_process); DECL_HANDLER(init_process);
DECL_HANDLER(init_process_done); DECL_HANDLER(init_process_done);
DECL_HANDLER(init_thread); DECL_HANDLER(init_thread);
DECL_HANDLER(get_thread_buffer); DECL_HANDLER(set_thread_buffer);
DECL_HANDLER(terminate_process); DECL_HANDLER(terminate_process);
DECL_HANDLER(terminate_thread); DECL_HANDLER(terminate_thread);
DECL_HANDLER(get_process_info); DECL_HANDLER(get_process_info);
...@@ -186,7 +186,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -186,7 +186,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_init_process, (req_handler)req_init_process,
(req_handler)req_init_process_done, (req_handler)req_init_process_done,
(req_handler)req_init_thread, (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_process,
(req_handler)req_terminate_thread, (req_handler)req_terminate_thread,
(req_handler)req_get_process_info, (req_handler)req_get_process_info,
......
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
#include <stdarg.h> #include <stdarg.h>
...@@ -84,61 +80,6 @@ static const struct object_ops thread_ops = ...@@ -84,61 +80,6 @@ static const struct object_ops thread_ops =
static struct thread *first_thread; static struct thread *first_thread;
static struct thread *booting_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 */ /* initialize the structure for a newly allocated thread */
inline static void init_thread_structure( struct thread *thread ) inline static void init_thread_structure( struct thread *thread )
{ {
...@@ -170,7 +111,6 @@ 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->affinity = 1;
thread->suspend = 0; thread->suspend = 0;
thread->buffer = (void *)-1; thread->buffer = (void *)-1;
thread->last_req = REQ_get_thread_buffer;
for (i = 0; i < MAX_INFLIGHT_FDS; i++) for (i = 0; i < MAX_INFLIGHT_FDS; i++)
thread->inflight[i].server = thread->inflight[i].client = -1; thread->inflight[i].server = thread->inflight[i].client = -1;
...@@ -181,9 +121,6 @@ struct thread *create_thread( int fd, struct process *process ) ...@@ -181,9 +121,6 @@ struct thread *create_thread( int fd, struct process *process )
{ {
struct thread *thread; 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; if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
init_thread_structure( thread ); init_thread_structure( thread );
...@@ -200,15 +137,10 @@ struct thread *create_thread( int fd, struct process *process ) ...@@ -200,15 +137,10 @@ struct thread *create_thread( int fd, struct process *process )
if ((thread->next = first_thread) != NULL) thread->next->prev = thread; if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
first_thread = thread; first_thread = thread;
#if 0 fcntl( fd, F_SETFL, O_NONBLOCK );
set_select_events( &thread->obj, POLLIN ); /* start listening to events */ set_select_events( &thread->obj, POLLIN ); /* start listening to events */
#endif add_process_thread( thread->process, thread );
if (!alloc_client_buffer( thread )) goto error;
return thread; return thread;
error:
release_object( thread );
return NULL;
} }
/* handle a client event */ /* handle a client event */
...@@ -218,9 +150,7 @@ static void thread_poll_event( struct object *obj, int event ) ...@@ -218,9 +150,7 @@ static 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 );
#if 0
else if (event & POLLIN) read_request( thread ); else if (event & POLLIN) read_request( thread );
#endif
} }
/* cleanup everything that is no longer needed by a dead thread */ /* cleanup everything that is no longer needed by a dead thread */
...@@ -773,8 +703,6 @@ struct thread_snapshot *thread_snap( int *count ) ...@@ -773,8 +703,6 @@ struct thread_snapshot *thread_snap( int *count )
DECL_HANDLER(boot_done) DECL_HANDLER(boot_done)
{ {
debug_level = max( debug_level, req->debug_level ); debug_level = max( debug_level, req->debug_level );
/* Make sure last_req is initialized */
current->last_req = REQ_boot_done;
if (current == booting_thread) if (current == booting_thread)
{ {
booting_thread = (struct thread *)~0UL; /* make sure it doesn't match other threads */ booting_thread = (struct thread *)~0UL; /* make sure it doesn't match other threads */
...@@ -786,48 +714,97 @@ DECL_HANDLER(boot_done) ...@@ -786,48 +714,97 @@ DECL_HANDLER(boot_done)
DECL_HANDLER(new_thread) DECL_HANDLER(new_thread)
{ {
struct thread *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 ))) set_error( STATUS_INVALID_HANDLE );
return;
}
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 )))
{ {
if (req->suspend) thread->suspend++; /* thread object will be released when the thread gets killed */
req->tid = thread; return;
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] ); kill_thread( thread, 1 );
request_fd = -1;
} }
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" );
} }
/* initialize a new thread */ /* initialize a new thread */
DECL_HANDLER(init_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) if (current->unix_pid)
{ {
fatal_protocol_error( current, "init_thread: already running\n" ); 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->unix_pid = req->unix_pid;
current->teb = req->teb; 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->suspend + current->process->suspend > 0) stop_thread( current );
if (current->process->running_threads > 1) if (current->process->running_threads > 1)
generate_debug_event( current, CREATE_THREAD_DEBUG_EVENT, req->entry ); 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 */ /* terminate a thread */
......
...@@ -75,7 +75,6 @@ struct thread ...@@ -75,7 +75,6 @@ struct thread
int affinity; /* affinity mask */ int affinity; /* affinity mask */
int suspend; /* suspend count */ int suspend; /* suspend count */
void *buffer; /* buffer for communication with the client */ void *buffer; /* buffer for communication with the client */
enum request last_req; /* last request received (for debugging) */
}; };
struct thread_snapshot struct thread_snapshot
......
...@@ -299,7 +299,8 @@ static void dump_get_new_process_info_reply( const struct get_new_process_info_r ...@@ -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 ) static void dump_new_thread_request( const struct new_thread_request *req )
{ {
fprintf( stderr, " suspend=%d,", req->suspend ); 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 ) 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 ) ...@@ -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, " unix_pid=%d,", req->unix_pid );
fprintf( stderr, " teb=%p,", req->teb ); 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, " pid=%p,", req->pid );
fprintf( stderr, " tid=%p,", req->tid ); fprintf( stderr, " tid=%p,", req->tid );
...@@ -366,6 +365,17 @@ static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request ...@@ -366,6 +365,17 @@ static void dump_get_thread_buffer_reply( const struct get_thread_buffer_request
fprintf( stderr, " version=%d", req->version ); 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 ) static void dump_terminate_process_request( const struct terminate_process_request *req )
{ {
fprintf( stderr, " handle=%d,", req->handle ); fprintf( stderr, " handle=%d,", req->handle );
...@@ -1492,7 +1502,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -1492,7 +1502,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_init_process_request, (dump_func)dump_init_process_request,
(dump_func)dump_init_process_done_request, (dump_func)dump_init_process_done_request,
(dump_func)dump_init_thread_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_process_request,
(dump_func)dump_terminate_thread_request, (dump_func)dump_terminate_thread_request,
(dump_func)dump_get_process_info_request, (dump_func)dump_get_process_info_request,
...@@ -1603,8 +1613,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -1603,8 +1613,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0, (dump_func)0,
(dump_func)dump_init_process_reply, (dump_func)dump_init_process_reply,
(dump_func)dump_init_process_done_reply, (dump_func)dump_init_process_done_reply,
(dump_func)0, (dump_func)dump_init_thread_reply,
(dump_func)dump_get_thread_buffer_reply, (dump_func)dump_set_thread_buffer_reply,
(dump_func)dump_terminate_process_reply, (dump_func)dump_terminate_process_reply,
(dump_func)dump_terminate_thread_reply, (dump_func)dump_terminate_thread_reply,
(dump_func)dump_get_process_info_reply, (dump_func)dump_get_process_info_reply,
...@@ -1716,7 +1726,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -1716,7 +1726,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"init_process", "init_process",
"init_process_done", "init_process_done",
"init_thread", "init_thread",
"get_thread_buffer", "set_thread_buffer",
"terminate_process", "terminate_process",
"terminate_thread", "terminate_thread",
"get_process_info", "get_process_info",
...@@ -1884,7 +1894,6 @@ void trace_request( struct thread *thread, const union generic_request *request ...@@ -1884,7 +1894,6 @@ void trace_request( struct thread *thread, const union generic_request *request
{ {
enum request req = request->header.req; enum request req = request->header.req;
cur_pos = 0; cur_pos = 0;
current->last_req = req;
if (req < REQ_NB_REQUESTS) if (req < REQ_NB_REQUESTS)
{ {
fprintf( stderr, "%08x: %s(", (unsigned int)thread, req_names[req] ); 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 ...@@ -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 ) void trace_reply( struct thread *thread, const union generic_request *request )
{ {
fprintf( stderr, "%08x: %s() = %s", enum request req = request->header.req;
(unsigned int)thread, req_names[thread->last_req], get_status_name(thread->error) ); if (req < REQ_NB_REQUESTS)
if (reply_dumpers[thread->last_req])
{ {
fprintf( stderr, " {" ); fprintf( stderr, "%08x: %s() = %s",
cur_pos = 0; (unsigned int)thread, req_names[req], get_status_name(thread->error) );
reply_dumpers[thread->last_req]( request ); if (reply_dumpers[req])
fprintf( stderr, " }" ); {
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) );
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment