// 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 );
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 )
/*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.
+extern VgSchedReturnCode VGO_(thread_wrapper)(Word /*ThreadId*/ tid);
-// Run a thread from beginning to end. Does not return if tid == VG_(master_tid).
-void VGA_(thread_wrapper)(Word /*ThreadId*/ tid);
+// Call here to exit the entire Valgrind system.
+extern void VGO_(terminate_NORETURN)(ThreadId tid, VgSchedReturnCode src);
-// 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__));
+// 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);
*/
#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);
//--------------------------------------------------------------
//--------------------------------------------------------------
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;
}
}
-/* 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);
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)
-{
- 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);
- }
-
- VG_(sigaction)(VKI_SIGVGCHLD, &old_sa, NULL);
- VG_(sigprocmask)(VKI_SIG_SETMASK, &saved, NULL);
- VG_(set_running)(VG_(master_tid));
-}
+/* Wait until all other threads disappear. */
void VGA_(reap_threads)(ThreadId self)
{
- vg_assert(self == VG_(master_tid));
- wait_for_threadstate(alldead, NULL);
+ while (!i_am_the_only_thread()) {
+ /* Let other thread(s) run */
+ VG_(vg_yield)();
+ }
+ vg_assert(i_am_the_only_thread());
}
/* The we need to know the address of it so it can be
#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"
return ((Addr)p) - tst->os_state.valgrind_stack_base;
}
+
+/* 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 )
+{
+ ThreadId tid = (ThreadId)tidW;
+
+ VG_(debugLog)(1, "syscalls-x86-linux",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "VGO_(thread_wrapper) called\n",
+ (ULong)tidW);
+
+ /* 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);
+}
+
+
/*
- Allocate a stack for the main thread, and call VGA_(thread_wrapper)
- on that stack.
- */
-void VGA_(main_thread_wrapper)(ThreadId tid)
+ Allocate a stack for the main thread, and run it all the way to the
+ end.
+*/
+void VGP_(main_thread_wrapper_NORETURN)(ThreadId tid)
{
+ VG_(debugLog)(1, "syscalls-x86-linux",
+ "entering VGP_(main_thread_wrapper_NORETURN)\n");
+
UWord* esp = allocstack(tid);
- vg_assert(tid == VG_(master_tid));
+ /* shouldn't be any other threads around yet */
+ vg_assert( VG_(count_living_threads)() == 1 );
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 */
+ (Addr)esp, /* stack */
+ 0, /*bogus return address*/
+ run_a_thread_NORETURN, /* fn to call */
+ (Word)tid /* arg to give it */
);
/*NOTREACHED*/
vg_assert(0);
}
-static Int start_thread(void *arg)
+
+static Int start_thread_NORETURN ( void* arg )
{
- ThreadState *tst = (ThreadState *)arg;
- ThreadId tid = tst->tid;
-
- VGA_(thread_wrapper)(tid);
-
- /* OK, thread is dead; this releases the run lock */
- VG_(exit_thread)(tid);
-
- vg_assert(tst->status == VgTs_Zombie);
-
- /* 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);
-
- 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));
-
- VG_(core_panic)("Thread exit failed?\n");
+ ThreadState* tst = (ThreadState*)arg;
+ ThreadId tid = tst->tid;
+
+ run_a_thread_NORETURN ( (Word)tid );
+ /*NOTREACHED*/
+ vg_assert(0);
}
+
/* ---------------------------------------------------------------------
clone() handling
------------------------------------------------------------------ */
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);
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
/* 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)) {
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) );
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 )
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;
//--------------------------------------------------------------
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.
/* 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 );
}
/*--------------------------------------------------------------------*/
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);
}
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;
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)();
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;
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);
// 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;
#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);
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),
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
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. */
/* 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