Quantcast

valgrind: r3816 - in trunk: coregrind coregrind/linux coregrind/m_syscalls include

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

valgrind: r3816 - in trunk: coregrind coregrind/linux coregrind/m_syscalls include

svn-2
Author: sewardj
Date: 2005-05-30 22:44:08 +0100 (Mon, 30 May 2005)
New Revision: 3816

Modified:
   trunk/coregrind/core.h
   trunk/coregrind/linux/core_os.c
   trunk/coregrind/m_syscalls/syscalls-x86-linux.c
   trunk/coregrind/m_syscalls/syscalls.c
   trunk/coregrind/vg_main.c
   trunk/coregrind/vg_scheduler.c
   trunk/coregrind/vg_signals.c
   trunk/include/vki-linux.h
Log:

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.




Modified: trunk/coregrind/core.h
===================================================================
--- trunk/coregrind/core.h 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/core.h 2005-05-30 21:44:08 UTC (rev 3816)
@@ -345,7 +345,10 @@
 
 // Do everything which needs doing before the process finally ends,
 // like printing reports, etc
-extern void VG_(shutdown_actions)(ThreadId tid);
+extern void VG_(shutdown_actions_NORETURN) (
+               ThreadId tid,
+               VgSchedReturnCode tids_schedretcode
+            );
 
 extern void VG_(scheduler_init) ( void );
 
@@ -524,12 +527,6 @@
 Char* VG_(build_child_VALGRINDCLO) ( Char* exename );
 Char* VG_(build_child_exename)     ( void );
 
-/* 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(). */
-extern ThreadId VG_(master_tid);
-
 /* Called when some unhandleable client behaviour is detected.
    Prints a msg and aborts. */
 extern void VG_(unimplemented) ( Char* msg )
@@ -608,21 +605,23 @@
                                  /*MOD*/ ThreadArchState* arch );
 
 // OS/Platform-specific thread clear (after thread exit)
-extern void VGA_(os_state_clear)(ThreadState *);
+extern void VGO_(os_state_clear)(ThreadState *);
 
 // OS/Platform-specific thread init (at scheduler init time)
-extern void VGA_(os_state_init)(ThreadState *);
+extern void VGO_(os_state_init)(ThreadState *);
 
-// Run a thread from beginning to end.  Does not return if tid == VG_(master_tid).
-void VGA_(thread_wrapper)(Word /*ThreadId*/ tid);
+// Run a thread from beginning to end.
+extern VgSchedReturnCode VGO_(thread_wrapper)(Word /*ThreadId*/ tid);
 
-// Like VGA_(thread_wrapper), but it allocates a stack before calling
-// to VGA_(thread_wrapper) on that stack, as if it had been set up by
-// clone()
-void VGA_(main_thread_wrapper)(ThreadId tid) __attribute__ ((__noreturn__));
+// Call here to exit the entire Valgrind system.
+extern void VGO_(terminate_NORETURN)(ThreadId tid, VgSchedReturnCode src);
 
+// Allocates a stack for the first thread, then runs it,
+// as if the thread had been set up by clone()
+extern void VGP_(main_thread_wrapper_NORETURN)(ThreadId tid);
+
 // Return how many bytes of a thread's Valgrind stack are unused
-SSizeT VGA_(stack_unused)(ThreadId tid);
+extern SSizeT VGA_(stack_unused)(ThreadId tid);
 
 // wait until all other threads are dead
 extern void VGA_(reap_threads)(ThreadId self);

Modified: trunk/coregrind/linux/core_os.c
===================================================================
--- trunk/coregrind/linux/core_os.c 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/linux/core_os.c 2005-05-30 21:44:08 UTC (rev 3816)
@@ -29,26 +29,37 @@
 */
 
 #include "core.h"
+#include "pub_core_debuglog.h"
 #include "pub_core_options.h"
 #include "pub_core_tooliface.h"
 
-void VGA_(os_state_clear)(ThreadState *tst)
+void VGO_(os_state_clear)(ThreadState *tst)
 {
    tst->os_state.lwpid = 0;
    tst->os_state.threadgroup = 0;
 }
 
