server: Simplify process creation.

Pass the socket for the new process from the parent through the
environment.
Perform initialisations during the new_process request.
This commit is contained in:
Alexandre Julliard 2006-07-19 14:00:10 +02:00
parent 718716b77a
commit c316f0e47f
8 changed files with 250 additions and 292 deletions

View File

@ -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 )
{ {
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
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 */
if (startup->dwFlags & STARTF_USESTDHANDLES)
{
params->hStdInput = startup->hStdInput; params->hStdInput = startup->hStdInput;
params->hStdOutput = startup->hStdOutput; params->hStdOutput = startup->hStdOutput;
params->hStdError = startup->hStdError; 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
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,75 +1284,18 @@ 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 );
RtlDestroyProcessParameters( params );
SetLastError( ERROR_TOO_MANY_OPEN_FILES ); 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; 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 */
@ -1347,20 +1303,15 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
{ {
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
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,25 +1344,46 @@ 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 */
write( startfd[1], &dummy, 1 ); if (!(pid = fork())) /* child */
close( startfd[1] );
if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */
{ {
errno = err; char preloader_reserve[64], socket_env[64];
FILE_SetDosError(); char **argv = build_argv( cmd_line, 1 );
close( execfd[0] );
CloseHandle( process_info ); if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
return FALSE;
/* 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);
}
/* this is the parent */
close( socketfd[0] );
HeapFree( GetProcessHeap(), 0, winedebug );
if (pid == -1)
{
FILE_SetDosError();
goto error;
} }
close( execfd[0] );
/* wait for the new process info to be ready */ /* wait for the new process info to be ready */
@ -1413,31 +1391,27 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
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;
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; success = reply->success;
} err = reply->exit_code;
} }
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;
} }

View File

