From 9d802152541eaef4ffe65445e691cdaa47e3e46b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 24 May 2002 21:20:27 +0000 Subject: [PATCH] A few optimizations in the process startup requests now that Winelib apps are started differently from Unix ones. --- include/wine/server_protocol.h | 7 +-- memory/environ.c | 5 +- scheduler/process.c | 74 +++++++++-------------- server/debugger.c | 4 +- server/process.c | 104 +++++++++++++++++---------------- server/process.h | 6 +- server/protocol.def | 5 +- server/ptrace.c | 4 +- server/trace.c | 5 +- 9 files changed, 94 insertions(+), 120 deletions(-) diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index ddc2afde232..1f4445245aa 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -214,7 +214,7 @@ struct get_new_process_info_reply handle_t phandle; void* tid; handle_t thandle; - handle_t event; + int success; }; @@ -258,7 +258,6 @@ struct init_process_reply struct reply_header __header; int create_flags; unsigned int server_start; - handle_t info; size_t info_size; handle_t exe_file; handle_t hstdin; @@ -271,8 +270,6 @@ struct init_process_reply struct get_startup_info_request { struct request_header __header; - handle_t info; - int close; }; struct get_startup_info_reply { @@ -3198,6 +3195,6 @@ union generic_reply struct get_window_properties_reply get_window_properties_reply; }; -#define SERVER_PROTOCOL_VERSION 79 +#define SERVER_PROTOCOL_VERSION 80 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/memory/environ.c b/memory/environ.c index da2ab4b7874..8fa917a6eca 100644 --- a/memory/environ.c +++ b/memory/environ.c @@ -201,8 +201,7 @@ inline static char *copy_str( char **dst, const char **src, size_t len ) * * Fill the startup info structure from the server. */ -ENVDB *ENV_InitStartupInfo( handle_t info_handle, size_t info_size, - char *main_exe_name, size_t main_exe_size ) +ENVDB *ENV_InitStartupInfo( size_t info_size, char *main_exe_name, size_t main_exe_size ) { startup_info_t info; void *data; @@ -217,8 +216,6 @@ ENVDB *ENV_InitStartupInfo( handle_t info_handle, size_t info_size, SERVER_START_REQ( get_startup_info ) { - req->info = info_handle; - req->close = TRUE; wine_server_set_reply( req, data, info_size ); wine_server_call( req ); info_size = wine_server_reply_size( reply ); diff --git a/scheduler/process.c b/scheduler/process.c index e611b55b9b8..2d83fbc7b70 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -118,8 +118,8 @@ static int main_create_flags; static unsigned int server_startticks; /* memory/environ.c */ -extern struct _ENVDB *ENV_InitStartupInfo( handle_t info_handle, size_t info_size, - char *main_exe_name, size_t main_exe_size ); +extern struct _ENVDB *ENV_InitStartupInfo( size_t info_size, char *main_exe_name, + size_t main_exe_size ); extern BOOL ENV_BuildCommandLine( char **argv ); extern STARTUPINFOA current_startupinfo; @@ -358,7 +358,6 @@ static BOOL process_init( char *argv[] ) { BOOL ret; size_t info_size = 0; - handle_t info = 0; /* store the program name */ argv0 = argv[0]; @@ -384,7 +383,6 @@ static BOOL process_init( char *argv[] ) main_exe_file = reply->exe_file; main_create_flags = reply->create_flags; info_size = reply->info_size; - info = reply->info; server_startticks = reply->server_start; current_startupinfo.hStdInput = reply->hstdin; current_startupinfo.hStdOutput = reply->hstdout; @@ -420,12 +418,12 @@ static BOOL process_init( char *argv[] ) PTHREAD_init_done(); /* Copy the parent environment */ - if (!(current_process.env_db = ENV_InitStartupInfo( info, info_size, - main_exe_name, sizeof(main_exe_name) ))) + if (!(current_process.env_db = ENV_InitStartupInfo( info_size, main_exe_name, + sizeof(main_exe_name) ))) return FALSE; /* Parse command line arguments */ - OPTIONS_ParseOptions( !info ? argv : NULL ); + OPTIONS_ParseOptions( !info_size ? argv : NULL ); ret = MAIN_MainInit(); @@ -891,8 +889,7 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, LPPROCESS_INFORMATION info, LPCSTR unixdir ) { - BOOL ret; - HANDLE load_done_evt = 0; + BOOL ret, success = FALSE; HANDLE process_info; startup_info_t startup_info; @@ -965,48 +962,33 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST /* wait for the new process info to be ready */ - ret = TRUE; /* pretend success even if we don't get the new process info */ - if (WaitForSingleObject( process_info, 2000 ) == STATUS_WAIT_0) + WaitForSingleObject( process_info, INFINITE ); + SERVER_START_REQ( get_new_process_info ) { - SERVER_START_REQ( get_new_process_info ) + req->info = process_info; + req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle); + req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle); + if ((ret = !wine_server_call_err( req ))) { - req->info = process_info; - req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle); - req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle); - 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; - load_done_evt = reply->event; - } + info->dwProcessId = (DWORD)reply->pid; + info->dwThreadId = (DWORD)reply->tid; + info->hProcess = reply->phandle; + info->hThread = reply->thandle; + success = reply->success; } - SERVER_END_REQ; + } + SERVER_END_REQ; + + if (ret && !success) /* new process failed to start */ + { + DWORD exitcode; + if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode ); + CloseHandle( info->hThread ); + CloseHandle( info->hProcess ); + ret = FALSE; } CloseHandle( process_info ); - if (!ret) return FALSE; - - /* Wait until process is initialized (or initialization failed) */ - if (load_done_evt) - { - DWORD res; - HANDLE handles[2]; - - handles[0] = info->hProcess; - handles[1] = load_done_evt; - res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE ); - CloseHandle( load_done_evt ); - if (res == STATUS_WAIT_0) /* the process died */ - { - DWORD exitcode; - if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode ); - CloseHandle( info->hThread ); - CloseHandle( info->hProcess ); - return FALSE; - } - } - return TRUE; + return ret; } diff --git a/server/debugger.c b/server/debugger.c index fa2c080ed02..dcf7e0ffe2a 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -427,7 +427,7 @@ static int debugger_attach( struct process *process, struct thread *debugger ) struct thread *thread; if (process->debugger) goto error; /* already being debugged */ - if (process->init_event) goto error; /* still starting up */ + if (!is_process_init_done( process )) goto error; /* still starting up */ if (!process->thread_list) goto error; /* no thread running in the process */ /* make sure we don't create a debugging loop */ @@ -470,7 +470,7 @@ int debugger_detach( struct process *process, struct thread *debugger ) goto error; /* not currently debugged, or debugged by another debugger */ if (!debugger->debug_ctx ) goto error; /* should be a debugger */ /* init should be done, otherwise wouldn't be attached */ - assert(!process->init_event); + assert(is_process_init_done(process)); suspend_process( process ); /* send continue indication for all events */ diff --git a/server/process.c b/server/process.c index 55cd67e4fd2..9368a81fb64 100644 --- a/server/process.c +++ b/server/process.c @@ -74,9 +74,12 @@ static const struct object_ops process_ops = /* process startup info */ +enum startup_state { STARTUP_IN_PROGRESS, STARTUP_DONE, STARTUP_ABORTED }; + struct startup_info { struct object obj; /* object header */ + enum startup_state state; /* child process startup state */ int inherit_all; /* inherit all handles from parent */ int use_handles; /* use stdio handles */ int create_flags; /* creation flags */ @@ -113,6 +116,16 @@ static const struct object_ops startup_info_ops = }; +/* set the state of the process startup info */ +static void set_process_startup_state( struct process *process, enum startup_state state ) +{ + if (!process->startup_info) return; + process->startup_info->state = state; + wake_up( &process->startup_info->obj, 0 ); + release_object( process->startup_info ); + process->startup_info = NULL; +} + /* set the console and stdio handles for a newly created process */ static int set_process_console( struct process *process, struct thread *parent_thread, struct startup_info *info, struct init_process_reply *reply ) @@ -122,7 +135,7 @@ static int set_process_console( struct process *process, struct thread *parent_t /* let the process init do the allocation */ return 1; } - else if (parent_thread && !(process->create_flags & DETACHED_PROCESS)) + else if (info && !(process->create_flags & DETACHED_PROCESS)) { /* FIXME: some better error checking should be done... * like if hConOut and hConIn are console handles, then they should be on the same @@ -131,7 +144,7 @@ static int set_process_console( struct process *process, struct thread *parent_t inherit_console( parent_thread, process, (info->inherit_all || info->use_handles) ? info->hstdin : 0 ); } - if (parent_thread) + if (info) { if (!info->inherit_all && !info->use_handles) { @@ -193,7 +206,7 @@ struct thread *create_process( int fd ) process->suspend = 0; process->create_flags = 0; process->console = NULL; - process->init_event = NULL; + process->startup_info = NULL; process->idle_event = NULL; process->queue = NULL; process->atom_table = NULL; @@ -201,6 +214,7 @@ struct thread *create_process( int fd ) process->exe.next = NULL; process->exe.prev = NULL; process->exe.file = NULL; + process->exe.base = NULL; process->exe.dbg_offset = 0; process->exe.dbg_size = 0; process->exe.namelen = 0; @@ -210,9 +224,6 @@ struct thread *create_process( int fd ) if ((process->next = first_process) != NULL) process->next->prev = process; first_process = process; - /* create the init done event */ - if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error; - /* create the main thread */ if (pipe( request_pipe ) == -1) { @@ -245,12 +256,7 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r { parent = parent_thread->process; info = parent_thread->info; - if (!info) - { - fatal_protocol_error( current, "init_process: parent but no info\n" ); - return NULL; - } - if (info->thread) + if (info && info->thread) { fatal_protocol_error( current, "init_process: called twice?\n" ); return NULL; @@ -262,7 +268,7 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r process->create_flags = info ? info->create_flags : 0; /* create the handle table */ - if (parent && info->inherit_all) + if (info && info->inherit_all) process->handles = copy_handle_table( process, parent ); else process->handles = alloc_handle_table( process, 0 ); @@ -270,7 +276,7 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r /* retrieve the main exe file */ reply->exe_file = 0; - if (parent && info->exe_file) + if (info && info->exe_file) { process->exe.file = (struct file *)grab_object( info->exe_file ); if (!(reply->exe_file = alloc_handle( process, process->exe.file, GENERIC_READ, 0 ))) @@ -285,7 +291,7 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r /* 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 && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS)) + else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS)) set_process_debugger( process, parent->debugger ); } @@ -297,7 +303,6 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r reply->info_size = info->data_size; info->process = (struct process *)grab_object( process ); info->thread = (struct thread *)grab_object( current ); - wake_up( &info->obj, 0 ); } reply->create_flags = process->create_flags; reply->server_start = server_start_ticks; @@ -312,12 +317,13 @@ static void process_destroy( struct object *obj ) /* we can't have a thread remaining */ assert( !process->thread_list ); + + set_process_startup_state( process, STARTUP_ABORTED ); if (process->console) release_object( process->console ); if (process->parent) release_object( process->parent ); if (process->next) process->next->prev = process->prev; if (process->prev) process->prev->next = process->next; else first_process = process->next; - if (process->init_event) release_object( process->init_event ); if (process->idle_event) release_object( process->idle_event ); if (process->queue) release_object( process->queue ); if (process->atom_table) release_object( process->atom_table ); @@ -371,17 +377,16 @@ 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=%d out=%d err=%d\n", - info->create_flags, info->hstdin, info->hstdout, info->hstderr ); + fprintf( stderr, "Startup info flags=%x in=%d out=%d err=%d state=%d\n", + info->create_flags, info->hstdin, info->hstdout, info->hstderr, info->state ); } static int startup_info_signaled( struct object *obj, struct thread *thread ) { struct startup_info *info = (struct startup_info *)obj; - return (info->thread != NULL); + return info->state != STARTUP_IN_PROGRESS; } - /* get a process from an id (and increment the refcount) */ struct process *get_process_from_id( void *id ) { @@ -490,6 +495,7 @@ static void process_killed( struct process *process ) if (dll->filename) free( dll->filename ); free( dll ); } + set_process_startup_state( process, STARTUP_ABORTED ); if (process->exe.file) release_object( process->exe.file ); process->exe.file = NULL; wake_up( &process->obj, 0 ); @@ -776,6 +782,7 @@ DECL_HANDLER(new_process) /* build the startup info for a new process */ if (!(info = alloc_object( &startup_info_ops, -1 ))) return; + info->state = STARTUP_IN_PROGRESS; info->inherit_all = req->inherit_all; info->use_handles = req->use_handles; info->create_flags = req->create_flags; @@ -807,8 +814,6 @@ DECL_HANDLER(get_new_process_info) { struct startup_info *info; - reply->event = 0; - if ((info = (struct startup_info *)get_handle_obj( current->process, req->info, 0, &startup_info_ops ))) { @@ -818,9 +823,7 @@ DECL_HANDLER(get_new_process_info) PROCESS_ALL_ACCESS, req->pinherit ); reply->thandle = alloc_handle( current->process, info->thread, THREAD_ALL_ACCESS, req->tinherit ); - if (info->process->init_event) - reply->event = alloc_handle( current->process, info->process->init_event, - EVENT_ALL_ACCESS, 0 ); + reply->success = (info->state == STARTUP_DONE); release_object( info ); } else @@ -829,6 +832,7 @@ DECL_HANDLER(get_new_process_info) reply->tid = 0; reply->phandle = 0; reply->thandle = 0; + reply->success = 0; } } @@ -837,19 +841,15 @@ DECL_HANDLER(get_startup_info) { struct startup_info *info; - if ((info = (struct startup_info *)get_handle_obj( current->process, req->info, - 0, &startup_info_ops ))) + if ((info = current->process->startup_info)) { size_t size = info->data_size; if (size > get_reply_max_size()) size = get_reply_max_size(); - if (req->close) - { - set_reply_data_ptr( info->data, size ); - info->data = NULL; - close_handle( current->process, req->info, NULL ); - } - else set_reply_data( info->data, size ); - release_object( info ); + + /* we return the data directly without making a copy so this can only be called once */ + set_reply_data_ptr( info->data, size ); + info->data = NULL; + info->data_size = 0; } } @@ -857,21 +857,19 @@ DECL_HANDLER(get_startup_info) /* initialize a new process */ DECL_HANDLER(init_process) { - struct startup_info *info; - - reply->info = 0; - reply->info_size = 0; if (!current->unix_pid) { fatal_protocol_error( current, "init_process: init_thread not called yet\n" ); return; } - current->process->ldt_copy = req->ldt_copy; - if ((info = init_process( req->ppid, reply ))) + if (current->process->startup_info) { - reply->info = alloc_handle( current->process, info, 0, FALSE ); - release_object( info ); + fatal_protocol_error( current, "init_process: called twice\n" ); + return; } + reply->info_size = 0; + current->process->ldt_copy = req->ldt_copy; + current->process->startup_info = init_process( req->ppid, reply ); } /* signal the end of the process initialization */ @@ -880,9 +878,14 @@ DECL_HANDLER(init_process_done) struct file *file = NULL; struct process *process = current->process; - if (!process->init_event) + if (is_process_init_done(process)) { - fatal_protocol_error( current, "init_process_done: no event\n" ); + fatal_protocol_error( current, "init_process_done: called twice\n" ); + return; + } + if (!req->module) + { + fatal_protocol_error( current, "init_process_done: module base address cannot be 0\n" ); return; } process->exe.base = req->module; @@ -896,10 +899,9 @@ DECL_HANDLER(init_process_done) if ((process->exe.namelen = get_req_data_size())) process->exe.filename = memdup( get_req_data(), process->exe.namelen ); - generate_startup_debug_events( current->process, req->entry ); - set_event( process->init_event ); - release_object( process->init_event ); - process->init_event = NULL; + generate_startup_debug_events( process, req->entry ); + set_process_startup_state( process, STARTUP_DONE ); + if (req->gui) process->idle_event = create_event( NULL, 0, 1, 0 ); if (current->suspend + current->process->suspend > 0) stop_thread( current ); reply->debugged = (current->process->debugger != 0); @@ -1018,7 +1020,7 @@ DECL_HANDLER(load_dll) dll->dbg_size = req->dbg_size; dll->name = req->name; /* only generate event if initialization is done */ - if (!current->process->init_event) + if (is_process_init_done( current->process )) generate_debug_event( current, LOAD_DLL_DEBUG_EVENT, dll ); } if (file) release_object( file ); diff --git a/server/process.h b/server/process.h index 3e84c093efe..81a18e25803 100644 --- a/server/process.h +++ b/server/process.h @@ -25,6 +25,7 @@ struct msg_queue; struct atom_table; +struct startup_info; /* process structures */ @@ -60,7 +61,7 @@ struct process int suspend; /* global process suspend count */ int create_flags; /* process creation flags */ struct console_input*console; /* console input */ - struct event *init_event; /* event for init done */ + struct startup_info *startup_info; /* startup info while init is in progress */ struct event *idle_event; /* event for input idle */ struct msg_queue *queue; /* main message queue */ struct atom_table *atom_table; /* pointer to local atom table */ @@ -106,6 +107,7 @@ extern void detach_debugged_processes( struct thread *debugger ); extern struct process_snapshot *process_snap( int *count ); extern struct module_snapshot *module_snap( struct process *process, int *count ); -static inline void *get_process_id( struct process *process ) { return process; } +inline static void *get_process_id( struct process *process ) { return process; } +inline static int is_process_init_done( struct process *process ) { return process->exe.base != 0; } #endif /* __WINE_SERVER_PROCESS_H */ diff --git a/server/protocol.def b/server/protocol.def index e1d49c31646..7222b7ec982 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -220,7 +220,7 @@ typedef struct handle_t phandle; /* process handle (in the current process) */ void* tid; /* thread id */ handle_t thandle; /* thread handle (in the current process) */ - handle_t event; /* event handle to signal startup */ + int success; /* did the process start successfully? */ @END @@ -248,7 +248,6 @@ typedef struct @REPLY int create_flags; /* creation flags */ unsigned int server_start; /* server start time (GetTickCount) */ - handle_t info; /* handle to startup info */ size_t info_size; /* total size of startup info */ handle_t exe_file; /* file handle for main exe */ handle_t hstdin; /* handle for stdin */ @@ -259,8 +258,6 @@ typedef struct /* Retrieve the new process startup info */ @REQ(get_startup_info) - handle_t info; /* handle to startup info */ - int close; /* should we close the handle at the same time? */ @REPLY VARARG(info,startup_info); /* startup information */ @END diff --git a/server/ptrace.c b/server/ptrace.c index b66f02a57c7..7aa0c88a955 100644 --- a/server/ptrace.c +++ b/server/ptrace.c @@ -177,7 +177,7 @@ void detach_thread( struct thread *thread, int sig ) void stop_thread( struct thread *thread ) { /* can't stop a thread while initialisation is in progress */ - if (!thread->unix_pid || thread->process->init_event) return; + if (!thread->unix_pid || !is_process_init_done(thread->process)) return; /* first try to attach to it */ if (!thread->attached) if (attach_thread( thread )) return; /* this will have stopped it */ @@ -206,7 +206,7 @@ int suspend_for_ptrace( struct thread *thread ) return 1; } /* can't stop a thread while initialisation is in progress */ - if (!thread->unix_pid || thread->process->init_event) goto error; + if (!thread->unix_pid || !is_process_init_done(thread->process)) goto error; thread->suspend++; if (attach_thread( thread )) return 1; thread->suspend--; diff --git a/server/trace.c b/server/trace.c index d957856225f..f610d049cab 100644 --- a/server/trace.c +++ b/server/trace.c @@ -376,7 +376,7 @@ static void dump_get_new_process_info_reply( const struct get_new_process_info_r fprintf( stderr, " phandle=%d,", req->phandle ); fprintf( stderr, " tid=%p,", req->tid ); fprintf( stderr, " thandle=%d,", req->thandle ); - fprintf( stderr, " event=%d", req->event ); + fprintf( stderr, " success=%d", req->success ); } static void dump_new_thread_request( const struct new_thread_request *req ) @@ -407,7 +407,6 @@ static void dump_init_process_reply( const struct init_process_reply *req ) { fprintf( stderr, " create_flags=%d,", req->create_flags ); fprintf( stderr, " server_start=%08x,", req->server_start ); - fprintf( stderr, " info=%d,", req->info ); fprintf( stderr, " info_size=%d,", req->info_size ); fprintf( stderr, " exe_file=%d,", req->exe_file ); fprintf( stderr, " hstdin=%d,", req->hstdin ); @@ -417,8 +416,6 @@ static void dump_init_process_reply( const struct init_process_reply *req ) static void dump_get_startup_info_request( const struct get_startup_info_request *req ) { - fprintf( stderr, " info=%d,", req->info ); - fprintf( stderr, " close=%d", req->close ); } static void dump_get_startup_info_reply( const struct get_startup_info_reply *req )