-void VGA_(os_state_init)(ThreadState *tst)
+void VGO_(os_state_init)(ThreadState *tst)
 {
    tst->os_state.valgrind_stack_base = 0;
    tst->os_state.valgrind_stack_szB  = 0;
 
-   VGA_(os_state_clear)(tst);
+   VGO_(os_state_clear)(tst);
 }
 
-static void terminate(ThreadId tid, VgSchedReturnCode src)
+static Bool i_am_the_only_thread ( void )
 {
-   vg_assert(tid == VG_(master_tid));
+   Int c = VG_(count_living_threads)();
+   vg_assert(c >= 1); /* stay sane */
+   return c == 1;
+}
+
+
+void VGO_(terminate_NORETURN)(ThreadId tid, VgSchedReturnCode src)
+{
+   VG_(debugLog)(1, "core_os",
+                    "VGO_(terminate_NORETURN)(tid=%lld)\n", (ULong)tid);
+
    vg_assert(VG_(count_living_threads)() == 0);
 
    //--------------------------------------------------------------
@@ -56,15 +67,15 @@
    //--------------------------------------------------------------
    switch (src) {
    case VgSrc_ExitSyscall: /* the normal way out */
-      VG_(exit)( VG_(threads)[VG_(master_tid)].os_state.exitcode );
+      VG_(exit)( VG_(threads)[tid].os_state.exitcode );
       /* NOT ALIVE HERE! */
       VG_(core_panic)("entered the afterlife in main() -- ExitSyscall");
       break; /* what the hell :) */
 
    case VgSrc_FatalSig:
       /* We were killed by a fatal signal, so replicate the effect */
-      vg_assert(VG_(threads)[VG_(master_tid)].os_state.fatalsig != 0);
-      VG_(kill_self)(VG_(threads)[VG_(master_tid)].os_state.fatalsig);
+      vg_assert(VG_(threads)[tid].os_state.fatalsig != 0);
+      VG_(kill_self)(VG_(threads)[tid].os_state.fatalsig);
       VG_(core_panic)("main(): signal was supposed to be fatal");
       break;
 
@@ -73,9 +84,16 @@
    }
 }
 
-/* Run a thread from beginning to end. Does not return. */
-void VGA_(thread_wrapper)(Word /*ThreadId*/ tidW)
+
+/* Run a thread from beginning to end and return the thread's
+   scheduler-return-code. */
+
+VgSchedReturnCode VGO_(thread_wrapper)(Word /*ThreadId*/ tidW)
 {
+   VG_(debugLog)(1, "core_os",
+                    "VGO_(thread_wrapper)(tid=%lld): entry\n",
+                    (ULong)tidW);
+
    VgSchedReturnCode ret;
    ThreadId     tid = (ThreadId)tidW;
    ThreadState* tst = VG_(get_ThreadState)(tid);
@@ -103,81 +121,26 @@
   
    vg_assert(tst->status == VgTs_Runnable);
    vg_assert(VG_(is_running_thread)(tid));
-  
-   if (tid == VG_(master_tid)) {
-      VG_(shutdown_actions)(tid);
-      terminate(tid, ret);
-   }
-}
 
-/* wait until all other threads are dead */
-static Bool alldead(void *v)
-{
-   /* master_tid must be alive... */
-   Int c = VG_(count_living_threads)();
-   //VG_(printf)("alldead: count=%d\n", c);
-   return c <= 1;
-}
+   VG_(debugLog)(1, "core_os",
+                    "VGO_(thread_wrapper)(tid=%lld): done\n",
+                    (ULong)tidW);
 
-static void sigvgchld_handler(Int sig)
-{
-   VG_(printf)("got a sigvgchld?\n");
+   /* Return to caller, still holding the lock. */
+   return ret;
 }
 
-/*
-   Wait until some predicate about threadstates is satisfied.
 
-   This uses SIGVGCHLD as a notification that it is now worth
-   re-evaluating the predicate.
- */
-static void wait_for_threadstate(Bool (*pred)(void *), void *arg)
+/* Wait until all other threads disappear. */
+void VGA_(reap_threads)(ThreadId self)
 {
-   vki_sigset_t set, saved;
-   struct vki_sigaction sa, old_sa;
-
-   /*
-      SIGVGCHLD is set to be ignored, and is unblocked by default.
-      This means all such signals are simply discarded.
-
-      In this loop, we actually block it, and then poll for it with
-      sigtimedwait.
-    */
-   VG_(sigemptyset)(&set);
-   VG_(sigaddset)(&set, VKI_SIGVGCHLD);
-
-   VG_(set_sleeping)(VG_(master_tid), VgTs_Yielding);
-   VG_(sigprocmask)(VKI_SIG_BLOCK, &set, &saved);
-
-   /* It shouldn't be necessary to set a handler, since the signal is
-      always blocked, but it seems to be necessary to convice the
-      kernel not to just toss the signal... */
-   sa.ksa_handler = sigvgchld_handler;
-   sa.sa_flags = 0;
-   VG_(sigfillset)(&sa.sa_mask);
-   VG_(sigaction)(VKI_SIGVGCHLD, &sa, &old_sa);
-
-   vg_assert(old_sa.ksa_handler == VKI_SIG_IGN);
-
-   while(!(*pred)(arg)) {
-      struct vki_siginfo si;
-      Int ret = VG_(sigtimedwait)(&set, &si, NULL);
-
-      if (ret > 0 && VG_(clo_trace_signals))
- VG_(message)(Vg_DebugMsg, "Got %d (code=%d) from tid lwp %d",
-      ret, si.si_code, si._sifields._kill._pid);
+   while (!i_am_the_only_thread()) {
+      /* Let other thread(s) run */
+      VG_(vg_yield)();
    }
-
-   VG_(sigaction)(VKI_SIGVGCHLD, &old_sa, NULL);
-   VG_(sigprocmask)(VKI_SIG_SETMASK, &saved, NULL);
-   VG_(set_running)(VG_(master_tid));
+   vg_assert(i_am_the_only_thread());
 }
 
-void VGA_(reap_threads)(ThreadId self)
-{
-   vg_assert(self == VG_(master_tid));
-   wait_for_threadstate(alldead, NULL);
-}
-
 /* The we need to know the address of it so it can be
    called at program exit. */
 static Addr __libc_freeres_wrapper;

Modified: trunk/coregrind/m_syscalls/syscalls-x86-linux.c
===================================================================
--- trunk/coregrind/m_syscalls/syscalls-x86-linux.c 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/m_syscalls/syscalls-x86-linux.c 2005-05-30 21:44:08 UTC (rev 3816)
@@ -35,6 +35,7 @@
 
 #include "core.h"
 #include "ume.h"                /* for jmp_with_stack */
+#include "pub_core_debuglog.h"
 #include "pub_core_aspacemgr.h"
 #include "pub_core_sigframe.h"
 #include "pub_core_syscalls.h"
@@ -244,64 +245,116 @@
    return ((Addr)p) - tst->os_state.valgrind_stack_base;
 }
 
-/*
-   Allocate a stack for the main thread, and call VGA_(thread_wrapper)
-   on that stack.
- */
-void VGA_(main_thread_wrapper)(ThreadId tid)
+
+/* Run a thread all the way to the end, then do appropriate exit actions
+   (this is the last-one-out-turn-off-the-lights bit).
+*/
+static void run_a_thread_NORETURN ( Word tidW )
 {
-   UWord* esp = allocstack(tid);
+   ThreadId tid = (ThreadId)tidW;
 
-   vg_assert(tid == VG_(master_tid));
+   VG_(debugLog)(1, "syscalls-x86-linux",
+                    "run_a_thread_NORETURN(tid=%lld): "
+                       "VGO_(thread_wrapper) called\n",
+                       (ULong)tidW);
 
-   call_on_new_stack_0_1(
-      (Addr)esp,             /* stack */
-      0,                     /*bogus return address*/
-      VGA_(thread_wrapper),  /* fn to call */
-      (Word)tid              /* arg to give it */
-   );
+   /* Run the thread all the way through. */
+   VgSchedReturnCode src = VGO_(thread_wrapper)(tid);  
 
+   VG_(debugLog)(1, "syscalls-x86-linux",
+                    "run_a_thread_NORETURN(tid=%lld): "
+                       "VGO_(thread_wrapper) done\n",
+                       (ULong)tidW);
+
+   Int c = VG_(count_living_threads)();
+   vg_assert(c >= 1); /* stay sane */
+
+   if (c == 1) {
+
+      VG_(debugLog)(1, "syscalls-x86-linux",
+                       "run_a_thread_NORETURN(tid=%lld): "
+                          "last one standing\n",
+                          (ULong)tidW);
+
+      /* We are the last one standing.  Keep hold of the lock and
+         carry on to show final tool results, then exit the entire system. */
+      VG_(shutdown_actions_NORETURN)(tid, src);
+
+   } else {
+
+      VG_(debugLog)(1, "syscalls-x86-linux",
+                       "run_a_thread_NORETURN(tid=%lld): "
+                          "not last one standing\n",
+                          (ULong)tidW);
+
+      /* OK, thread is dead, but others still exist.  Just exit. */
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+
+      /* This releases the run lock */
+      VG_(exit_thread)(tid);
+      vg_assert(tst->status == VgTs_Zombie);
+
+      /* We have to use this sequence to terminate the thread to
+         prevent a subtle race.  If VG_(exit_thread)() had left the
+         ThreadState as Empty, then it could have been reallocated,
+         reusing the stack while we're doing these last cleanups.
+         Instead, VG_(exit_thread) leaves it as Zombie to prevent
+         reallocation.  We need to make sure we don't touch the stack
+         between marking it Empty and exiting.  Hence the
+         assembler. */
+      asm volatile (
+         "movl %1, %0\n" /* set tst->status = VgTs_Empty */
+         "movl %2, %%eax\n"    /* set %eax = __NR_exit */
+         "movl %3, %%ebx\n"    /* set %ebx = tst->os_state.exitcode */
+         "int $0x80\n" /* exit(tst->os_state.exitcode) */
+         : "=m" (tst->status)
+         : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode));
+
+      VG_(core_panic)("Thread exit failed?\n");
+   }
+
    /*NOTREACHED*/
    vg_assert(0);
 }
 
-static Int start_thread(void *arg)
+
+/*
+   Allocate a stack for the main thread, and run it all the way to the
+   end.  
+*/
+void VGP_(main_thread_wrapper_NORETURN)(ThreadId tid)
 {
-   ThreadState *tst = (ThreadState *)arg;
-   ThreadId tid = tst->tid;
+   VG_(debugLog)(1, "syscalls-x86-linux",
+                    "entering VGP_(main_thread_wrapper_NORETURN)\n");
 
-   VGA_(thread_wrapper)(tid);
+   UWord* esp = allocstack(tid);
 
-   /* OK, thread is dead; this releases the run lock */
-   VG_(exit_thread)(tid);
+   /* shouldn't be any other threads around yet */
+   vg_assert( VG_(count_living_threads)() == 1 );
 
-   vg_assert(tst->status == VgTs_Zombie);
+   call_on_new_stack_0_1(
+      (Addr)esp,              /* stack */
+      0,                      /*bogus return address*/
+      run_a_thread_NORETURN,  /* fn to call */
+      (Word)tid               /* arg to give it */
+   );
 
-   /* Poke the reaper */
-   if (VG_(clo_trace_signals))
-      VG_(message)(Vg_DebugMsg, "Sending SIGVGCHLD to master tid=%d lwp=%d",
-   VG_(master_tid), VG_(threads)[VG_(master_tid)].os_state.lwpid);
+   /*NOTREACHED*/
+   vg_assert(0);
+}
 
-   VG_(tkill)(VG_(threads)[VG_(master_tid)].os_state.lwpid, VKI_SIGVGCHLD);
 
