Change the way Valgrind exits.

Until now, valgrind waited for ld.so to call the .fini code in
valgrind.so, and took this as its cue to switch back to the real CPU
for the rest of the journey.

This is a problem if ld.so subsequently calls other .so's .fini code
and threading is in use, because they do pthread_* calls which cannot
be handled by valgrind's libpthread.so without valgrind actually being
active.

So we ignore the call to valgrind's .fini code, and run the program
all the way up to the point where it calls syscall exit() to
disappear.  This makes the order in which the .fini sections are run
irrelevant, since Valgrind has control during all of them, and so
threading facilities are still available for all of them.

This change means Mozilla 1.0RC1 now exits a lot more cleanly than it
did.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@201 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/vg_scheduler.c b/vg_scheduler.c
index a585587..ea24997 100644
--- a/vg_scheduler.c
+++ b/vg_scheduler.c
@@ -1142,7 +1142,7 @@
 
    /* Start with the root thread.  tid in general indicates the
       currently runnable/just-finished-running thread. */
-   tid = 1;
+   VG_(last_run_tid) = tid = 1;
 
    /* This is the top level scheduler loop.  It falls into three
       phases. */
@@ -1239,8 +1239,8 @@
             while, and go round again, in the hope that eventually a
             thread becomes runnable. */
          nanosleep_for_a_while();
-	 //         pp_sched_status();
-	 //	 VG_(printf)(".\n");
+	 /* pp_sched_status(); */
+	 /* VG_(printf)(".\n"); */
       }
 
 
@@ -1275,6 +1275,8 @@
       /* Actually run thread tid. */
       while (True) {
 
+         VG_(last_run_tid) = tid;
+
          /* For stats purposes only. */
          VG_(num_scheduling_events_MINOR) ++;
 
@@ -1334,7 +1336,9 @@
 
          if (trc == VG_TRC_EBP_JMP_SYSCALL) {
             /* Do a syscall for the vthread tid.  This could cause it
-               to become non-runnable. */
+               to become non-runnable.  One special case: spot the
+               client doing calls to exit() and take this as the cue
+               to exit. */
 #           if 0
             { UInt* esp; Int i;
               esp=(UInt*)vg_threads[tid].m_esp;
@@ -1344,6 +1348,9 @@
             }
 #           endif
 
+            if (vg_threads[tid].m_eax == __NR_exit)
+               return VgSrc_ExitSyscall;
+
             sched_do_syscall(tid);
 
 #           if 0
@@ -1413,14 +1420,6 @@
                1, whereupon the signal will be "delivered". */
 	    break;
 
-#if 0
-         case VG_TRC_EBP_JMP_SYSCALL:
-            /* Do a syscall for the vthread tid.  This could cause it
-               to become non-runnable. */
-            sched_do_syscall(tid);
-            break;
-#endif
-
          case VG_TRC_EBP_JMP_CLIENTREQ: 
             /* Do a client request for the vthread tid.  Note that
                some requests will have been handled by
@@ -1442,11 +1441,7 @@
                other blocked threads become runnable.  In general we
                can and often do mess with the state of arbitrary
                threads at this point. */
-            if (request_code == VG_USERREQ__SHUTDOWN_VALGRIND) {
-               return VgSrc_Shutdown;
-            } else {
-               do_nontrivial_clientreq(tid);
-	    }
+            do_nontrivial_clientreq(tid);
             break;
 
          default: