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:
parent
afa36ce1f1
commit
8859d77279
28
files/file.c
28
files/file.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
134
server/request.c
134
server/request.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
173
server/thread.c
173
server/thread.c
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue