Fixed handling of debug events on thread/process exit.
diff --git a/server/debugger.c b/server/debugger.c
index a7e1640..683270c 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -232,7 +232,7 @@
{
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 @@
/* (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 @@
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 @@
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 @@
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 @@
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)
{