Change the way thread termination is handled.  Until now, there has
been a concept of a 'master thread'.  This is the first thread in the
process.  There was special logic which kept the master thread alive
artificially should it attempt to exit before its children.  So the
master would wait for all children to exit and then exit itself, in
the process emitting the final summary of errors, leaks, etc.

This has the advantage that any process waiting on this one will see
the final summaries appearing before its sys_wait call returns.  In
other words, the final summary output is synchronous with the
master-thread exiting.

Unfortunately the master-thread idea has a serious drawback, namely
that it can and sometimes does cause threaded programs to deadlock at
exit.  It introduces an artificial dependency which is that the master
thread cannot really exit until all its children have exited.  If --
by any means at all -- the children are waiting for the master to exit
before exiting themselves, deadlock results.  There are now two known
examples of such deadlocks.

This commit removes the master thread concept and lets threads exit in
the order which they would have exited without Valgrind's involvement.
The last thread to exit prints the final summaries.  This has the
disadvantage that final output may appear arbitrarily later relative
to the exit of the initial thread.  Whether this is a problem in
practice remains to be seen.

As a minor side effect of this change, some functions have had
_NORETURN added to their names.  Such functions do not return.  The
thread in which they execute is guaranteed to exit before they return.
This makes the logic somewhat easier to follow.

amd64 compilation is now broken.  I will fix it shortly.




git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3816 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index f181423..f026ed6 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -137,12 +137,6 @@
 static Int  vg_argc;
 static Char **vg_argv;
 
-/* The master thread the one which will be responsible for mopping
-   everything up at exit.  Normally it is tid 1, since that's the
-   first thread created, but it may be something else after a
-   fork(). */
-ThreadId VG_(master_tid) = VG_INVALID_THREADID;
-
 /* Application-visible file descriptor limits */
 Int VG_(fd_soft_limit) = -1;
 Int VG_(fd_hard_limit) = -1;
@@ -2817,24 +2811,29 @@
    //--------------------------------------------------------------
    VGP_POPCC(VgpStartup);
 
-   vg_assert(VG_(master_tid) == 1);
-
    if (VG_(clo_xml)) {
       VG_(message)(Vg_UserMsg, "<status>RUNNING</status>");
       VG_(message)(Vg_UserMsg, "");
    }
 
    VG_(debugLog)(1, "main", "Running thread 1\n");
-   VGA_(main_thread_wrapper)(1);
+   /* As a result of the following call, the last thread standing
+      eventually winds up running VG_(shutdown_actions_NORETURN) just
+      below. */
+   VGP_(main_thread_wrapper_NORETURN)(1);
 
-   abort();
+   /*NOTREACHED*/
+   vg_assert(0);
 }
 
 
 /* Do everything which needs doing when the last thread exits */
-void VG_(shutdown_actions)(ThreadId tid)
+void VG_(shutdown_actions_NORETURN) ( ThreadId tid, 
+                                      VgSchedReturnCode tids_schedretcode )
 {
-   vg_assert(tid == VG_(master_tid));
+   VG_(debugLog)(1, "main", "entering VG_(shutdown_actions_NORETURN)\n");
+
+   vg_assert( VG_(count_living_threads)() == 1 );
    vg_assert(VG_(is_running_thread)(tid));
 
    // Wait for all other threads to exit.
@@ -2896,6 +2895,12 @@
    /* Print Vex storage stats */
    if (0)
        LibVEX_ShowAllocStats();
+
+   /* Ok, finally exit in the os-specific way.  In short, if the
+      (last) thread exited by calling sys_exit, do likewise; if the
+      (last) thread stopped due to a fatal signal, terminate the
+      entire system with that same fatal signal. */
+   VGO_(terminate_NORETURN)( tid, tids_schedretcode );
 }
 
 /*--------------------------------------------------------------------*/