-   /* We have to use this sequence to terminate the thread to prevent
-      a subtle race.  If VG_(exit_thread)() had left the ThreadState
-      as Empty, then it could have been reallocated, reusing the stack
-      while we're doing these last cleanups.  Instead,
-      VG_(exit_thread) leaves it as Zombie to prevent reallocation.
-      We need to make sure we don't touch the stack between marking it
-      Empty and exiting.  Hence the assembler. */
-   asm volatile (
-      "movl %1, %0\n" /* set tst->status = VgTs_Empty */
-      "movl %2, %%eax\n"    /* set %eax = __NR_exit */
-      "movl %3, %%ebx\n"    /* set %ebx = tst->os_state.exitcode */
-      "int $0x80\n" /* exit(tst->os_state.exitcode) */
-      : "=m" (tst->status)
-      : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode));
+static Int start_thread_NORETURN ( void* arg )
+{
+   ThreadState* tst = (ThreadState*)arg;
+   ThreadId     tid = tst->tid;
 
-   VG_(core_panic)("Thread exit failed?\n");
+   run_a_thread_NORETURN ( (Word)tid );
+   /*NOTREACHED*/
+   vg_assert(0);
 }
 
+
 /* ---------------------------------------------------------------------
    clone() handling
    ------------------------------------------------------------------ */
@@ -404,7 +457,7 @@
    VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
 
    /* Create the new thread */
-   ret = VG_(clone)(start_thread, stack, flags, &VG_(threads)[ctid],
+   ret = VG_(clone)(start_thread_NORETURN, stack, flags, &VG_(threads)[ctid],
     child_tidptr, parent_tidptr, NULL);
 
    VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
@@ -1470,7 +1523,7 @@
    GENX_(__NR_chroot,            sys_chroot),         // 61
    //   (__NR_ustat,             sys_ustat)           // 62 SVr4 -- deprecated
    GENXY(__NR_dup2,              sys_dup2),           // 63
-   GENXY(__NR_getppid,           sys_getppid),        // 64
+   GENX_(__NR_getppid,           sys_getppid),        // 64
 
    GENX_(__NR_getpgrp,           sys_getpgrp),        // 65
    GENX_(__NR_setsid,            sys_setsid),         // 66

Modified: trunk/coregrind/m_syscalls/syscalls.c
===================================================================
--- trunk/coregrind/m_syscalls/syscalls.c 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/m_syscalls/syscalls.c 2005-05-30 21:44:08 UTC (rev 3816)
@@ -2345,29 +2345,19 @@
    /* Resistance is futile.  Nuke all other threads.  POSIX mandates
       this. (Really, nuke them all, since the new process will make
       its own new thread.) */
-   VG_(master_tid) = tid;       /* become the master */
    VG_(nuke_all_threads_except)( tid, VgSrc_ExitSyscall );
    VGA_(reap_threads)(tid);
 
-   if (0) {
-      /* Shut down cleanly and report final state
-         XXX Is this reasonable? */
-      tst->exitreason = VgSrc_ExitSyscall;
-      VG_(shutdown_actions)(tid);
+   { // Remove the valgrind-specific stuff from the environment so the
+     // child doesn't get vg_inject.so, vgpreload.so, etc.  This is
+     // done unconditionally, since if we are tracing the child,
+     // stage1/2 will set up the appropriate client environment.
+     Char** envp = (Char**)ARG3;
+     if (envp != NULL) {
+        VG_(env_remove_valgrind_env_stuff)( envp );
+     }
    }
 
-   {
-      // Remove the valgrind-specific stuff from the environment so the
-      // child doesn't get vg_inject.so, vgpreload.so, etc.  This is
-      // done unconditionally, since if we are tracing the child,
-      // stage1/2 will set up the appropriate client environment.
-      Char** envp = (Char**)ARG3;
-
-      if (envp != NULL) {
-         VG_(env_remove_valgrind_env_stuff)( envp );
-      }
-   }
-
    if (VG_(clo_trace_children)) {
       Char* optvar = VG_(build_child_VALGRINDCLO)( (Char*)ARG1 );
 
@@ -2952,16 +2942,6 @@
    PRE_REG_READ0(long, "getppid");
 }
 
-POST(sys_getppid)
-{
-   /* If the master thread has already exited, and it is this thread's
-      parent, then force getppid to return 1 (init) rather than the
-      real ppid, so that it thinks its parent has exited. */
-   if (VG_(threads)[VG_(master_tid)].os_state.lwpid == RES &&
-       VG_(is_exiting)(VG_(master_tid)))
-      RES = 1;
-}
-
 static void common_post_getrlimit(ThreadId tid, UWord a1, UWord a2)
 {
    POST_MEM_WRITE( a2, sizeof(struct vki_rlimit) );
@@ -6068,15 +6048,6 @@
    VG_(sigdelset)(mask, VKI_SIGSTOP);
 
    VG_(sigdelset)(mask, VKI_SIGVGKILL); /* never block */
-
-   /* SIGVGCHLD is used by threads to indicate their state changes to
-      the master thread.  Mostly it doesn't care, so it leaves the
-      signal ignored and unblocked.  Everyone else should have it
-      blocked, so there's at most 1 thread with it unblocked. */
-   if (tid == VG_(master_tid))
-      VG_(sigdelset)(mask, VKI_SIGVGCHLD);
-   else
-      VG_(sigaddset)(mask, VKI_SIGVGCHLD);
 }
 
 void VG_(client_syscall) ( ThreadId tid )

Modified: trunk/coregrind/vg_main.c
===================================================================
--- trunk/coregrind/vg_main.c 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/vg_main.c 2005-05-30 21:44:08 UTC (rev 3816)
@@ -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 );
 }
 
 /*--------------------------------------------------------------------*/

Modified: trunk/coregrind/vg_scheduler.c
===================================================================
--- trunk/coregrind/vg_scheduler.c 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/vg_scheduler.c 2005-05-30 21:44:08 UTC (rev 3816)
@@ -439,10 +439,6 @@
    VG_(sigdelset)(&mask, VKI_SIGSTOP);
    VG_(sigdelset)(&mask, VKI_SIGKILL);
 
-   /* Master doesn't block this */
-   if (tid == VG_(master_tid))
-      VG_(sigdelset)(&mask, VKI_SIGVGCHLD);
-
    VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, NULL);
 }
 
@@ -566,7 +562,7 @@
    VG_(sigemptyset)(&VG_(threads)[tid].sig_mask);
    VG_(sigemptyset)(&VG_(threads)[tid].tmp_sig_mask);
 
-   VGA_(os_state_clear)(&VG_(threads)[tid]);
+   VGO_(os_state_clear)(&VG_(threads)[tid]);
 
    /* start with no altstack */
    VG_(threads)[tid].altstack.ss_sp = (void *)0xdeadbeef;
@@ -600,8 +596,6 @@
    ThreadId tid;
    vg_assert(running_tid == me);
 
-   VG_(master_tid) = me;
-
    VG_(threads)[me].os_state.lwpid = VG_(gettid)();
    VG_(threads)[me].os_state.threadgroup = VG_(getpid)();
 
@@ -635,7 +629,7 @@
    for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
       VG_(threads)[i].sig_queue            = NULL;
 
-      VGA_(os_state_init)(&VG_(threads)[i]);
+      VGO_(os_state_init)(&VG_(threads)[i]);
       mostly_clear_thread_record(i);
 
       VG_(threads)[i].status                    = VgTs_Empty;
@@ -645,8 +639,6 @@
 
    tid_main = VG_(alloc_ThreadState)();
 
-   VG_(master_tid) = tid_main;
-
    /* Initial thread's stack is the original process stack */
    VG_(threads)[tid_main].client_stack_highest_word
                                             = VG_(clstk_end) - sizeof(UWord);

Modified: trunk/coregrind/vg_signals.c
===================================================================
--- trunk/coregrind/vg_signals.c 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/coregrind/vg_signals.c 2005-05-30 21:44:08 UTC (rev 3816)
@@ -303,8 +303,6 @@
          // cases in the switch, so we handle them in the 'default' case.
  if (sig == VKI_SIGVGKILL)
     skss_handler = sigvgkill_handler;
