Commit c316f0e4 authored by Alexandre Julliard's avatar Alexandre Julliard

server: Simplify process creation.

Pass the socket for the new process from the parent through the environment. Perform initialisations during the new_process request.
parent 718716b7
...@@ -31,6 +31,12 @@ ...@@ -31,6 +31,12 @@
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> # include <sys/time.h>
#endif #endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_PRCTL_H #ifdef HAVE_SYS_PRCTL_H
# include <sys/prctl.h> # include <sys/prctl.h>
#endif #endif
...@@ -1104,6 +1110,7 @@ static char **build_envp( const WCHAR *envW ) ...@@ -1104,6 +1110,7 @@ static char **build_envp( const WCHAR *envW )
{ {
if (*p == '=') continue; /* skip drive curdirs, this crashes some unix apps */ if (*p == '=') continue; /* skip drive curdirs, this crashes some unix apps */
if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue; if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
if (!strncmp( p, "WINESERVERSOCKET=", sizeof("WINESERVERSOCKET=")-1 )) continue;
if (is_special_env_var( p )) /* prefix it with "WINE" */ if (is_special_env_var( p )) /* prefix it with "WINE" */
*envptr++ = alloc_env_string( "WINE", p ); *envptr++ = alloc_env_string( "WINE", p );
else else
...@@ -1210,9 +1217,18 @@ static RTL_USER_PROCESS_PARAMETERS *create_user_params( LPCWSTR filename, LPCWST ...@@ -1210,9 +1217,18 @@ static RTL_USER_PROCESS_PARAMETERS *create_user_params( LPCWSTR filename, LPCWST
if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1; if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1;
if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1; /* FIXME: cf. kernel_main.c */ if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1; /* FIXME: cf. kernel_main.c */
params->hStdInput = startup->hStdInput; if (startup->dwFlags & STARTF_USESTDHANDLES)
params->hStdOutput = startup->hStdOutput; {
params->hStdError = startup->hStdError; params->hStdInput = startup->hStdInput;
params->hStdOutput = startup->hStdOutput;
params->hStdError = startup->hStdError;
}
else
{
params->hStdInput = GetStdHandle( STD_INPUT_HANDLE );
params->hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE );
params->hStdError = GetStdHandle( STD_ERROR_HANDLE );
}
params->dwX = startup->dwX; params->dwX = startup->dwX;
params->dwY = startup->dwY; params->dwY = startup->dwY;
params->dwXSize = startup->dwXSize; params->dwXSize = startup->dwXSize;
...@@ -1243,12 +1259,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW ...@@ -1243,12 +1259,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
WCHAR *env_end; WCHAR *env_end;
char *winedebug = NULL; char *winedebug = NULL;
RTL_USER_PROCESS_PARAMETERS *params; RTL_USER_PROCESS_PARAMETERS *params;
int startfd[2]; int socketfd[2];
int execfd[2];
pid_t pid; pid_t pid;
int err; int err;
char dummy = 0;
char preloader_reserve[64];
if (!env) RtlAcquirePebLock(); if (!env) RtlAcquirePebLock();
...@@ -1271,96 +1284,34 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW ...@@ -1271,96 +1284,34 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
} }
env_end++; env_end++;
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx%c", /* create the socket for the new process */
(unsigned long)res_start, (unsigned long)res_end, 0 );
/* create the synchronization pipes */ if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
if (pipe( startfd ) == -1)
{ {
if (!env) RtlReleasePebLock(); if (!env) RtlReleasePebLock();
HeapFree( GetProcessHeap(), 0, winedebug ); HeapFree( GetProcessHeap(), 0, winedebug );
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
RtlDestroyProcessParameters( params ); RtlDestroyProcessParameters( params );
return FALSE;
}
if (pipe( execfd ) == -1)
{
if (!env) RtlReleasePebLock();
HeapFree( GetProcessHeap(), 0, winedebug );
SetLastError( ERROR_TOO_MANY_OPEN_FILES ); SetLastError( ERROR_TOO_MANY_OPEN_FILES );
close( startfd[0] );
close( startfd[1] );
RtlDestroyProcessParameters( params );
return FALSE;
}
fcntl( execfd[1], F_SETFD, 1 ); /* set close on exec */
/* create the child process */
if (!(pid = fork())) /* child */
{
char **argv = build_argv( cmd_line, 1 );
close( startfd[1] );
close( execfd[0] );
/* wait for parent to tell us to start */
if (read( startfd[0], &dummy, 1 ) != 1) _exit(1);
close( startfd[0] );
if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
/* Reset signals that we previously set to SIG_IGN */
signal( SIGPIPE, SIG_DFL );
signal( SIGCHLD, SIG_DFL );
putenv( preloader_reserve );
if (winedebug) putenv( winedebug );
if (unixdir) chdir(unixdir);
if (argv) wine_exec_wine_binary( NULL, argv, getenv("WINELOADER") );
err = errno;
write( execfd[1], &err, sizeof(err) );
_exit(1);
}
/* this is the parent */
close( startfd[0] );
close( execfd[1] );
HeapFree( GetProcessHeap(), 0, winedebug );
if (pid == -1)
{
if (!env) RtlReleasePebLock();
close( startfd[1] );
close( execfd[0] );
FILE_SetDosError();
RtlDestroyProcessParameters( params );
return FALSE; return FALSE;
} }
wine_server_send_fd( socketfd[1] );
close( socketfd[1] );
/* create the process on the server side */ /* create the process on the server side */
SERVER_START_REQ( new_process ) SERVER_START_REQ( new_process )
{ {
req->inherit_all = inherit; req->inherit_all = inherit;
req->create_flags = flags; req->create_flags = flags;
req->unix_pid = pid; req->socket_fd = socketfd[1];
req->exe_file = hFile; req->exe_file = hFile;
if (startup->dwFlags & STARTF_USESTDHANDLES) req->process_access = PROCESS_ALL_ACCESS;
{ req->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0;
req->hstdin = startup->hStdInput; req->thread_access = THREAD_ALL_ACCESS;
req->hstdout = startup->hStdOutput; req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0;
req->hstderr = startup->hStdError; req->hstdin = params->hStdInput;
} req->hstdout = params->hStdOutput;
else req->hstderr = params->hStdError;
{
req->hstdin = GetStdHandle( STD_INPUT_HANDLE );
req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
}
if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0) if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0)
{ {
...@@ -1378,7 +1329,13 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW ...@@ -1378,7 +1329,13 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
wine_server_add_data( req, params, params->Size ); wine_server_add_data( req, params, params->Size );
wine_server_add_data( req, params->Environment, (env_end-params->Environment)*sizeof(WCHAR) ); wine_server_add_data( req, params->Environment, (env_end-params->Environment)*sizeof(WCHAR) );
ret = !wine_server_call_err( req ); if ((ret = !wine_server_call_err( req )))
{
info->dwProcessId = (DWORD)reply->pid;
info->dwThreadId = (DWORD)reply->tid;
info->hProcess = reply->phandle;
info->hThread = reply->thandle;
}
process_info = reply->info; process_info = reply->info;
} }
SERVER_END_REQ; SERVER_END_REQ;
...@@ -1387,57 +1344,74 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW ...@@ -1387,57 +1344,74 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
RtlDestroyProcessParameters( params ); RtlDestroyProcessParameters( params );
if (!ret) if (!ret)
{ {
close( startfd[1] ); close( socketfd[0] );
close( execfd[0] ); HeapFree( GetProcessHeap(), 0, winedebug );
return FALSE; return FALSE;
} }
/* tell child to start and wait for it to exec */ /* create the child process */
if (!(pid = fork())) /* child */
{
char preloader_reserve[64], socket_env[64];
char **argv = build_argv( cmd_line, 1 );
if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
/* Reset signals that we previously set to SIG_IGN */
signal( SIGPIPE, SIG_DFL );
signal( SIGCHLD, SIG_DFL );
sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd[0] );
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx",
(unsigned long)res_start, (unsigned long)res_end );
putenv( preloader_reserve );
putenv( socket_env );
if (winedebug) putenv( winedebug );
if (unixdir) chdir(unixdir);
if (argv) wine_exec_wine_binary( NULL, argv, getenv("WINELOADER") );
_exit(1);
}
write( startfd[1], &dummy, 1 ); /* this is the parent */
close( startfd[1] );
if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */ close( socketfd[0] );
HeapFree( GetProcessHeap(), 0, winedebug );
if (pid == -1)
{ {
errno = err;
FILE_SetDosError(); FILE_SetDosError();
close( execfd[0] ); goto error;
CloseHandle( process_info );
return FALSE;
} }
close( execfd[0] );
/* wait for the new process info to be ready */ /* wait for the new process info to be ready */
WaitForSingleObject( process_info, INFINITE ); WaitForSingleObject( process_info, INFINITE );
SERVER_START_REQ( get_new_process_info ) SERVER_START_REQ( get_new_process_info )
{ {
req->info = process_info; req->info = process_info;
req->process_access = PROCESS_ALL_ACCESS; wine_server_call( req );
req->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0; success = reply->success;
req->thread_access = THREAD_ALL_ACCESS; err = reply->exit_code;
req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0;
if ((ret = !wine_server_call_err( req )))
{
info->dwProcessId = (DWORD)reply->pid;
info->dwThreadId = (DWORD)reply->tid;
info->hProcess = reply->phandle;
info->hThread = reply->thandle;
success = reply->success;
}
} }
SERVER_END_REQ; SERVER_END_REQ;
if (ret && !success) /* new process failed to start */ if (!success)
{ {
DWORD exitcode; SetLastError( err ? err : ERROR_INTERNAL_ERROR );
if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode ); goto error;
CloseHandle( info->hThread );
CloseHandle( info->hProcess );
ret = FALSE;
} }
CloseHandle( process_info ); CloseHandle( process_info );
return ret; return success;
error:
CloseHandle( process_info );
CloseHandle( info->hProcess );
CloseHandle( info->hThread );
info->hProcess = info->hThread = 0;
info->dwProcessId = info->dwThreadId = 0;
return FALSE;
} }
......
...@@ -843,16 +843,27 @@ static void create_config_dir(void) ...@@ -843,16 +843,27 @@ static void create_config_dir(void)
void server_init_process(void) void server_init_process(void)
{ {
obj_handle_t dummy_handle; obj_handle_t dummy_handle;
const char *server_dir = wine_get_server_dir(); const char *env_socket = getenv( "WINESERVERSOCKET" );
if (!server_dir) /* this means the config dir doesn't exist */ if (env_socket)
{ {
create_config_dir(); fd_socket = atoi( env_socket );
server_dir = wine_get_server_dir(); if (fcntl( fd_socket, F_SETFD, 1 ) == -1)
fatal_perror( "Bad server socket %d", fd_socket );
} }
else
{
const char *server_dir = wine_get_server_dir();
if (!server_dir) /* this means the config dir doesn't exist */
{
create_config_dir();
server_dir = wine_get_server_dir();
}
/* connect to the server */ /* connect to the server */
fd_socket = server_connect( server_dir ); fd_socket = server_connect( server_dir );
}
/* setup the signal mask */ /* setup the signal mask */
sigemptyset( &block_set ); sigemptyset( &block_set );
......
...@@ -193,11 +193,15 @@ struct new_process_request ...@@ -193,11 +193,15 @@ struct new_process_request
struct request_header __header; struct request_header __header;
int inherit_all; int inherit_all;
unsigned int create_flags; unsigned int create_flags;
int unix_pid; int socket_fd;
obj_handle_t exe_file; obj_handle_t exe_file;
obj_handle_t hstdin; obj_handle_t hstdin;
obj_handle_t hstdout; obj_handle_t hstdout;
obj_handle_t hstderr; obj_handle_t hstderr;
unsigned int process_access;
unsigned int process_attr;
unsigned int thread_access;
unsigned int thread_attr;
/* VARARG(info,startup_info); */ /* VARARG(info,startup_info); */
/* VARARG(env,unicode_str); */ /* VARARG(env,unicode_str); */
}; };
...@@ -205,6 +209,10 @@ struct new_process_reply ...@@ -205,6 +209,10 @@ struct new_process_reply
{ {
struct reply_header __header; struct reply_header __header;
obj_handle_t info; obj_handle_t info;
process_id_t pid;
obj_handle_t phandle;
thread_id_t tid;
obj_handle_t thandle;
}; };
...@@ -213,19 +221,12 @@ struct get_new_process_info_request ...@@ -213,19 +221,12 @@ struct get_new_process_info_request
{ {
struct request_header __header; struct request_header __header;
obj_handle_t info; obj_handle_t info;
unsigned int process_access;
unsigned int process_attr;
unsigned int thread_access;
unsigned int thread_attr;
}; };
struct get_new_process_info_reply struct get_new_process_info_reply
{ {
struct reply_header __header; struct reply_header __header;
process_id_t pid;
obj_handle_t phandle;
thread_id_t tid;
obj_handle_t thandle;
int success; int success;
int exit_code;
}; };
...@@ -4382,6 +4383,6 @@ union generic_reply ...@@ -4382,6 +4383,6 @@ union generic_reply
struct query_symlink_reply query_symlink_reply; struct query_symlink_reply query_symlink_reply;
}; };
#define SERVER_PROTOCOL_VERSION 237 #define SERVER_PROTOCOL_VERSION 238
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -102,7 +102,7 @@ struct module_snapshot ...@@ -102,7 +102,7 @@ struct module_snapshot
extern unsigned int alloc_ptid( void *ptr ); extern unsigned int alloc_ptid( void *ptr );
extern void free_ptid( unsigned int id ); extern void free_ptid( unsigned int id );
extern void *get_ptid_entry( unsigned int id ); extern void *get_ptid_entry( unsigned int id );
extern struct thread *create_process( int fd ); extern struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all );
extern size_t init_process( struct thread *thread ); extern size_t init_process( struct thread *thread );
extern struct thread *get_process_first_thread( struct process *process ); extern struct thread *get_process_first_thread( struct process *process );
extern struct process *get_process_from_id( process_id_t id ); extern struct process *get_process_from_id( process_id_t id );
......
...@@ -205,33 +205,34 @@ struct token_groups ...@@ -205,33 +205,34 @@ struct token_groups
/* Create a new process from the context of the parent */ /* Create a new process from the context of the parent */
@REQ(new_process) @REQ(new_process)
int inherit_all; /* inherit all handles from parent */ int inherit_all; /* inherit all handles from parent */
unsigned int create_flags; /* creation flags */ unsigned int create_flags; /* creation flags */
int unix_pid; /* Unix pid of new process */ int socket_fd; /* file descriptor for process socket */
obj_handle_t exe_file; /* file handle for main exe */ obj_handle_t exe_file; /* file handle for main exe */
obj_handle_t hstdin; /* handle for stdin */ obj_handle_t hstdin; /* handle for stdin */
obj_handle_t hstdout; /* handle for stdout */ obj_handle_t hstdout; /* handle for stdout */
obj_handle_t hstderr; /* handle for stderr */ obj_handle_t hstderr; /* handle for stderr */
VARARG(info,startup_info); /* startup information */ unsigned int process_access; /* access rights for process object */
VARARG(env,unicode_str); /* environment for new process */ unsigned int process_attr; /* attributes for process object */
unsigned int thread_access; /* access rights for thread object */
unsigned int thread_attr; /* attributes for thread object */
VARARG(info,startup_info); /* startup information */
VARARG(env,unicode_str); /* environment for new process */
@REPLY @REPLY
obj_handle_t info; /* new process info handle */ obj_handle_t info; /* new process info handle */
process_id_t pid; /* process id */
obj_handle_t phandle; /* process handle (in the current process) */
thread_id_t tid; /* thread id */
obj_handle_t thandle; /* thread handle (in the current process) */
@END @END
/* Retrieve information about a newly started process */ /* Retrieve information about a newly started process */
@REQ(get_new_process_info) @REQ(get_new_process_info)
obj_handle_t info; /* info handle returned from new_process_request */ obj_handle_t info; /* info handle returned from new_process_request */
unsigned int process_access; /* access rights for process object */
unsigned int process_attr; /* attributes for process object */
unsigned int thread_access; /* access rights for thread object */
unsigned int thread_attr; /* attributes for thread object */
@REPLY @REPLY
process_id_t pid; /* process id */
obj_handle_t phandle; /* process handle (in the current process) */
thread_id_t tid; /* thread id */
obj_handle_t thandle; /* thread handle (in the current process) */
int success; /* did the process start successfully? */ int success; /* did the process start successfully? */
int exit_code; /* process exit code if failed */
@END @END
......
...@@ -508,7 +508,7 @@ static void master_socket_poll_event( struct fd *fd, int event ) ...@@ -508,7 +508,7 @@ static void master_socket_poll_event( struct fd *fd, int event )
sock->timeout = NULL; sock->timeout = NULL;
} }
fcntl( client, F_SETFL, O_NONBLOCK ); fcntl( client, F_SETFL, O_NONBLOCK );
create_process( client ); create_process( client, NULL, 0 );
} }
} }
......
...@@ -606,11 +606,15 @@ static void dump_new_process_request( const struct new_process_request *req ) ...@@ -606,11 +606,15 @@ static void dump_new_process_request( const struct new_process_request *req )
{ {
fprintf( stderr, " inherit_all=%d,", req->inherit_all ); fprintf( stderr, " inherit_all=%d,", req->inherit_all );
fprintf( stderr, " create_flags=%08x,", req->create_flags ); fprintf( stderr, " create_flags=%08x,", req->create_flags );
fprintf( stderr, " unix_pid=%d,", req->unix_pid ); fprintf( stderr, " socket_fd=%d,", req->socket_fd );
fprintf( stderr, " exe_file=%p,", req->exe_file ); fprintf( stderr, " exe_file=%p,", req->exe_file );
fprintf( stderr, " hstdin=%p,", req->hstdin ); fprintf( stderr, " hstdin=%p,", req->hstdin );
fprintf( stderr, " hstdout=%p,", req->hstdout ); fprintf( stderr, " hstdout=%p,", req->hstdout );
fprintf( stderr, " hstderr=%p,", req->hstderr ); fprintf( stderr, " hstderr=%p,", req->hstderr );
fprintf( stderr, " process_access=%08x,", req->process_access );
fprintf( stderr, " process_attr=%08x,", req->process_attr );
fprintf( stderr, " thread_access=%08x,", req->thread_access );
fprintf( stderr, " thread_attr=%08x,", req->thread_attr );
fprintf( stderr, " info=" ); fprintf( stderr, " info=" );
dump_varargs_startup_info( cur_size ); dump_varargs_startup_info( cur_size );
fputc( ',', stderr ); fputc( ',', stderr );
...@@ -620,25 +624,22 @@ static void dump_new_process_request( const struct new_process_request *req ) ...@@ -620,25 +624,22 @@ static void dump_new_process_request( const struct new_process_request *req )
static void dump_new_process_reply( const struct new_process_reply *req ) static void dump_new_process_reply( const struct new_process_reply *req )
{ {
fprintf( stderr, " info=%p", req->info ); fprintf( stderr, " info=%p,", req->info );
fprintf( stderr, " pid=%04x,", req->pid );
fprintf( stderr, " phandle=%p,", req->phandle );
fprintf( stderr, " tid=%04x,", req->tid );
fprintf( stderr, " thandle=%p", req->thandle );
} }
static void dump_get_new_process_info_request( const struct get_new_process_info_request *req ) static void dump_get_new_process_info_request( const struct get_new_process_info_request *req )
{ {
fprintf( stderr, " info=%p,", req->info ); fprintf( stderr, " info=%p", req->info );
fprintf( stderr, " process_access=%08x,", req->process_access );
fprintf( stderr, " process_attr=%08x,", req->process_attr );
fprintf( stderr, " thread_access=%08x,", req->thread_access );
fprintf( stderr, " thread_attr=%08x", req->thread_attr );
} }
static void dump_get_new_process_info_reply( const struct get_new_process_info_reply *req ) static void dump_get_new_process_info_reply( const struct get_new_process_info_reply *req )
{ {
fprintf( stderr, " pid=%04x,", req->pid ); fprintf( stderr, " success=%d,", req->success );
fprintf( stderr, " phandle=%p,", req->phandle ); fprintf( stderr, " exit_code=%d", req->exit_code );
fprintf( stderr, " tid=%04x,", req->tid );
fprintf( stderr, " thandle=%p,", req->thandle );
fprintf( stderr, " success=%d", req->success );
} }
static void dump_new_thread_request( const struct new_thread_request *req ) static void dump_new_thread_request( const struct new_thread_request *req )
......
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