Fixed handling of debug events on thread/process exit.
This commit is contained in:
parent
6f1b642479
commit
17cf81018f
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue