From 17cf81018fc46ad51ff22dee5b9be03a68763d6a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 24 Nov 1999 01:22:14 +0000 Subject: [PATCH] Fixed handling of debug events on thread/process exit. --- server/debugger.c | 57 +++++++++++++++++++++++-------------------------------- server/process.c | 17 +++++++++++++++-- server/process.h | 3 +-- server/thread.c | 2 +- server/thread.h | 2 +- 5 files changed, 42 insertions(+), 39 deletions(-) diff --git a/server/debugger.c b/server/debugger.c index a7e1640b7db..683270c516d 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -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) { diff --git a/server/process.c b/server/process.c index 4e8062bc584..b105cc965ad 100644 --- a/server/process.c +++ b/server/process.c @@ -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 ) { diff --git a/server/process.h b/server/process.h index 08edd0b0b60..d1671ec423a 100644 --- a/server/process.h +++ b/server/process.h @@ -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 */ diff --git a/server/thread.c b/server/thread.c index 6d96eac1f29..b65f7e04596 100644 --- a/server/thread.c +++ b/server/thread.c @@ -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; diff --git a/server/thread.h b/server/thread.h index ecb9226a0d0..6a482cc65b3 100644 --- a/server/thread.h +++ b/server/thread.h @@ -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 */ -- 2.11.4.GIT