- else if (sig == VKI_SIGVGCHLD)
-    skss_handler = VKI_SIG_IGN; /* we only poll for it */
  else {
     if (scss_handler == VKI_SIG_IGN)
        skss_handler = VKI_SIG_IGN;
@@ -1358,7 +1356,8 @@
       #endif
 
    /* stash fatal signal in main thread */
-   VG_(threads)[VG_(master_tid)].os_state.fatalsig = sigNo;
+   // what's this for?
+   //VG_(threads)[VG_(master_tid)].os_state.fatalsig = sigNo;
 
    /* everyone dies */
    VG_(nuke_all_threads_except)(tid, VgSrc_FatalSig);
@@ -1884,8 +1883,10 @@
       if (0)
  VG_(kill_self)(sigNo); /* generate a core dump */
 
-      if (tid == 0)            /* could happen after everyone has exited */
-        tid = VG_(master_tid);
+      //if (tid == 0)            /* could happen after everyone has exited */
+      //  tid = VG_(master_tid);
+      vg_assert(tid != 0);
+
       tst = VG_(get_ThreadState)(tid);
       VG_(get_StackTrace2)(ips, VG_(clo_backtrace_size),
                            VGP_UCONTEXT_INSTR_PTR(uc),
@@ -1967,8 +1968,6 @@
    for(i = 0; i < _VKI_NSIG_WORDS; i++)
       pollset.sig[i] = ~tst->sig_mask.sig[i];
 
-   VG_(sigdelset)(&pollset, VKI_SIGVGCHLD); /* already dealt with */
-
    //VG_(printf)("tid %d pollset=%08x%08x\n", tid, pollset.sig[1], pollset.sig[0]);
 
    block_all_host_signals(&saved_mask); // protect signal queue
@@ -2063,19 +2062,18 @@
       VG_(message)(Vg_DebugMsg, "Max kernel-supported signal is %d", VG_(max_signal));
 
    /* Our private internal signals are treated as ignored */
-   scss.scss_per_sig[VKI_SIGVGCHLD].scss_handler = VKI_SIG_IGN;
-   scss.scss_per_sig[VKI_SIGVGCHLD].scss_flags   = VKI_SA_SIGINFO;
-   VG_(sigfillset)(&scss.scss_per_sig[VKI_SIGVGCHLD].scss_mask);
-
    scss.scss_per_sig[VKI_SIGVGKILL].scss_handler = VKI_SIG_IGN;
    scss.scss_per_sig[VKI_SIGVGKILL].scss_flags   = VKI_SA_SIGINFO;
    VG_(sigfillset)(&scss.scss_per_sig[VKI_SIGVGKILL].scss_mask);
 
    /* Copy the process' signal mask into the root thread. */
-   vg_assert(VG_(threads)[VG_(master_tid)].status == VgTs_Init);
-   VG_(threads)[VG_(master_tid)].sig_mask = saved_procmask;
-   VG_(threads)[VG_(master_tid)].tmp_sig_mask = saved_procmask;
+   vg_assert(VG_(threads)[1].status == VgTs_Init);
+   for (i = 2; i < VG_N_THREADS; i++)
+      vg_assert(VG_(threads)[i].status == VgTs_Empty);
 
+   VG_(threads)[1].sig_mask = saved_procmask;
+   VG_(threads)[1].tmp_sig_mask = saved_procmask;
+
    /* Calculate SKSS and apply it.  This also sets the initial kernel
       mask we need to run with. */
    handle_SCSS_change( True /* forced update */ );

Modified: trunk/include/vki-linux.h
===================================================================
--- trunk/include/vki-linux.h 2005-05-30 03:12:09 UTC (rev 3815)
+++ trunk/include/vki-linux.h 2005-05-30 21:44:08 UTC (rev 3816)
@@ -351,8 +351,7 @@
 
 /* Use high signals because native pthreads wants to use low */
 #define VKI_SIGVGKILL       (VG_(max_signal)-0) // [[internal: kill]]
-#define VKI_SIGVGCHLD       (VG_(max_signal)-1) // [[internal: thread death]]
-#define VKI_SIGVGRTUSERMAX  (VG_(max_signal)-2) // [[internal: last user-usable RT signal]]
+#define VKI_SIGVGRTUSERMAX  (VG_(max_signal)-1) // [[internal: last user-usable RT signal]]
 
 //----------------------------------------------------------------------
 // From linux-2.6.8.1/include/asm-generic/siginfo.h



-------------------------------------------------------
This SF.Net email is sponsored by Yahoo.
Introducing Yahoo! Search Developer Network - Create apps using Yahoo!
Search APIs Find out how you can build Yahoo! directly into your own
Applications - visit http://developer.yahoo.net/?fr=offad-ysdn-ostg-q22005
_______________________________________________
Valgrind-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/valgrind-developers
Loading...