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:
parent
718716b77a
commit
c316f0e47f
|
@ -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 );
|
||||
RtlDestroyProcessParameters( params );
|
||||
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 */
|
||||
|
||||
write( startfd[1], &dummy, 1 );
|
||||
close( startfd[1] );
|
||||
|
||||
if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */
|
||||
if (!(pid = fork())) /* child */
|
||||
{
|
||||
errno = err;
|
||||
FILE_SetDosError();
|
||||
close( execfd[0] );
|
||||
CloseHandle( process_info );
|
||||
return FALSE;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
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();
|
||||
|
||||
/* connect to the server */
|
||||
fd_socket = server_connect( 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 );
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
|
220
server/process.c
220
server/process.c
|
@ -94,17 +94,11 @@ static const struct fd_ops process_fd_ops =
|
|||
struct startup_info
|
||||
{
|
||||
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 hstdout; /* handle for stdout */
|
||||
obj_handle_t hstderr; /* handle for stderr */
|
||||
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 thread *thread; /* created thread */
|
||||
size_t data_size; /* size of startup data */
|
||||
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
|
||||
{
|
||||
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 */
|
||||
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 thread *thread = NULL;
|
||||
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->debugger = NULL;
|
||||
process->handles = NULL;
|
||||
|
@ -261,9 +258,24 @@ struct thread *create_process( int fd )
|
|||
gettimeofday( &process->start_time, NULL );
|
||||
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;
|
||||
|
||||
/* 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 */
|
||||
if (pipe( request_pipe ) == -1)
|
||||
{
|
||||
|
@ -290,82 +302,13 @@ struct thread *create_process( int fd )
|
|||
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 */
|
||||
size_t init_process( struct thread *thread )
|
||||
{
|
||||
struct process *process = thread->process;
|
||||
struct thread *parent_thread = NULL;
|
||||
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 );
|
||||
struct startup_info *info = process->startup_info;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -426,12 +369,9 @@ static void startup_info_destroy( struct object *obj )
|
|||
{
|
||||
struct startup_info *info = (struct startup_info *)obj;
|
||||
assert( obj->ops == &startup_info_ops );
|
||||
list_remove( &info->entry );
|
||||
if (info->data) free( info->data );
|
||||
if (info->exe_file) release_object( info->exe_file );
|
||||
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 )
|
||||
|
@ -439,8 +379,8 @@ static void startup_info_dump( struct object *obj, int verbose )
|
|||
struct startup_info *info = (struct startup_info *)obj;
|
||||
assert( obj->ops == &startup_info_ops );
|
||||
|
||||
fprintf( stderr, "Startup info flags=%x in=%p out=%p err=%p\n",
|
||||
info->create_flags, info->hstdin, info->hstdout, info->hstderr );
|
||||
fprintf( stderr, "Startup info in=%p out=%p err=%p\n",
|
||||
info->hstdin, info->hstdout, info->hstderr );
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
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->hstdout = req->hstdout;
|
||||
info->hstderr = req->hstderr;
|
||||
info->exe_file = NULL;
|
||||
info->owner = (struct thread *)grab_object( current );
|
||||
info->process = NULL;
|
||||
info->thread = NULL;
|
||||
info->data_size = get_req_data_size();
|
||||
info->data = NULL;
|
||||
|
||||
|
@ -814,7 +764,56 @@ DECL_HANDLER(new_process)
|
|||
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->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:
|
||||
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,
|
||||
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->exit_code = info->process->exit_code;
|
||||
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 */
|
||||
|
@ -859,25 +845,9 @@ DECL_HANDLER(get_startup_info)
|
|||
if (info->exe_file &&
|
||||
!(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->hstdout = info->hstdout;
|
||||
reply->hstderr = info->hstderr;
|
||||
}
|
||||
reply->hstdin = info->hstdin;
|
||||
reply->hstdout = info->hstdout;
|
||||
reply->hstderr = info->hstderr;
|
||||
|
||||
/* we return the data directly without making a copy so this can only be called once */
|
||||
size = info->data_size;
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue