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 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#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
# include <sys/prctl.h>
#endif
......@@ -1104,6 +1110,7 @@ static char **build_envp( const WCHAR *envW )
{
if (*p == '=') continue; /* skip drive curdirs, this crashes some unix apps */
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" */
*envptr++ = alloc_env_string( "WINE", p );
else
......@@ -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_CONSOLE) params->ConsoleHandle = (HANDLE)1; /* FIXME: cf. kernel_main.c */
params->hStdInput = startup->hStdInput;
params->hStdOutput = startup->hStdOutput;
params->hStdError = startup->hStdError;
if (startup->dwFlags & STARTF_USESTDHANDLES)
{
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->dwY = startup->dwY;
params->dwXSize = startup->dwXSize;
......@@ -1243,12 +1259,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
WCHAR *env_end;
char *winedebug = NULL;
RTL_USER_PROCESS_PARAMETERS *params;
int startfd[2];
int execfd[2];
int socketfd[2];
pid_t pid;
int err;
char dummy = 0;
char preloader_reserve[64];
if (!env) RtlAcquirePebLock();
......@@ -1271,96 +1284,34 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
}
env_end++;
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx%c",
(unsigned long)res_start, (unsigned long)res_end, 0 );
/* create the socket for the new process */
/* create the synchronization pipes */
if (pipe( startfd ) == -1)
if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
{
if (!env) RtlReleasePebLock();
HeapFree( GetProcessHeap(), 0, winedebug );
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
RtlDestroyProcessParameters( params );
return FALSE;
}
if (pipe( execfd ) == -1)
{
if (!env) RtlReleasePebLock();
HeapFree( GetProcessHeap(), 0, winedebug );
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;
}
wine_server_send_fd( socketfd[1] );
close( socketfd[1] );
/* create the process on the server side */
SERVER_START_REQ( new_process )
{
req->inherit_all = inherit;
req->create_flags = flags;
req->unix_pid = pid;
req->exe_file = hFile;
if (startup->dwFlags & STARTF_USESTDHANDLES)
{
req->hstdin = startup->hStdInput;
req->hstdout = startup->hStdOutput;
req->hstderr = startup->hStdError;
}
else
{
req->hstdin = GetStdHandle( STD_INPUT_HANDLE );
req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
}
req->inherit_all = inherit;
req->create_flags = flags;
req->socket_fd = socketfd[1];
req->exe_file = hFile;
req->process_access = PROCESS_ALL_ACCESS;
req->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0;
req->thread_access = THREAD_ALL_ACCESS;
req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0;
req->hstdin = params->hStdInput;
req->hstdout = params->hStdOutput;
req->hstderr = params->hStdError;
if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0)
{
......@@ -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->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;
}
SERVER_END_REQ;
......@@ -1387,57 +1344,74 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
RtlDestroyProcessParameters( params );
if (!ret)
{
close( startfd[1] );
close( execfd[0] );
close( socketfd[0] );
HeapFree( GetProcessHeap(), 0, winedebug );
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 );
close( startfd[1] );
/* this is the parent */
if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */
close( socketfd[0] );
HeapFree( GetProcessHeap(), 0, winedebug );
if (pid == -1)
{
errno = err;
FILE_SetDosError();
close( execfd[0] );
CloseHandle( process_info );
return FALSE;
goto error;
}
close( execfd[0] );
/* wait for the new process info to be ready */
WaitForSingleObject( process_info, INFINITE );
SERVER_START_REQ( get_new_process_info )
{
req->info = process_info;
req->process_access = PROCESS_ALL_ACCESS;
req->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0;
req->thread_access = THREAD_ALL_ACCESS;
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;
}
req->info = process_info;
wine_server_call( req );
success = reply->success;
err = reply->exit_code;
}
SERVER_END_REQ;
if (ret && !success) /* new process failed to start */
if (!success)
{
DWORD exitcode;
if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
CloseHandle( info->hThread );
CloseHandle( info->hProcess );
ret = FALSE;
SetLastError( err ? err : ERROR_INTERNAL_ERROR );
goto error;
}
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)
void server_init_process(void)
{
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();
server_dir = wine_get_server_dir();
fd_socket = atoi( env_socket );
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 */
fd_socket = server_connect( server_dir );
/* connect to the server */
fd_socket = server_connect( server_dir );
}
/* setup the signal mask */
sigemptyset( &block_set );
......
......@@ -193,11 +193,15 @@ struct new_process_request
struct request_header __header;
int inherit_all;
unsigned int create_flags;
int unix_pid;
int socket_fd;
obj_handle_t exe_file;
obj_handle_t hstdin;
obj_handle_t hstdout;
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(env,unicode_str); */
};
......@@ -205,6 +209,10 @@ struct new_process_reply
{
struct reply_header __header;
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
{
struct request_header __header;
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 reply_header __header;
process_id_t pid;
obj_handle_t phandle;
thread_id_t tid;
obj_handle_t thandle;
int success;
int exit_code;
};
......@@ -4382,6 +4383,6 @@ union generic_reply
struct query_symlink_reply query_symlink_reply;
};
#define SERVER_PROTOCOL_VERSION 237
#define SERVER_PROTOCOL_VERSION 238
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -102,7 +102,7 @@ struct module_snapshot
extern unsigned int alloc_ptid( void *ptr );
extern void free_ptid( 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 struct thread *get_process_first_thread( struct process *process );
extern struct process *get_process_from_id( process_id_t id );
......
......@@ -205,33 +205,34 @@ struct token_groups
/* Create a new process from the context of the parent */
@REQ(new_process)
int inherit_all; /* inherit all handles from parent */
unsigned int create_flags; /* creation flags */
int unix_pid; /* Unix pid of new process */
obj_handle_t exe_file; /* file handle for main exe */
obj_handle_t hstdin; /* handle for stdin */
obj_handle_t hstdout; /* handle for stdout */
obj_handle_t hstderr; /* handle for stderr */
VARARG(info,startup_info); /* startup information */
VARARG(env,unicode_str); /* environment for new process */
int inherit_all; /* inherit all handles from parent */
unsigned int create_flags; /* creation flags */
int socket_fd; /* file descriptor for process socket */
obj_handle_t exe_file; /* file handle for main exe */
obj_handle_t hstdin; /* handle for stdin */
obj_handle_t hstdout; /* handle for stdout */
obj_handle_t hstderr; /* handle for stderr */
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 */
VARARG(info,startup_info); /* startup information */
VARARG(env,unicode_str); /* environment for new process */
@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
/* Retrieve information about a newly started process */
@REQ(get_new_process_info)
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
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 exit_code; /* process exit code if failed */
@END
......
......@@ -508,7 +508,7 @@ static void master_socket_poll_event( struct fd *fd, int event )
sock->timeout = NULL;
}
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 )
{
fprintf( stderr, " inherit_all=%d,", req->inherit_all );
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, " hstdin=%p,", req->hstdin );
fprintf( stderr, " hstdout=%p,", req->hstdout );
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=" );
dump_varargs_startup_info( cur_size );
fputc( ',', stderr );
......@@ -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 )
{
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 )
{
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 );
fprintf( stderr, " info=%p", req->info );
}
static void dump_get_new_process_info_reply( const struct get_new_process_info_reply *req )
{
fprintf( stderr, " pid=%04x,", req->pid );
fprintf( stderr, " phandle=%p,", req->phandle );
fprintf( stderr, " tid=%04x,", req->tid );
fprintf( stderr, " thandle=%p,", req->thandle );
fprintf( stderr, " success=%d", req->success );
fprintf( stderr, " success=%d,", req->success );
fprintf( stderr, " exit_code=%d", req->exit_code );
}
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