Revert "SafeStack: Delay thread stack clean-up"

This reverts commit r339405, it's failing on Darwin buildbots because
it doesn't seem to have a tgkill/thr_kill2 interface. It has a
__pthread_kill() syscall, but that relies on having a handle to the
thread's port which is not equivalent to it's tid.

llvm-svn: 339408
diff --git a/compiler-rt/lib/safestack/safestack.cc b/compiler-rt/lib/safestack/safestack.cc
index 920b89b..8af9362 100644
--- a/compiler-rt/lib/safestack/safestack.cc
+++ b/compiler-rt/lib/safestack/safestack.cc
@@ -14,13 +14,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <errno.h>
 #include <limits.h>
 #include <pthread.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <unistd.h>
-#include <stdlib.h>
 #include <sys/resource.h>
 #include <sys/types.h>
 #if !defined(__NetBSD__)
@@ -117,6 +115,14 @@
   unsafe_stack_guard = guard;
 }
 
+static void unsafe_stack_free() {
+  if (unsafe_stack_start) {
+    UnmapOrDie((char *)unsafe_stack_start - unsafe_stack_guard,
+               unsafe_stack_size + unsafe_stack_guard);
+  }
+  unsafe_stack_start = nullptr;
+}
+
 /// Thread data for the cleanup handler
 static pthread_key_t thread_cleanup_key;
 
@@ -143,68 +149,26 @@
                      tinfo->unsafe_stack_guard);
 
   // Make sure out thread-specific destructor will be called
+  // FIXME: we can do this only any other specific key is set by
+  // intercepting the pthread_setspecific function itself
   pthread_setspecific(thread_cleanup_key, (void *)1);
 
   return start_routine(start_routine_arg);
 }
 
-/// Linked list used to store exiting threads stack/thread information.
-struct thread_stack_ll {
-  struct thread_stack_ll *next;
-  void *stack_base;
-  pid_t pid;
-  tid_t tid;
-};
-
-/// Linked list of unsafe stacks for threads that are exiting. We delay
-/// unmapping them until the thread exits.
-static thread_stack_ll *thread_stacks = nullptr;
-static pthread_mutex_t thread_stacks_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-/// Thread-specific data destructor. We want to free the unsafe stack only after
-/// this thread is terminated. libc can call functions in safestack-instrumented
-/// code (like free) after thread-specific data destructors have run.
+/// Thread-specific data destructor
 static void thread_cleanup_handler(void *_iter) {
-  CHECK_NE(unsafe_stack_start, nullptr);
-  pthread_setspecific(thread_cleanup_key, NULL);
-
-  pthread_mutex_lock(&thread_stacks_mutex);
-  // Temporary list to hold the previous threads stacks so we don't hold the
-  // thread_stacks_mutex for long.
-  thread_stack_ll *temp_stacks = thread_stacks;
-  thread_stacks = nullptr;
-  pthread_mutex_unlock(&thread_stacks_mutex);
-
-  pid_t pid = getpid();
-  tid_t tid = GetTid();
-
-  // Free stacks for dead threads
-  thread_stack_ll **stackp = &temp_stacks;
-  while (*stackp) {
-    thread_stack_ll *stack = *stackp;
-    if (stack->pid != pid || TgKill(stack->pid, stack->tid, 0) == -ESRCH) {
-      UnmapOrDie(stack->stack_base, unsafe_stack_size + unsafe_stack_guard);
-      *stackp = stack->next;
-      free(stack);
-    } else
-      stackp = &stack->next;
+  // We want to free the unsafe stack only after all other destructors
+  // have already run. We force this function to be called multiple times.
+  // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
+  // times might still end up executing after the unsafe stack is deallocated.
+  size_t iter = (size_t)_iter;
+  if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
+    pthread_setspecific(thread_cleanup_key, (void *)(iter + 1));
+  } else {
+    // This is the last iteration
+    unsafe_stack_free();
   }
-
-  thread_stack_ll *cur_stack =
-      (thread_stack_ll *)malloc(sizeof(thread_stack_ll));
-  cur_stack->stack_base = (char *)unsafe_stack_start - unsafe_stack_guard;
-  cur_stack->pid = pid;
-  cur_stack->tid = tid;
-
-  pthread_mutex_lock(&thread_stacks_mutex);
-  // Merge thread_stacks with the current thread's stack and any remaining
-  // temp_stacks
-  *stackp = thread_stacks;
-  cur_stack->next = temp_stacks;
-  thread_stacks = cur_stack;
-  pthread_mutex_unlock(&thread_stacks_mutex);
-
-  unsafe_stack_start = nullptr;
 }
 
 static void EnsureInterceptorsInitialized();