Pass the pid of the new process in the new_process request, don't
depend on the parent pid to find the startup info.
This commit is contained in:
parent
745a78f490
commit
77c8b1dc2b
|
@ -185,6 +185,7 @@ struct new_process_request
|
||||||
int inherit_all;
|
int inherit_all;
|
||||||
int use_handles;
|
int use_handles;
|
||||||
int create_flags;
|
int create_flags;
|
||||||
|
int unix_pid;
|
||||||
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;
|
||||||
|
@ -250,7 +251,6 @@ struct init_process_request
|
||||||
{
|
{
|
||||||
struct request_header __header;
|
struct request_header __header;
|
||||||
void* ldt_copy;
|
void* ldt_copy;
|
||||||
int ppid;
|
|
||||||
};
|
};
|
||||||
struct init_process_reply
|
struct init_process_reply
|
||||||
{
|
{
|
||||||
|
@ -3551,6 +3551,6 @@ union generic_reply
|
||||||
struct get_next_hook_reply get_next_hook_reply;
|
struct get_next_hook_reply get_next_hook_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 97
|
#define SERVER_PROTOCOL_VERSION 98
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -416,7 +416,6 @@ static BOOL process_init( char *argv[] )
|
||||||
SERVER_START_REQ( init_process )
|
SERVER_START_REQ( init_process )
|
||||||
{
|
{
|
||||||
req->ldt_copy = &wine_ldt_copy;
|
req->ldt_copy = &wine_ldt_copy;
|
||||||
req->ppid = getppid();
|
|
||||||
if ((ret = !wine_server_call_err( req )))
|
if ((ret = !wine_server_call_err( req )))
|
||||||
{
|
{
|
||||||
main_exe_file = reply->exe_file;
|
main_exe_file = reply->exe_file;
|
||||||
|
@ -888,20 +887,15 @@ static void exec_wine_binary( char **argv, char **envp )
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* fork_and_exec
|
* fork_and_exec
|
||||||
*
|
*
|
||||||
* Fork and exec a new Unix process, checking for errors.
|
* Fork and exec a new Unix binary, checking for errors.
|
||||||
*/
|
*/
|
||||||
static int fork_and_exec( const char *filename, char *cmdline,
|
static int fork_and_exec( const char *filename, char *cmdline,
|
||||||
const char *env, const char *newdir )
|
const char *env, const char *newdir )
|
||||||
{
|
{
|
||||||
int fd[2];
|
int fd[2];
|
||||||
int pid, err;
|
int pid, err;
|
||||||
char *extra_env = NULL;
|
|
||||||
|
|
||||||
if (!env)
|
if (!env) env = GetEnvironmentStringsA();
|
||||||
{
|
|
||||||
env = GetEnvironmentStringsA();
|
|
||||||
extra_env = DRIVE_BuildEnv();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipe(fd) == -1)
|
if (pipe(fd) == -1)
|
||||||
{
|
{
|
||||||
|
@ -911,8 +905,8 @@ static int fork_and_exec( const char *filename, char *cmdline,
|
||||||
fcntl( fd[1], F_SETFD, 1 ); /* set close on exec */
|
fcntl( fd[1], F_SETFD, 1 ); /* set close on exec */
|
||||||
if (!(pid = fork())) /* child */
|
if (!(pid = fork())) /* child */
|
||||||
{
|
{
|
||||||
char **argv = build_argv( cmdline, filename ? 0 : 1 );
|
char **argv = build_argv( cmdline, 0 );
|
||||||
char **envp = build_envp( env, extra_env );
|
char **envp = build_envp( env, NULL );
|
||||||
close( fd[0] );
|
close( fd[0] );
|
||||||
|
|
||||||
/* Reset signals that we previously set to SIG_IGN */
|
/* Reset signals that we previously set to SIG_IGN */
|
||||||
|
@ -921,11 +915,7 @@ static int fork_and_exec( const char *filename, char *cmdline,
|
||||||
|
|
||||||
if (newdir) chdir(newdir);
|
if (newdir) chdir(newdir);
|
||||||
|
|
||||||
if (argv && envp)
|
if (argv && envp) execve( filename, argv, envp );
|
||||||
{
|
|
||||||
if (!filename) exec_wine_binary( argv, envp );
|
|
||||||
else execve( filename, argv, envp );
|
|
||||||
}
|
|
||||||
err = errno;
|
err = errno;
|
||||||
write( fd[1], &err, sizeof(err) );
|
write( fd[1], &err, sizeof(err) );
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
@ -938,7 +928,6 @@ static int fork_and_exec( const char *filename, char *cmdline,
|
||||||
}
|
}
|
||||||
if (pid == -1) FILE_SetDosError();
|
if (pid == -1) FILE_SetDosError();
|
||||||
close( fd[0] );
|
close( fd[0] );
|
||||||
if (extra_env) HeapFree( GetProcessHeap(), 0, extra_env );
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -957,6 +946,74 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST
|
||||||
BOOL ret, success = FALSE;
|
BOOL ret, success = FALSE;
|
||||||
HANDLE process_info;
|
HANDLE process_info;
|
||||||
startup_info_t startup_info;
|
startup_info_t startup_info;
|
||||||
|
char *extra_env = NULL;
|
||||||
|
int startfd[2];
|
||||||
|
int execfd[2];
|
||||||
|
pid_t pid;
|
||||||
|
int err;
|
||||||
|
char dummy;
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
{
|
||||||
|
env = GetEnvironmentStringsA();
|
||||||
|
extra_env = DRIVE_BuildEnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the synchronization pipes */
|
||||||
|
|
||||||
|
if (pipe( startfd ) == -1)
|
||||||
|
{
|
||||||
|
FILE_SetDosError();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (pipe( execfd ) == -1)
|
||||||
|
{
|
||||||
|
close( startfd[0] );
|
||||||
|
close( startfd[1] );
|
||||||
|
FILE_SetDosError();
|
||||||
|
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 );
|
||||||
|
char **envp = build_envp( env, extra_env );
|
||||||
|
|
||||||
|
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] );
|
||||||
|
/* Reset signals that we previously set to SIG_IGN */
|
||||||
|
signal( SIGPIPE, SIG_DFL );
|
||||||
|
signal( SIGCHLD, SIG_DFL );
|
||||||
|
|
||||||
|
if (unixdir) chdir(unixdir);
|
||||||
|
|
||||||
|
if (argv && envp) exec_wine_binary( argv, envp );
|
||||||
|
|
||||||
|
err = errno;
|
||||||
|
write( execfd[1], &err, sizeof(err) );
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is the parent */
|
||||||
|
|
||||||
|
close( startfd[0] );
|
||||||
|
close( execfd[1] );
|
||||||
|
if (extra_env) HeapFree( GetProcessHeap(), 0, extra_env );
|
||||||
|
if (pid == -1)
|
||||||
|
{
|
||||||
|
close( startfd[1] );
|
||||||
|
close( execfd[0] );
|
||||||
|
FILE_SetDosError();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* fill the startup info structure */
|
/* fill the startup info structure */
|
||||||
|
|
||||||
|
@ -985,6 +1042,7 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST
|
||||||
req->inherit_all = inherit;
|
req->inherit_all = inherit;
|
||||||
req->create_flags = flags;
|
req->create_flags = flags;
|
||||||
req->use_handles = (startup->dwFlags & STARTF_USESTDHANDLES) != 0;
|
req->use_handles = (startup->dwFlags & STARTF_USESTDHANDLES) != 0;
|
||||||
|
req->unix_pid = pid;
|
||||||
req->exe_file = hFile;
|
req->exe_file = hFile;
|
||||||
if (startup->dwFlags & STARTF_USESTDHANDLES)
|
if (startup->dwFlags & STARTF_USESTDHANDLES)
|
||||||
{
|
{
|
||||||
|
@ -1015,12 +1073,24 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST
|
||||||
process_info = reply->info;
|
process_info = reply->info;
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
if (!ret) return FALSE;
|
|
||||||
|
|
||||||
/* fork and execute */
|
if (!ret)
|
||||||
|
|
||||||
if (fork_and_exec( NULL, cmd_line, env, unixdir ) == -1)
|
|
||||||
{
|
{
|
||||||
|
close( startfd[1] );
|
||||||
|
close( execfd[0] );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tell child to start and wait for it to exec */
|
||||||
|
|
||||||
|
write( startfd[1], &dummy, 1 );
|
||||||
|
close( startfd[1] );
|
||||||
|
|
||||||
|
if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */
|
||||||
|
{
|
||||||
|
errno = err;
|
||||||
|
FILE_SetDosError();
|
||||||
|
close( execfd[0] );
|
||||||
CloseHandle( process_info );
|
CloseHandle( process_info );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,9 +81,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 */
|
int inherit_all; /* inherit all handles from parent */
|
||||||
int use_handles; /* use stdio handles */
|
int use_handles; /* use stdio handles */
|
||||||
int create_flags; /* creation flags */
|
int create_flags; /* creation flags */
|
||||||
|
pid_t 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 */
|
||||||
|
@ -112,6 +114,8 @@ 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 */
|
||||||
|
@ -326,23 +330,36 @@ 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( pid_t 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 */
|
||||||
static struct startup_info *init_process( int ppid, struct init_process_reply *reply )
|
static struct startup_info *init_process( struct init_process_reply *reply )
|
||||||
{
|
{
|
||||||
struct process *process = current->process;
|
struct process *process = current->process;
|
||||||
struct thread *parent_thread = get_thread_from_pid( ppid );
|
struct thread *parent_thread = NULL;
|
||||||
struct process *parent = NULL;
|
struct process *parent = NULL;
|
||||||
struct startup_info *info = NULL;
|
struct startup_info *info = find_startup_info( current->unix_pid );
|
||||||
|
|
||||||
if (parent_thread)
|
if (info)
|
||||||
{
|
{
|
||||||
parent = parent_thread->process;
|
if (info->thread)
|
||||||
info = parent_thread->info;
|
|
||||||
if (info && info->thread)
|
|
||||||
{
|
{
|
||||||
fatal_protocol_error( current, "init_process: called twice?\n" );
|
fatal_protocol_error( current, "init_process: called twice?\n" );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
parent_thread = info->owner;
|
||||||
|
parent = parent_thread->process;
|
||||||
process->parent = (struct process *)grab_object( parent );
|
process->parent = (struct process *)grab_object( parent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,15 +464,12 @@ 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->thread) release_object( info->thread );
|
||||||
if (info->owner)
|
if (info->owner) release_object( info->owner );
|
||||||
{
|
|
||||||
info->owner->info = NULL;
|
|
||||||
release_object( info->owner );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void startup_info_dump( struct object *obj, int verbose )
|
static void startup_info_dump( struct object *obj, int verbose )
|
||||||
|
@ -878,17 +892,13 @@ DECL_HANDLER(new_process)
|
||||||
{
|
{
|
||||||
struct startup_info *info;
|
struct startup_info *info;
|
||||||
|
|
||||||
if (current->info)
|
|
||||||
{
|
|
||||||
fatal_protocol_error( current, "new_process: another process is being created\n" );
|
|
||||||
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->inherit_all = req->inherit_all;
|
||||||
info->use_handles = req->use_handles;
|
info->use_handles = req->use_handles;
|
||||||
info->create_flags = req->create_flags;
|
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;
|
||||||
|
@ -905,7 +915,6 @@ DECL_HANDLER(new_process)
|
||||||
|
|
||||||
if (!(info->data = mem_alloc( info->data_size ))) goto done;
|
if (!(info->data = mem_alloc( info->data_size ))) goto done;
|
||||||
memcpy( info->data, get_req_data(), info->data_size );
|
memcpy( info->data, get_req_data(), info->data_size );
|
||||||
current->info = info;
|
|
||||||
reply->info = alloc_handle( current->process, info, SYNCHRONIZE, FALSE );
|
reply->info = alloc_handle( current->process, info, SYNCHRONIZE, FALSE );
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -972,7 +981,7 @@ DECL_HANDLER(init_process)
|
||||||
}
|
}
|
||||||
reply->info_size = 0;
|
reply->info_size = 0;
|
||||||
current->process->ldt_copy = req->ldt_copy;
|
current->process->ldt_copy = req->ldt_copy;
|
||||||
current->process->startup_info = init_process( req->ppid, reply );
|
current->process->startup_info = init_process( reply );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* signal the end of the process initialization */
|
/* signal the end of the process initialization */
|
||||||
|
|
|
@ -199,6 +199,7 @@ typedef struct
|
||||||
int inherit_all; /* inherit all handles from parent */
|
int inherit_all; /* inherit all handles from parent */
|
||||||
int use_handles; /* use stdio handles */
|
int use_handles; /* use stdio handles */
|
||||||
int create_flags; /* creation flags */
|
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 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 */
|
||||||
|
@ -243,7 +244,6 @@ typedef struct
|
||||||
/* Initialize a process; called from the new process context */
|
/* Initialize a process; called from the new process context */
|
||||||
@REQ(init_process)
|
@REQ(init_process)
|
||||||
void* ldt_copy; /* addr of LDT copy */
|
void* ldt_copy; /* addr of LDT copy */
|
||||||
int ppid; /* parent Unix pid */
|
|
||||||
@REPLY
|
@REPLY
|
||||||
int create_flags; /* creation flags */
|
int create_flags; /* creation flags */
|
||||||
unsigned int server_start; /* server start time (GetTickCount) */
|
unsigned int server_start; /* server start time (GetTickCount) */
|
||||||
|
|
|
@ -116,7 +116,6 @@ inline static void init_thread_structure( struct thread *thread )
|
||||||
thread->debug_event = NULL;
|
thread->debug_event = NULL;
|
||||||
thread->queue = NULL;
|
thread->queue = NULL;
|
||||||
thread->hooks = NULL;
|
thread->hooks = NULL;
|
||||||
thread->info = NULL;
|
|
||||||
thread->wait = NULL;
|
thread->wait = NULL;
|
||||||
thread->system_apc.head = NULL;
|
thread->system_apc.head = NULL;
|
||||||
thread->system_apc.tail = NULL;
|
thread->system_apc.tail = NULL;
|
||||||
|
@ -243,7 +242,6 @@ static void destroy_thread( struct object *obj )
|
||||||
if (thread->prev) thread->prev->next = thread->next;
|
if (thread->prev) thread->prev->next = thread->next;
|
||||||
else first_thread = thread->next;
|
else first_thread = thread->next;
|
||||||
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
|
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
|
||||||
if (thread->info) release_object( thread->info );
|
|
||||||
cleanup_thread( thread );
|
cleanup_thread( thread );
|
||||||
release_object( thread->process );
|
release_object( thread->process );
|
||||||
if (thread->id) free_ptid( thread->id );
|
if (thread->id) free_ptid( thread->id );
|
||||||
|
|
|
@ -31,7 +31,6 @@ struct thread_apc;
|
||||||
struct mutex;
|
struct mutex;
|
||||||
struct debug_ctx;
|
struct debug_ctx;
|
||||||
struct debug_event;
|
struct debug_event;
|
||||||
struct startup_info;
|
|
||||||
struct msg_queue;
|
struct msg_queue;
|
||||||
struct hook_table;
|
struct hook_table;
|
||||||
|
|
||||||
|
@ -69,7 +68,6 @@ struct thread
|
||||||
struct debug_event *debug_event; /* debug event being sent to debugger */
|
struct debug_event *debug_event; /* debug event being sent to debugger */
|
||||||
struct msg_queue *queue; /* message queue */
|
struct msg_queue *queue; /* message queue */
|
||||||
struct hook_table *hooks; /* hooks table */
|
struct hook_table *hooks; /* hooks table */
|
||||||
struct startup_info *info; /* startup info for child process */
|
|
||||||
struct thread_wait *wait; /* current wait condition if sleeping */
|
struct thread_wait *wait; /* current wait condition if sleeping */
|
||||||
struct apc_queue system_apc; /* queue of system async procedure calls */
|
struct apc_queue system_apc; /* queue of system async procedure calls */
|
||||||
struct apc_queue user_apc; /* queue of user async procedure calls */
|
struct apc_queue user_apc; /* queue of user async procedure calls */
|
||||||
|
|
|
@ -354,6 +354,7 @@ 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, " use_handles=%d,", req->use_handles );
|
fprintf( stderr, " use_handles=%d,", req->use_handles );
|
||||||
fprintf( stderr, " create_flags=%d,", req->create_flags );
|
fprintf( stderr, " create_flags=%d,", req->create_flags );
|
||||||
|
fprintf( stderr, " unix_pid=%d,", req->unix_pid );
|
||||||
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 );
|
||||||
|
@ -403,8 +404,7 @@ static void dump_boot_done_request( const struct boot_done_request *req )
|
||||||
|
|
||||||
static void dump_init_process_request( const struct init_process_request *req )
|
static void dump_init_process_request( const struct init_process_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " ldt_copy=%p,", req->ldt_copy );
|
fprintf( stderr, " ldt_copy=%p", req->ldt_copy );
|
||||||
fprintf( stderr, " ppid=%d", req->ppid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_init_process_reply( const struct init_process_reply *req )
|
static void dump_init_process_reply( const struct init_process_reply *req )
|
||||||
|
|
Loading…
Reference in New Issue