Commit 17cf8101 authored by Alexandre Julliard's avatar Alexandre Julliard

Fixed handling of debug events on thread/process exit.

parent 6f1b6424
......@@ -232,7 +232,7 @@ static int continue_debug_event( struct process *process, struct thread *thread,
{
struct debug_event *event = thread->debug_event;
if (process->debugger != current || !event || !event->sent)
if (process->debugger != current || thread->process != process || !event || !event->sent)
{
/* not debugging this process, or no event pending */
set_error( ERROR_ACCESS_DENIED ); /* FIXME */
......@@ -244,9 +244,20 @@ static int continue_debug_event( struct process *process, struct thread *thread,
/* (we can get a continue on an exit thread/process event) */
struct send_debug_event_request *req = get_req_ptr( thread );
req->status = status;
/* copy the context into the reply */
if (event->code == EXCEPTION_DEBUG_EVENT)
memcpy( req + 1, &event->data, event_sizes[event->code] );
send_reply( thread );
}
free_event( current, event );
if (thread->exit_event)
{
/* we still have a queued exit event, promote it to normal event */
thread->debug_event = thread->exit_event;
thread->exit_event = NULL;
}
resume_process( process );
return 1;
}
......@@ -279,14 +290,13 @@ static struct debug_event *queue_debug_event( struct thread *debugger, struct th
if (thread->debug_event)
{
/* only exit events can replace others */
/* exit events can happen while another one is still queued */
assert( code == EXIT_THREAD_DEBUG_EVENT || code == EXIT_PROCESS_DEBUG_EVENT );
if (!thread->debug_event->sent) unlink_event( debug_ctx, thread->debug_event );
free_event( debugger, thread->debug_event );
thread->exit_event = event;
}
else thread->debug_event = event;
link_event( debug_ctx, event );
thread->debug_event = event;
suspend_process( thread->process );
if (debug_ctx->waiting)
{
......@@ -317,7 +327,6 @@ int debugger_attach( struct process *process, struct thread *debugger )
if (!debugger->debug_ctx) /* need to allocate a context */
{
assert( !debugger->debug_first );
if (!(debug_ctx = mem_alloc( sizeof(*debug_ctx) ))) return 0;
debug_ctx->owner = current;
debug_ctx->waiting = 0;
......@@ -326,44 +335,25 @@ int debugger_attach( struct process *process, struct thread *debugger )
debug_ctx->event_tail = NULL;
debugger->debug_ctx = debug_ctx;
}
process->debugger = debugger;
process->debug_prev = NULL;
process->debug_next = debugger->debug_first;
debugger->debug_first = process;
process->debugger = debugger;
return 1;
}
/* detach a process from its debugger thread */
static void debugger_detach( struct process *process )
{
struct thread *debugger = process->debugger;
assert( debugger );
if (process->debug_next) process->debug_next->debug_prev = process->debug_prev;
if (process->debug_prev) process->debug_prev->debug_next = process->debug_next;
else debugger->debug_first = process->debug_next;
process->debugger = NULL;
}
/* a thread is exiting */
void debug_exit_thread( struct thread *thread, int exit_code )
{
struct thread *debugger = current->process->debugger;
struct thread *debugger = thread->process->debugger;
struct debug_ctx *debug_ctx = thread->debug_ctx;
if (debugger) /* being debugged -> send an event to the debugger */
{
struct debug_event_exit event;
event.exit_code = exit_code;
if (!thread->proc_next && !thread->proc_prev)
{
assert( thread->process->thread_list == thread );
/* this is the last thread, send an exit process event and cleanup */
queue_debug_event( debugger, current, EXIT_PROCESS_DEBUG_EVENT, &event );
debugger_detach( thread->process );
}
else queue_debug_event( debugger, current, EXIT_THREAD_DEBUG_EVENT, &event );
if (thread->process->running_threads == 1)
/* this is the last thread, send an exit process event */
queue_debug_event( debugger, thread, EXIT_PROCESS_DEBUG_EVENT, &event );
else
queue_debug_event( debugger, thread, EXIT_THREAD_DEBUG_EVENT, &event );
}
if (debug_ctx) /* this thread is a debugger */
......@@ -371,7 +361,8 @@ void debug_exit_thread( struct thread *thread, int exit_code )
struct debug_event *event;
/* kill all debugged processes */
while (thread->debug_first) kill_process( thread->debug_first, exit_code );
kill_debugged_processes( thread, exit_code );
/* free all pending events */
while ((event = debug_ctx->event_head) != NULL)
{
......
......@@ -60,8 +60,6 @@ static struct process *create_process( struct process *parent, struct new_proces
process->next = NULL;
process->prev = NULL;
process->thread_list = NULL;
process->debug_next = NULL;
process->debug_prev = NULL;
process->debugger = NULL;
process->handles = NULL;
process->exit_code = 0x103; /* STILL_ACTIVE */
......@@ -292,6 +290,21 @@ void kill_process( struct process *process, int exit_code )
kill_thread( process->thread_list, exit_code );
}
/* kill all processes being debugged by a given thread */
void kill_debugged_processes( struct thread *debugger, int exit_code )
{
for (;;) /* restart from the beginning of the list every time */
{
struct process *process = first_process;
/* find the first process being debugged by 'debugger' and still running */
while (process && (process->debugger != debugger || !process->running_threads))
process = process->next;
if (!process) return;
process->debugger = NULL;
kill_process( process, exit_code );
}
}
/* get all information about a process */
static void get_process_info( struct process *process, struct get_process_info_request *req )
{
......
......@@ -21,8 +21,6 @@ struct process
struct process *next; /* system-wide process list */
struct process *prev;
struct thread *thread_list; /* head of the thread list */
struct process *debug_next; /* per-debugger process list */
struct process *debug_prev;
struct thread *debugger; /* thread debugging this process */
struct object *handles; /* handle entries */
int exit_code; /* process exit code */
......@@ -59,6 +57,7 @@ extern void remove_process_thread( struct process *process,
extern void suspend_process( struct process *process );
extern void resume_process( struct process *process );
extern void kill_process( struct process *process, int exit_code );
extern void kill_debugged_processes( struct thread *debugger, int exit_code );
extern struct process_snapshot *process_snap( int *count );
#endif /* __WINE_SERVER_PROCESS_H */
......@@ -112,8 +112,8 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
thread->teb = NULL;
thread->mutex = NULL;
thread->debug_ctx = NULL;
thread->debug_first = NULL;
thread->debug_event = NULL;
thread->exit_event = NULL;
thread->wait = NULL;
thread->apc = NULL;
thread->apc_count = 0;
......
......@@ -40,8 +40,8 @@ struct thread
struct process *process;
struct mutex *mutex; /* list of currently owned mutexes */
struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
struct process *debug_first; /* head of debugged processes list */
struct debug_event *debug_event; /* pending debug event for this thread */
struct debug_event *exit_event; /* pending debug exit event for this thread */
struct thread_wait *wait; /* current wait condition if sleeping */
struct thread_apc *apc; /* list of async procedure calls */
int apc_count; /* number of outstanding APCs */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment