diff --git a/dlls/kernel/debugger.c b/dlls/kernel/debugger.c index 6dc274ab2db..0db2981bedb 100644 --- a/dlls/kernel/debugger.c +++ b/dlls/kernel/debugger.c @@ -31,82 +31,92 @@ BOOL WINAPI WaitForDebugEvent( DWORD timeout /* Number of milliseconds to wait for event. */) { BOOL ret; - SERVER_START_REQ + DWORD res; + + for (;;) { - debug_event_t *data; - struct wait_debug_event_request *req = server_alloc_req( sizeof(*req), sizeof(*data) ); - - req->timeout = timeout; - if (!(ret = !server_call( REQ_WAIT_DEBUG_EVENT ))) goto done; - - if (!server_data_size(req)) /* timeout */ + HANDLE wait = 0; + SERVER_START_REQ { - SetLastError( ERROR_SEM_TIMEOUT ); - ret = FALSE; - goto done; + debug_event_t *data; + struct wait_debug_event_request *req = server_alloc_req( sizeof(*req), sizeof(*data) ); + + req->get_handle = (timeout != 0); + if (!(ret = !server_call( REQ_WAIT_DEBUG_EVENT ))) goto done; + + if (!server_data_size(req)) /* timeout */ + { + wait = req->wait; + ret = FALSE; + goto done; + } + data = server_data_ptr(req); + event->dwDebugEventCode = data->code; + event->dwProcessId = (DWORD)req->pid; + event->dwThreadId = (DWORD)req->tid; + switch(data->code) + { + case EXCEPTION_DEBUG_EVENT: + event->u.Exception.ExceptionRecord = data->info.exception.record; + event->u.Exception.dwFirstChance = data->info.exception.first; + break; + case CREATE_THREAD_DEBUG_EVENT: + event->u.CreateThread.hThread = data->info.create_thread.handle; + event->u.CreateThread.lpThreadLocalBase = data->info.create_thread.teb; + event->u.CreateThread.lpStartAddress = data->info.create_thread.start; + break; + case CREATE_PROCESS_DEBUG_EVENT: + event->u.CreateProcessInfo.hFile = data->info.create_process.file; + event->u.CreateProcessInfo.hProcess = data->info.create_process.process; + event->u.CreateProcessInfo.hThread = data->info.create_process.thread; + event->u.CreateProcessInfo.lpBaseOfImage = data->info.create_process.base; + event->u.CreateProcessInfo.dwDebugInfoFileOffset = data->info.create_process.dbg_offset; + event->u.CreateProcessInfo.nDebugInfoSize = data->info.create_process.dbg_size; + event->u.CreateProcessInfo.lpThreadLocalBase = data->info.create_process.teb; + event->u.CreateProcessInfo.lpStartAddress = data->info.create_process.start; + event->u.CreateProcessInfo.lpImageName = data->info.create_process.name; + event->u.CreateProcessInfo.fUnicode = data->info.create_process.unicode; + if (data->info.create_process.file == -1) event->u.CreateProcessInfo.hFile = 0; + break; + case EXIT_THREAD_DEBUG_EVENT: + event->u.ExitThread.dwExitCode = data->info.exit.exit_code; + break; + case EXIT_PROCESS_DEBUG_EVENT: + event->u.ExitProcess.dwExitCode = data->info.exit.exit_code; + break; + case LOAD_DLL_DEBUG_EVENT: + event->u.LoadDll.hFile = data->info.load_dll.handle; + event->u.LoadDll.lpBaseOfDll = data->info.load_dll.base; + event->u.LoadDll.dwDebugInfoFileOffset = data->info.load_dll.dbg_offset; + event->u.LoadDll.nDebugInfoSize = data->info.load_dll.dbg_size; + event->u.LoadDll.lpImageName = data->info.load_dll.name; + event->u.LoadDll.fUnicode = data->info.load_dll.unicode; + if (data->info.load_dll.handle == -1) event->u.LoadDll.hFile = 0; + break; + case UNLOAD_DLL_DEBUG_EVENT: + event->u.UnloadDll.lpBaseOfDll = data->info.unload_dll.base; + break; + case OUTPUT_DEBUG_STRING_EVENT: + event->u.DebugString.lpDebugStringData = data->info.output_string.string; + event->u.DebugString.fUnicode = data->info.output_string.unicode; + event->u.DebugString.nDebugStringLength = data->info.output_string.length; + break; + case RIP_EVENT: + event->u.RipInfo.dwError = data->info.rip_info.error; + event->u.RipInfo.dwType = data->info.rip_info.type; + break; + } + done: } - data = server_data_ptr(req); - event->dwDebugEventCode = data->code; - event->dwProcessId = (DWORD)req->pid; - event->dwThreadId = (DWORD)req->tid; - switch(data->code) - { - case EXCEPTION_DEBUG_EVENT: - event->u.Exception.ExceptionRecord = data->info.exception.record; - event->u.Exception.dwFirstChance = data->info.exception.first; - break; - case CREATE_THREAD_DEBUG_EVENT: - event->u.CreateThread.hThread = data->info.create_thread.handle; - event->u.CreateThread.lpThreadLocalBase = data->info.create_thread.teb; - event->u.CreateThread.lpStartAddress = data->info.create_thread.start; - break; - case CREATE_PROCESS_DEBUG_EVENT: - event->u.CreateProcessInfo.hFile = data->info.create_process.file; - event->u.CreateProcessInfo.hProcess = data->info.create_process.process; - event->u.CreateProcessInfo.hThread = data->info.create_process.thread; - event->u.CreateProcessInfo.lpBaseOfImage = data->info.create_process.base; - event->u.CreateProcessInfo.dwDebugInfoFileOffset = data->info.create_process.dbg_offset; - event->u.CreateProcessInfo.nDebugInfoSize = data->info.create_process.dbg_size; - event->u.CreateProcessInfo.lpThreadLocalBase = data->info.create_process.teb; - event->u.CreateProcessInfo.lpStartAddress = data->info.create_process.start; - event->u.CreateProcessInfo.lpImageName = data->info.create_process.name; - event->u.CreateProcessInfo.fUnicode = data->info.create_process.unicode; - if (data->info.create_process.file == -1) event->u.CreateProcessInfo.hFile = 0; - break; - case EXIT_THREAD_DEBUG_EVENT: - event->u.ExitThread.dwExitCode = data->info.exit.exit_code; - break; - case EXIT_PROCESS_DEBUG_EVENT: - event->u.ExitProcess.dwExitCode = data->info.exit.exit_code; - break; - case LOAD_DLL_DEBUG_EVENT: - event->u.LoadDll.hFile = data->info.load_dll.handle; - event->u.LoadDll.lpBaseOfDll = data->info.load_dll.base; - event->u.LoadDll.dwDebugInfoFileOffset = data->info.load_dll.dbg_offset; - event->u.LoadDll.nDebugInfoSize = data->info.load_dll.dbg_size; - event->u.LoadDll.lpImageName = data->info.load_dll.name; - event->u.LoadDll.fUnicode = data->info.load_dll.unicode; - if (data->info.load_dll.handle == -1) event->u.LoadDll.hFile = 0; - break; - case UNLOAD_DLL_DEBUG_EVENT: - event->u.UnloadDll.lpBaseOfDll = data->info.unload_dll.base; - break; - case OUTPUT_DEBUG_STRING_EVENT: - event->u.DebugString.lpDebugStringData = data->info.output_string.string; - event->u.DebugString.fUnicode = data->info.output_string.unicode; - event->u.DebugString.nDebugStringLength = data->info.output_string.length; - break; - case RIP_EVENT: - event->u.RipInfo.dwError = data->info.rip_info.error; - event->u.RipInfo.dwType = data->info.rip_info.type; - break; - default: - server_protocol_error( "WaitForDebugEvent: bad code %d\n", data->code ); - } - done: + SERVER_END_REQ; + if (ret) return TRUE; + if (!wait) break; + res = WaitForSingleObject( wait, timeout ); + CloseHandle( wait ); + if (res != STATUS_WAIT_0) break; } - SERVER_END_REQ; - return ret; + SetLastError( ERROR_SEM_TIMEOUT ); + return FALSE; } diff --git a/include/server.h b/include/server.h index 90bbca058d3..a1fa6cdf928 100644 --- a/include/server.h +++ b/include/server.h @@ -131,18 +131,18 @@ struct new_process_request IN handle_t hstdout; /* handle for stdout */ IN handle_t hstderr; /* handle for stderr */ IN int cmd_show; /* main window show mode */ + OUT handle_t info; /* new process info handle */ IN VARARG(filename,string); /* file name of main exe */ }; -/* Wait for the new process to start */ -struct wait_process_request +/* Retrieve information about a newly started process */ +struct get_new_process_info_request { REQUEST_HEADER; /* request header */ + IN handle_t info; /* info handle returned from new_process_request */ IN int pinherit; /* process handle inherit flag */ IN int tinherit; /* thread handle inherit flag */ - IN int timeout; /* wait timeout */ - IN int cancel; /* cancel the process creation? */ OUT void* pid; /* process id */ OUT handle_t phandle; /* process handle (in the current process) */ OUT void* tid; /* thread id */ @@ -930,9 +930,10 @@ struct next_module_request struct wait_debug_event_request { REQUEST_HEADER; /* request header */ - IN int timeout; /* timeout in ms */ + IN int get_handle; /* should we alloc a handle for waiting? */ OUT void* pid; /* process id */ OUT void* tid; /* thread id */ + OUT handle_t wait; /* wait handle if no event ready */ OUT VARARG(event,debug_event); /* debug event data */ }; @@ -1356,7 +1357,7 @@ struct async_result_request enum request { REQ_NEW_PROCESS, - REQ_WAIT_PROCESS, + REQ_GET_NEW_PROCESS_INFO, REQ_NEW_THREAD, REQ_BOOT_DONE, REQ_INIT_PROCESS, @@ -1471,7 +1472,7 @@ union generic_request struct request_max_size max_size; struct request_header header; struct new_process_request new_process; - struct wait_process_request wait_process; + struct get_new_process_info_request get_new_process_info; struct new_thread_request new_thread; struct boot_done_request boot_done; struct init_process_request init_process; @@ -1580,7 +1581,7 @@ union generic_request struct async_result_request async_result; }; -#define SERVER_PROTOCOL_VERSION 34 +#define SERVER_PROTOCOL_VERSION 35 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ diff --git a/scheduler/process.c b/scheduler/process.c index f1faaa3b6fd..091bb86ee21 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -743,6 +743,7 @@ BOOL PROCESS_Create( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env, const char *unixdir = NULL; DOS_FULL_NAME full_dir, full_name; HANDLE load_done_evt = 0; + HANDLE process_info; info->hThread = info->hProcess = 0; @@ -797,6 +798,7 @@ BOOL PROCESS_Create( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env, lstrcpynA( server_data_ptr(req), filename, MAX_PATH ); } ret = !server_call( REQ_NEW_PROCESS ); + process_info = req->info; } SERVER_END_REQ; if (!ret) return FALSE; @@ -805,24 +807,30 @@ BOOL PROCESS_Create( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env, pid = fork_and_exec( unixfilename, cmd_line, env, unixdir ); - SERVER_START_REQ + /* wait for the new process info to be ready */ + + ret = FALSE; + if ((pid != -1) && (WaitForSingleObject( process_info, 2000 ) == STATUS_WAIT_0)) { - struct wait_process_request *req = server_alloc_req( sizeof(*req), 0 ); - req->cancel = (pid == -1); - req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle); - req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle); - req->timeout = 2000; - if ((ret = !server_call( REQ_WAIT_PROCESS )) && (pid != -1)) + SERVER_START_REQ { - info->dwProcessId = (DWORD)req->pid; - info->dwThreadId = (DWORD)req->tid; - info->hProcess = req->phandle; - info->hThread = req->thandle; - load_done_evt = req->event; + struct get_new_process_info_request *req = server_alloc_req( sizeof(*req), 0 ); + req->info = process_info; + req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle); + req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle); + if ((ret = !server_call( REQ_GET_NEW_PROCESS_INFO ))) + { + info->dwProcessId = (DWORD)req->pid; + info->dwThreadId = (DWORD)req->tid; + info->hProcess = req->phandle; + info->hThread = req->thandle; + load_done_evt = req->event; + } } + SERVER_END_REQ; } - SERVER_END_REQ; - if (!ret || (pid == -1)) goto error; + CloseHandle( process_info ); + if (!ret) goto error; /* Wait until process is initialized (or initialization failed) */ if (load_done_evt) diff --git a/server/debugger.c b/server/debugger.c index 32ca8d542a7..5edee7f4489 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -241,37 +241,6 @@ static struct debug_event *find_event_to_send( struct debug_ctx *debug_ctx ) return event; } -/* build a reply for the wait_debug_event request */ -static void build_wait_debug_reply( struct thread *thread, struct object *obj, int signaled ) -{ - struct wait_debug_event_request *req = get_req_ptr( thread ); - - if (obj) - { - struct debug_ctx *debug_ctx = (struct debug_ctx *)obj; - struct debug_event *event = find_event_to_send( debug_ctx ); - size_t size = get_req_data_size(req); - - /* the object that woke us has to be our debug context */ - assert( obj->ops == &debug_ctx_ops ); - assert( event ); - - event->state = EVENT_SENT; - event->sender->debug_event = event; - req->pid = event->sender->process; - req->tid = event->sender; - if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t); - memcpy( get_req_data(req), &event->data, size ); - set_req_data_size( req, size ); - } - else /* timeout or error */ - { - set_req_data_size( req, 0 ); - req->pid = 0; - req->tid = 0; - } -} - /* build a reply for the send_event request */ static void build_exception_event_reply( struct thread *thread, struct object *obj, int signaled ) { @@ -357,29 +326,6 @@ static void debug_ctx_destroy( struct object *obj ) while ((event = debug_ctx->event_head) != NULL) unlink_event( debug_ctx, event ); } -/* wait for a debug event (or send a reply at once if one is pending) */ -static int wait_for_debug_event( int timeout ) -{ - struct debug_ctx *debug_ctx = current->debug_ctx; - struct object *obj = &debug_ctx->obj; - int flags = 0; - struct timeval tv; - - if (!debug_ctx) /* current thread is not a debugger */ - { - set_error( STATUS_INVALID_HANDLE ); - return 0; - } - if (timeout != -1) - { - flags = SELECT_TIMEOUT; - gettimeofday( &tv, 0 ); - add_timeout( &tv, timeout ); - } - else tv.tv_sec = tv.tv_usec = 0; - return sleep_on( 1, &obj, flags, tv.tv_sec, tv.tv_usec, build_wait_debug_reply ); -} - /* continue a debug event */ static int continue_debug_event( struct process *process, struct thread *thread, int status ) { @@ -539,11 +485,33 @@ void debug_exit_thread( struct thread *thread ) /* Wait for a debug event */ DECL_HANDLER(wait_debug_event) { - if (!wait_for_debug_event( req->timeout )) + struct debug_ctx *debug_ctx = current->debug_ctx; + struct debug_event *event; + + if (!debug_ctx) /* current thread is not a debugger */ { - req->pid = NULL; - req->tid = NULL; + set_error( STATUS_INVALID_HANDLE ); + return; + } + req->wait = 0; + if ((event = find_event_to_send( debug_ctx ))) + { + size_t size = get_req_data_size(req); + event->state = EVENT_SENT; + event->sender->debug_event = event; + req->pid = event->sender->process; + req->tid = event->sender; + if (size > sizeof(debug_event_t)) size = sizeof(debug_event_t); + memcpy( get_req_data(req), &event->data, size ); + set_req_data_size( req, size ); + } + else /* no event ready */ + { + req->pid = 0; + req->tid = 0; set_req_data_size( req, 0 ); + if (req->get_handle) + req->wait = alloc_handle( current->process, debug_ctx, SYNCHRONIZE, FALSE ); } } diff --git a/server/process.c b/server/process.c index bab104333b1..cd5889c5041 100644 --- a/server/process.c +++ b/server/process.c @@ -68,6 +68,7 @@ struct startup_info int cmd_show; /* main window show mode */ struct file *exe_file; /* file handle for main exe */ char *filename; /* file name 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 */ }; @@ -319,6 +320,11 @@ static void startup_info_destroy( struct object *obj ) 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) + { + info->owner->info = NULL; + release_object( info->owner ); + } } static void startup_info_dump( struct object *obj, int verbose ) @@ -337,33 +343,6 @@ static int startup_info_signaled( struct object *obj, struct thread *thread ) } -/* build a reply for the wait_process request */ -static void build_wait_process_reply( struct thread *thread, struct object *obj, int signaled ) -{ - struct wait_process_request *req = get_req_ptr( thread ); - if (obj) - { - struct startup_info *info = (struct startup_info *)obj; - assert( obj->ops == &startup_info_ops ); - - req->pid = get_process_id( info->process ); - req->tid = get_thread_id( info->thread ); - req->phandle = alloc_handle( thread->process, info->process, - PROCESS_ALL_ACCESS, req->pinherit ); - req->thandle = alloc_handle( thread->process, info->thread, - THREAD_ALL_ACCESS, req->tinherit ); - if (info->process->init_event) - req->event = alloc_handle( thread->process, info->process->init_event, - EVENT_ALL_ACCESS, 0 ); - else - req->event = 0; - - /* FIXME: set_error */ - } - release_object( thread->info ); - thread->info = NULL; -} - /* get a process from an id (and increment the refcount) */ struct process *get_process_from_id( void *id ) { @@ -731,52 +710,52 @@ DECL_HANDLER(new_process) info->cmd_show = req->cmd_show; info->exe_file = NULL; info->filename = NULL; + info->owner = (struct thread *)grab_object( current ); info->process = NULL; info->thread = NULL; if (req->exe_file && !(info->exe_file = get_file_obj( current->process, req->exe_file, GENERIC_READ ))) - { - release_object( info ); - return; - } + goto done; + + if (!(info->filename = mem_alloc( len + 1 ))) goto done; - if (!(info->filename = mem_alloc( len + 1 ))) - { - release_object( info ); - return; - } memcpy( info->filename, get_req_data(req), len ); info->filename[len] = 0; current->info = info; + req->info = alloc_handle( current->process, info, SYNCHRONIZE, FALSE ); + + done: + release_object( info ); } -/* Wait for the new process to start */ -DECL_HANDLER(wait_process) +/* Retrieve information about a newly started process */ +DECL_HANDLER(get_new_process_info) { - if (!current->info) + struct startup_info *info; + + req->event = 0; + + if ((info = (struct startup_info *)get_handle_obj( current->process, req->info, + 0, &startup_info_ops ))) { - fatal_protocol_error( current, "wait_process: no process is being created\n" ); - return; - } - req->pid = 0; - req->tid = 0; - req->phandle = 0; - req->thandle = 0; - req->event = 0; - if (req->cancel) - { - release_object( current->info ); - current->info = NULL; + req->pid = get_process_id( info->process ); + req->tid = get_thread_id( info->thread ); + req->phandle = alloc_handle( current->process, info->process, + PROCESS_ALL_ACCESS, req->pinherit ); + req->thandle = alloc_handle( current->process, info->thread, + THREAD_ALL_ACCESS, req->tinherit ); + if (info->process->init_event) + req->event = alloc_handle( current->process, info->process->init_event, + EVENT_ALL_ACCESS, 0 ); + release_object( info ); } else { - struct timeval timeout; - struct object *obj = ¤t->info->obj; - gettimeofday( &timeout, 0 ); - add_timeout( &timeout, req->timeout ); - sleep_on( 1, &obj, SELECT_TIMEOUT, timeout.tv_sec, timeout.tv_usec, - build_wait_process_reply ); + req->pid = 0; + req->tid = 0; + req->phandle = 0; + req->thandle = 0; } } diff --git a/server/request.h b/server/request.h index 6383cb11f54..4c627a83e81 100644 --- a/server/request.h +++ b/server/request.h @@ -71,7 +71,7 @@ inline static void set_req_data_size( const void *req, size_t size ) /* ### make_requests begin ### */ DECL_HANDLER(new_process); -DECL_HANDLER(wait_process); +DECL_HANDLER(get_new_process_info); DECL_HANDLER(new_thread); DECL_HANDLER(boot_done); DECL_HANDLER(init_process); @@ -185,7 +185,7 @@ typedef void (*req_handler)( void *req ); static const req_handler req_handlers[REQ_NB_REQUESTS] = { (req_handler)req_new_process, - (req_handler)req_wait_process, + (req_handler)req_get_new_process_info, (req_handler)req_new_thread, (req_handler)req_boot_done, (req_handler)req_init_process, diff --git a/server/trace.c b/server/trace.c index 76c7bdf0a11..677960155d8 100644 --- a/server/trace.c +++ b/server/trace.c @@ -275,15 +275,19 @@ static void dump_new_process_request( const struct new_process_request *req ) cur_pos += dump_varargs_string( req ); } -static void dump_wait_process_request( const struct wait_process_request *req ) +static void dump_new_process_reply( const struct new_process_request *req ) { - fprintf( stderr, " pinherit=%d,", req->pinherit ); - fprintf( stderr, " tinherit=%d,", req->tinherit ); - fprintf( stderr, " timeout=%d,", req->timeout ); - fprintf( stderr, " cancel=%d", req->cancel ); + fprintf( stderr, " info=%d", req->info ); } -static void dump_wait_process_reply( const struct wait_process_request *req ) +static void dump_get_new_process_info_request( const struct get_new_process_info_request *req ) +{ + fprintf( stderr, " info=%d,", req->info ); + fprintf( stderr, " pinherit=%d,", req->pinherit ); + fprintf( stderr, " tinherit=%d", req->tinherit ); +} + +static void dump_get_new_process_info_reply( const struct get_new_process_info_request *req ) { fprintf( stderr, " pid=%p,", req->pid ); fprintf( stderr, " phandle=%d,", req->phandle ); @@ -1050,13 +1054,14 @@ static void dump_next_module_reply( const struct next_module_request *req ) static void dump_wait_debug_event_request( const struct wait_debug_event_request *req ) { - fprintf( stderr, " timeout=%d", req->timeout ); + fprintf( stderr, " get_handle=%d", req->get_handle ); } static void dump_wait_debug_event_reply( const struct wait_debug_event_request *req ) { fprintf( stderr, " pid=%p,", req->pid ); fprintf( stderr, " tid=%p,", req->tid ); + fprintf( stderr, " wait=%d,", req->wait ); fprintf( stderr, " event=" ); cur_pos += dump_varargs_debug_event( req ); } @@ -1474,7 +1479,7 @@ static void dump_async_result_request( const struct async_result_request *req ) static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, - (dump_func)dump_wait_process_request, + (dump_func)dump_get_new_process_info_request, (dump_func)dump_new_thread_request, (dump_func)dump_boot_done_request, (dump_func)dump_init_process_request, @@ -1584,8 +1589,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { - (dump_func)0, - (dump_func)dump_wait_process_reply, + (dump_func)dump_new_process_reply, + (dump_func)dump_get_new_process_info_reply, (dump_func)dump_new_thread_reply, (dump_func)0, (dump_func)dump_init_process_reply, @@ -1696,7 +1701,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { static const char * const req_names[REQ_NB_REQUESTS] = { "new_process", - "wait_process", + "get_new_process_info", "new_thread", "boot_done", "init_process",