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
|
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
214
server/process.c
214
server/process.c
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 )
|
||||||
{
|
{
|
||||||
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 )
|
||||||
|
|
Loading…
Reference in New Issue