@ -843,6 +843,16 @@ 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 *env_socket = getenv( "WINESERVERSOCKET" );
if (env_socket)
{
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(); const char *server_dir = wine_get_server_dir();
if (!server_dir) /* this means the config dir doesn't exist */ if (!server_dir) /* this means the config dir doesn't exist */
@ -853,6 +863,7 @@ void server_init_process(void)
/* 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 );

View File

@ -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
{ {
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
{ {
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
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 */

View File

@ -94,17 +94,11 @@ static const struct fd_ops process_fd_ops =
struct startup_info struct startup_info
{ {
struct object obj; /* object header */ struct object obj; /* object header */
struct list entry; /* entry in list of startup infos */
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 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 */
struct file *exe_file; /* file handle for main exe */ struct file *exe_file; /* file handle for main exe */
struct thread *owner; /* owner thread (the one that created the new process) */
struct process *process; /* created process */ struct process *process; /* created process */
struct thread *thread; /* created thread */
size_t data_size; /* size of startup data */ size_t data_size; /* size of startup data */
void *data; /* data for startup info */ void *data; /* data for startup info */
}; };
@ -130,8 +124,6 @@ static const struct object_ops startup_info_ops =
}; };
static struct list startup_info_list = LIST_INIT(startup_info_list);
struct ptid_entry struct ptid_entry
{ {
void *ptr; /* entry ptr */ void *ptr; /* entry ptr */
@ -226,13 +218,18 @@ static void set_process_startup_state( struct process *process, enum startup_sta
} }
/* create a new process and its main thread */ /* create a new process and its main thread */
struct thread *create_process( int fd ) /* if the function fails the fd is closed */
struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all )
{ {
struct process *process; struct process *process;
struct thread *thread = NULL; struct thread *thread = NULL;
int request_pipe[2]; int request_pipe[2];
if (!(process = alloc_object( &process_ops ))) goto error; if (!(process = alloc_object( &process_ops )))
{
close( fd );
goto error;
}
process->parent = NULL; process->parent = NULL;
process->debugger = NULL; process->debugger = NULL;
process->handles = NULL; process->handles = NULL;
@ -261,9 +258,24 @@ struct thread *create_process( int fd )
gettimeofday( &process->start_time, NULL ); gettimeofday( &process->start_time, NULL );
list_add_head( &process_list, &process->entry ); list_add_head( &process_list, &process->entry );
if (!(process->id = process->group_id = alloc_ptid( process ))) goto error; if (!(process->id = process->group_id = alloc_ptid( process )))
{
close( fd );
goto error;
}
if (!(process->msg_fd = create_anonymous_fd( &process_fd_ops, fd, &process->obj ))) goto error; if (!(process->msg_fd = create_anonymous_fd( &process_fd_ops, fd, &process->obj ))) goto error;
/* create the handle table */
if (!parent_thread) process->handles = alloc_handle_table( process, 0 );
else
{
struct process *parent = parent_thread->process;
process->parent = (struct process *)grab_object( parent );
process->handles = inherit_all ? copy_handle_table( process, parent )
: alloc_handle_table( process, 0 );
}
if (!process->handles) goto error;
/* create the main thread */ /* create the main thread */
if (pipe( request_pipe ) == -1) if (pipe( request_pipe ) == -1)
{ {
@ -290,82 +302,13 @@ struct thread *create_process( int fd )
return NULL; return NULL;
} }
/* find the startup info for a given Unix process */
inline static struct startup_info *find_startup_info( int unix_pid )
{
struct list *ptr;
LIST_FOR_EACH( ptr, &startup_info_list )
{
struct startup_info *info = LIST_ENTRY( ptr, struct startup_info, entry );
if (info->unix_pid == unix_pid) return info;
}
return NULL;
}
/* initialize the current process and fill in the request */ /* initialize the current process and fill in the request */
size_t init_process( struct thread *thread ) size_t init_process( struct thread *thread )
{ {
struct process *process = thread->process; struct process *process = thread->process;
struct thread *parent_thread = NULL; struct startup_info *info = process->startup_info;
struct process *parent = NULL;
struct startup_info *info;
if (process->startup_info) return process->startup_info->data_size; /* already initialized */
if ((info = find_startup_info( thread->unix_pid )))
{
if (info->thread) return info->data_size; /* already initialized */
info->thread = (struct thread *)grab_object( thread );
info->process = (struct process *)grab_object( process );
process->startup_info = (struct startup_info *)grab_object( info );
parent_thread = info->owner;
parent = parent_thread->process;
process->parent = (struct process *)grab_object( parent );
/* set the process flags */
process->create_flags = info->create_flags;
if (info->inherit_all) process->handles = copy_handle_table( process, parent );
}
/* create the handle table */
if (!process->handles) process->handles = alloc_handle_table( process, 0 );
if (!process->handles)
{
set_error( STATUS_NO_MEMORY );
return 0;
}
/* connect to the window station */
connect_process_winstation( process, parent_thread );
if (!info) return 0; if (!info) return 0;
/* thread will be actually suspended in init_done */
if (info->create_flags & CREATE_SUSPENDED) thread->suspend++;
/* set the process console */
if (!(info->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
{
/* FIXME: some better error checking should be done...
* like if hConOut and hConIn are console handles, then they should be on the same
* physical console
*/
inherit_console( parent_thread, process, info->inherit_all ? info->hstdin : 0 );
}
/* attach to the debugger if requested */
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent_thread );
else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent->debugger );
if (!(process->create_flags & CREATE_NEW_PROCESS_GROUP))
process->group_id = parent->group_id;
return info->data_size; return info->data_size;
} }
@ -426,12 +369,9 @@ static void startup_info_destroy( struct object *obj )
{ {
struct startup_info *info = (struct startup_info *)obj; struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops ); assert( obj->ops == &startup_info_ops );
list_remove( &info->entry );
if (info->data) free( info->data ); if (info->data) free( info->data );
if (info->exe_file) release_object( info->exe_file ); if (info->exe_file) release_object( info->exe_file );
if (info->process) release_object( info->process ); if (info->process) release_object( info->process );
if (info->thread) release_object( info->thread );
if (info->owner) release_object( info->owner );
} }
static void startup_info_dump( struct object *obj, int verbose ) static void startup_info_dump( struct object *obj, int verbose )
@ -439,8 +379,8 @@ static void startup_info_dump( struct object *obj, int verbose )
struct startup_info *info = (struct startup_info *)obj; struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops ); assert( obj->ops == &startup_info_ops );
fprintf( stderr, "Startup info flags=%x in=%p out=%p err=%p\n", fprintf( stderr, "Startup info in=%p out=%p err=%p\n",
info->create_flags, info->hstdin, info->hstdout, info->hstderr ); info->hstdin, info->hstdout, info->hstderr );
} }
static int startup_info_signaled( struct object *obj, struct thread *thread ) static int startup_info_signaled( struct object *obj, struct thread *thread )
@ -792,20 +732,30 @@ struct module_snapshot *module_snap( struct process *process, int *count )
DECL_HANDLER(new_process) DECL_HANDLER(new_process)
{ {
struct startup_info *info; struct startup_info *info;
struct thread *thread;
struct process *process;
struct process *parent = current->process;
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
if (socket_fd == -1)
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
if (fcntl( socket_fd, F_SETFL, O_NONBLOCK ) == -1)
{
set_error( STATUS_INVALID_HANDLE );
close( socket_fd );
return;
}
/* build the startup info for a new process */ /* build the startup info for a new process */
if (!(info = alloc_object( &startup_info_ops ))) return; if (!(info = alloc_object( &startup_info_ops ))) return;
list_add_head( &startup_info_list, &info->entry );
info->inherit_all = req->inherit_all;
info->create_flags = req->create_flags;
info->unix_pid = req->unix_pid;
info->hstdin = req->hstdin; info->hstdin = req->hstdin;
info->hstdout = req->hstdout; info->hstdout = req->hstdout;
info->hstderr = req->hstderr; info->hstderr = req->hstderr;
info->exe_file = NULL; info->exe_file = NULL;
info->owner = (struct thread *)grab_object( current );
info->process = NULL; info->process = NULL;
info->thread = NULL;
info->data_size = get_req_data_size(); info->data_size = get_req_data_size();
info->data = NULL; info->data = NULL;
@ -814,7 +764,56 @@ DECL_HANDLER(new_process)
goto done; goto done;
if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done; if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done;
if (!(thread = create_process( socket_fd, current, req->inherit_all ))) goto done;
process = thread->process;
process->create_flags = req->create_flags;
process->startup_info = (struct startup_info *)grab_object( info );
/* connect to the window station */
connect_process_winstation( process, current );
/* thread will be actually suspended in init_done */
if (req->create_flags & CREATE_SUSPENDED) thread->suspend++;
/* set the process console */
if (!(req->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
{
/* FIXME: some better error checking should be done...
* like if hConOut and hConIn are console handles, then they should be on the same
* physical console
*/
inherit_console( current, process, req->inherit_all ? req->hstdin : 0 );
}
if (!req->inherit_all && !(req->create_flags & CREATE_NEW_CONSOLE))
{
info->hstdin = duplicate_handle( parent, req->hstdin, process,
0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
info->hstdout = duplicate_handle( parent, req->hstdout, process,
0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
info->hstderr = duplicate_handle( parent, req->hstderr, process,
0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
/* some handles above may have been invalid; this is not an error */
if (get_error() == STATUS_INVALID_HANDLE ||
get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
}
/* attach to the debugger if requested */
if (req->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, current );
else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent->debugger );
if (!(req->create_flags & CREATE_NEW_PROCESS_GROUP))
process->group_id = parent->group_id;
info->process = (struct process *)grab_object( process );
reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 ); reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 );
reply->pid = get_process_id( process );
reply->tid = get_thread_id( thread );
reply->phandle = alloc_handle( parent, process, req->process_access, req->process_attr );
reply->thandle = alloc_handle( parent, thread, req->thread_access, req->thread_attr );
done: done:
release_object( info ); release_object( info );
@ -828,23 +827,10 @@ DECL_HANDLER(get_new_process_info)
if ((info = (struct startup_info *)get_handle_obj( current->process, req->info, if ((info = (struct startup_info *)get_handle_obj( current->process, req->info,
0, &startup_info_ops ))) 0, &startup_info_ops )))
{ {
reply->pid = get_process_id( info->process );
reply->tid = get_thread_id( info->thread );
reply->phandle = alloc_handle( current->process, info->process,
req->process_access, req->process_attr );
reply->thandle = alloc_handle( current->process, info->thread,
req->thread_access, req->thread_attr );
reply->success = is_process_init_done( info->process ); reply->success = is_process_init_done( info->process );
reply->exit_code = info->process->exit_code;
release_object( info ); release_object( info );
} }
else
{
reply->pid = 0;
reply->tid = 0;
reply->phandle = 0;
reply->thandle = 0;
reply->success = 0;
}
} }
/* Retrieve the new process startup info */ /* Retrieve the new process startup info */
@ -859,25 +845,9 @@ DECL_HANDLER(get_startup_info)
if (info->exe_file && if (info->exe_file &&
!(reply->exe_file = alloc_handle( process, info->exe_file, GENERIC_READ, 0 ))) return; !(reply->exe_file = alloc_handle( process, info->exe_file, GENERIC_READ, 0 ))) return;
if (!info->inherit_all && !(info->create_flags & CREATE_NEW_CONSOLE))
{
struct process *parent_process = info->owner->process;
reply->hstdin = duplicate_handle( parent_process, info->hstdin, process,
0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
reply->hstdout = duplicate_handle( parent_process, info->hstdout, process,
0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
reply->hstderr = duplicate_handle( parent_process, info->hstderr, process,
0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
/* some handles above may have been invalid; this is not an error */
if (get_error() == STATUS_INVALID_HANDLE ||
get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
}
else
{
reply->hstdin = info->hstdin; reply->hstdin = info->hstdin;
reply->hstdout = info->hstdout; reply->hstdout = info->hstdout;
reply->hstderr = info->hstderr; reply->hstderr = info->hstderr;
}
/* we return the data directly without making a copy so this can only be called once */ /* we return the data directly without making a copy so this can only be called once */
size = info->data_size; size = info->data_size;

View File

@ -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 );

View File

@ -207,31 +207,32 @@ struct token_groups
@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 */
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(info,startup_info); /* startup information */
VARARG(env,unicode_str); /* environment for new process */ 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

View File

@ -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 );
} }
} }

View File

@ -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 )
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 )