From 47b0e70a85956bc0688fb0cef2218f482d2e94fb Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Mon, 19 Oct 2015 00:34:01 +0200
Subject: server: Do not signal thread until it is really gone.

---
 server/thread.c | 25 +++++++++++++++++++++++--
 server/thread.h |  1 +
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/server/thread.c b/server/thread.c
index 6383000..438d9d0 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -195,6 +195,7 @@ static inline void init_thread_structure( struct thread *thread )
     thread->suspend         = 0;
     thread->desktop_users   = 0;
     thread->token           = NULL;
+    thread->exit_poll       = NULL;
 
     thread->creation_time = current_time;
     thread->exit_time     = 0;
@@ -316,6 +317,7 @@ static void destroy_thread( struct object *obj )
     list_remove( &thread->entry );
     cleanup_thread( thread );
     release_object( thread->process );
+    if (thread->exit_poll) remove_timeout_user( thread->exit_poll );
     if (thread->id) free_ptid( thread->id );
     if (thread->token) release_object( thread->token );
 }
@@ -333,7 +335,7 @@ static void dump_thread( struct object *obj, int verbose )
 static int thread_signaled( struct object *obj, struct wait_queue_entry *entry )
 {
     struct thread *mythread = (struct thread *)obj;
-    return (mythread->state == TERMINATED);
+    return (mythread->state == TERMINATED && !mythread->exit_poll);
 }
 
 static unsigned int thread_map_access( struct object *obj, unsigned int access )
@@ -1091,6 +1093,25 @@ int thread_get_inflight_fd( struct thread *thread, int client )
     return -1;
 }
 
+static void check_terminated( void *arg )
+{
+    struct thread *thread = arg;
+    assert( thread->obj.ops == &thread_ops );
+    assert( thread->state == TERMINATED );
+
+    if (thread->unix_tid != -1 && !kill( thread->unix_tid, 0 ))
+    {
+        thread->exit_poll = add_timeout_user( -TICKS_PER_SEC / 100, check_terminated, thread );
+        return;
+    }
+
+    /* grab reference since object can be destroyed while trying to wake up */
+    grab_object( &thread->obj );
+    thread->exit_poll = NULL;
+    wake_up( &thread->obj, 0 );
+    release_object( &thread->obj );
+}
+
 /* kill a thread on the spot */
 void kill_thread( struct thread *thread, int violent_death )
 {
@@ -1111,8 +1132,8 @@ void kill_thread( struct thread *thread, int violent_death )
     kill_console_processes( thread, 0 );
     debug_exit_thread( thread );
     abandon_mutexes( thread );
-    wake_up( &thread->obj, 0 );
     if (violent_death) send_thread_signal( thread, SIGQUIT );
+    check_terminated( thread );
     cleanup_thread( thread );
     remove_process_thread( thread->process, thread );
     release_object( thread );
diff --git a/server/thread.h b/server/thread.h
index 2821991..ac9af24 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -88,6 +88,7 @@ struct thread
     timeout_t              creation_time; /* Thread creation time */
     timeout_t              exit_time;     /* Thread exit time */
     struct token          *token;         /* security token associated with this thread */
+    struct timeout_user   *exit_poll;     /* poll if the thread/process has exited already */
 };
 
 struct thread_snapshot
-- 
2.6.1

