server: Properly handle kill_thread recursion when killing a process.
Spotted by Mike McCormack.
diff --git a/server/process.c b/server/process.c
index cc4fd6f..b66e492 100644
--- a/server/process.c
+++ b/server/process.c
@@ -515,15 +515,25 @@
/* terminate a process with the given exit code */
static void terminate_process( struct process *process, struct thread *skip, int exit_code )
{
- struct list *ptr, *next;
+ struct list *ptr;
- LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list )
+ if (skip) /* move it to the end of the list */
+ {
+ assert( skip->state != TERMINATED );
+ list_remove( &skip->proc_entry );
+ list_add_tail( &process->thread_list, &skip->proc_entry );
+ }
+
+ grab_object( process ); /* make sure it doesn't get freed when threads die */
+ while ((ptr = list_head( &process->thread_list )))
{
struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry );
if (exit_code) thread->exit_code = exit_code;
- if (thread != skip) kill_thread( thread, 1 );
+ if (thread == skip) break;
+ kill_thread( thread, 1 );
}
+ release_object( process );
}
/* kill all processes */
@@ -657,13 +667,15 @@
if (violent_death) terminate_process( process, NULL, 1 );
else
{
- struct list *ptr, *next;
+ struct list *ptr;
- LIST_FOR_EACH_SAFE( ptr, next, &process->thread_list )
+ grab_object( process ); /* make sure it doesn't get freed when threads die */
+ while ((ptr = list_head( &process->thread_list )))
{
struct thread *thread = LIST_ENTRY( ptr, struct thread, proc_entry );
kill_thread( thread, 0 );
}
+ release_object( process );
}
}