]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Modularised m_scheduler.
authorNicholas Nethercote <njn@valgrind.org>
Mon, 30 May 2005 23:20:51 +0000 (23:20 +0000)
committerNicholas Nethercote <njn@valgrind.org>
Mon, 30 May 2005 23:20:51 +0000 (23:20 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3817

configure.in
coregrind/Makefile.am
coregrind/core.h
coregrind/linux/Makefile.am
coregrind/linux/core_os.h
coregrind/m_scheduler/Makefile.am [new file with mode: 0644]
coregrind/m_scheduler/priv_sema.h [new file with mode: 0644]
coregrind/m_scheduler/scheduler.c [moved from coregrind/vg_scheduler.c with 98% similarity]
coregrind/m_scheduler/sema.c [moved from coregrind/linux/sema.c with 90% similarity]
coregrind/pub_core_scheduler.h [new file with mode: 0644]

index 3cb47c23f822a50c6855d65bf1755b7569f1f847..7f34ac0cdae1cc1885ba43b9016c9ff605ed837d 100644 (file)
@@ -391,6 +391,7 @@ AC_OUTPUT(
    coregrind/m_demangle/Makefile 
    coregrind/m_dispatch/Makefile 
    coregrind/m_replacemalloc/Makefile 
+   coregrind/m_scheduler/Makefile 
    coregrind/m_sigframe/Makefile 
    coregrind/m_syscalls/Makefile 
    coregrind/amd64/Makefile
index 22b8408981bd65f309429bdd2e3d030a4e5bee46..b6f2dbe41e4a9df02bfe76321998f85f5d35f773 100644 (file)
@@ -6,6 +6,7 @@ MODULES = \
        m_demangle \
        m_dispatch \
        m_replacemalloc \
+       m_scheduler \
        m_sigframe \
        m_syscalls
 
@@ -47,6 +48,7 @@ noinst_HEADERS = \
        pub_core_options.h      \
        pub_core_redir.h        \
        pub_core_replacemalloc.h\
+       pub_core_scheduler.h    \
        pub_core_sigframe.h     \
        pub_core_skiplist.h     \
        pub_core_stacktrace.h   \
@@ -92,7 +94,6 @@ stage2_SOURCES = \
        m_transtab.c \
        ume.c \
        \
-       vg_scheduler.c \
        vg_main.c \
        vg_messages.c \
        vg_mylibc.c \
@@ -105,7 +106,9 @@ stage2_SOURCES = \
        vg_stabs.c \
        vg_symtypes.c
 
+## Nb: libscheduler.a must precede libdispatch.a in this list.
 stage2_extra= \
+       m_scheduler/libscheduler.a \
        m_dispatch/libdispatch.a \
        m_demangle/libdemangle.a \
        m_aspacemgr/libaspacemgr.a \
index 40ba16175a6b70704c9a5e8d34a1588695c81d9a..8dbfa0e396ba335cdf3cd18dd260ee32ce6cf811 100644 (file)
 
 #include "core_os.h"       // OS-specific stuff,    eg. linux/core_os.h
 
+#include <setjmp.h>        // for jmp_buf
+
 #include "pub_core_mallocfree.h"  // for type 'ArenaId'
+#include "pub_core_scheduler.h"   // for types 'ThreadState', 'ThreadArchState'
 #include "pub_core_stacktrace.h"  // for type 'StackTrace'
 
-#include <setjmp.h>       /* for jmp_buf         */
-
 /* ---------------------------------------------------------------------
    Global macros.
    ------------------------------------------------------------------ */
@@ -136,230 +137,6 @@ extern void VG_(done_profiling) ( void );
 #define VG_WRAPPER_ALIAS(name) "_vgw_" #name
 
 
-/* ---------------------------------------------------------------------
-   Exports of vg_scheduler.c
-   ------------------------------------------------------------------ */
-
-/* 
-   Thread state machine:
-
-   Empty -> Init -> Runnable <=> WaitSys/Yielding
-     ^                 |
-     \---- Zombie -----/                      
- */
-typedef
-   enum ThreadStatus { 
-      VgTs_Empty,      /* this slot is not in use */
-      VgTs_Init,       /* just allocated */
-      VgTs_Runnable,   /* ready to run */
-      VgTs_WaitSys,    /* waiting for a syscall to complete */
-      VgTs_Yielding,   /* temporarily yielding the CPU */
-      VgTs_Zombie,     /* transient state just before exiting */
-   }
-   ThreadStatus;
-
-/* Return codes from the scheduler. */
-typedef
-   enum { 
-      VgSrc_None,       /* not exiting yet */
-      VgSrc_ExitSyscall, /* client called exit().  This is the normal
-                            route out. */
-      VgSrc_FatalSig    /* Killed by the default action of a fatal
-                           signal */
-   }
-   VgSchedReturnCode;
-
-
-#if defined(VGA_x86)
-   typedef VexGuestX86State   VexGuestArchState;
-#elif defined(VGA_amd64)
-   typedef VexGuestAMD64State VexGuestArchState;
-#elif defined(VGA_arm)
-   typedef VexGuestARMState   VexGuestArchState;
-#else
-#  error Unknown architecture
-#endif
-
-
-typedef 
-   struct {
-      /* --- BEGIN vex-mandated guest state --- */
-
-      /* Saved machine context. */
-      VexGuestArchState vex;
-
-      /* Saved shadow context. */
-      VexGuestArchState vex_shadow;
-
-      /* Spill area. */
-      UChar vex_spill[LibVEX_N_SPILL_BYTES];
-
-      /* --- END vex-mandated guest state --- */
-   } 
-   ThreadArchState;
-
-
-typedef struct {
-   /* ThreadId == 0 (and hence vg_threads[0]) is NEVER USED.
-      The thread identity is simply the index in vg_threads[].
-      ThreadId == 1 is the root thread and has the special property
-      that we don't try and allocate or deallocate its stack.  For
-      convenience of generating error message, we also put the
-      ThreadId in this tid field, but be aware that it should
-      ALWAYS == the index in vg_threads[]. */
-   ThreadId tid;
-
-   /* Current scheduling status. */
-   ThreadStatus status;
-
-   /* This is set if the thread is in the process of exiting for any
-      reason.  The precise details of the exit are in the OS-specific
-      state. */
-   VgSchedReturnCode exitreason;
-
-   /* Architecture-specific thread state. */
-   ThreadArchState arch;
-
-   /* This thread's blocked-signals mask.  Semantics is that for a
-      signal to be delivered to this thread, the signal must not be
-      blocked by this signal mask.  If more than one thread accepts a
-      signal, then it will be delivered to one at random.  If all
-      threads block the signal, it will remain pending until either a
-      thread unblocks it or someone uses sigwaitsig/sigtimedwait. */
-   vki_sigset_t sig_mask;
-
-   /* tmp_sig_mask is usually the same as sig_mask, and is kept in
-      sync whenever sig_mask is changed.  The only time they have
-      different values is during the execution of a sigsuspend, where
-      tmp_sig_mask is the temporary mask which sigsuspend installs.
-      It is only consulted to compute the signal mask applied to a
-      signal handler. */
-   vki_sigset_t tmp_sig_mask;
-
-   /* A little signal queue for signals we can't get the kernel to
-      queue for us.  This is only allocated as needed, since it should
-      be rare. */
-   struct SigQueue *sig_queue;
-
-   /* Syscall the Thread is currently running; -1 if none.  Should only
-      be set while Thread is in VgTs_WaitSys. */
-   Int syscallno;
-
-   /* Client stacks.  When a thread slot is freed, we don't deallocate its
-      stack; we just leave it lying around for the next use of the
-      slot.  If the next use of the slot requires a larger stack,
-      only then is the old one deallocated and a new one
-      allocated. 
-
-      For the main thread (threadid == 0), this mechanism doesn't
-      apply.  We don't know the size of the stack since we didn't
-      allocate it, and furthermore we never reallocate it. */
-
-   /* The allocated size of this thread's stack (permanently zero
-      if this is ThreadId == 0, since we didn't allocate its stack) */
-   SizeT client_stack_szB;
-
-   /* Address of the highest legitimate word in this stack.  This is
-      used for error messages only -- not critical for execution
-      correctness.  Is is set for all stacks, specifically including
-      ThreadId == 0 (the main thread). */
-   Addr client_stack_highest_word;
-
-   /* Alternate signal stack */
-   vki_stack_t altstack;
-
-   /* OS-specific thread state */
-   os_thread_t os_state;
-
-   /* Used in the syscall handlers.  Set to True to indicate that the
-      PRE routine for a syscall has set the syscall result already and
-      so the syscall does not need to be handed to the kernel. */
-   Bool syscall_result_set;
-   
-   /* Per-thread jmp_buf to resume scheduler after a signal */
-   Bool    sched_jmpbuf_valid;
-   jmp_buf sched_jmpbuf;
-}
-ThreadState;
-
-
-/* The thread table. */
-extern ThreadState VG_(threads)[VG_N_THREADS];
-
-/* Allocate a new ThreadState */
-extern ThreadId VG_(alloc_ThreadState)(void);
-
-/* A thread exits.  tid must currently be running. */
-extern void VG_(exit_thread)(ThreadId tid);
-
-/* Kill a thread.  This interrupts whatever a thread is doing, and
-   makes it exit ASAP.  This does not set the exitreason or
-   exitcode. */
-extern void VG_(kill_thread)(ThreadId tid);
-
-/* Check that tid is in range and denotes a non-Empty thread. */
-extern Bool VG_(is_valid_tid) ( ThreadId tid );
-
-/* Get the ThreadState for a particular thread */
-extern ThreadState *VG_(get_ThreadState)(ThreadId tid);
-
-/* Given an LWP id (ie, real kernel thread id), find the corresponding
-   ThreadId */
-extern ThreadId VG_(get_lwp_tid)(Int lwpid);
-
-/* Returns true if a thread is currently running (ie, has the CPU lock) */
-extern Bool VG_(is_running_thread)(ThreadId tid);
-
-/* Returns true if the thread is in the process of exiting */
-extern Bool VG_(is_exiting)(ThreadId tid);
-
-/* Return the number of non-dead Threads */
-extern Int VG_(count_living_threads)(void);
-
-/* Nuke all threads except tid. */
-extern void VG_(nuke_all_threads_except) ( ThreadId me,
-                                           VgSchedReturnCode reason );
-
-/* Make a thread the running thread.  The thread must previously been
-   sleeping, and not holding the CPU semaphore. This will set the
-   thread state to VgTs_Runnable, and the thread will attempt to take
-   the CPU semaphore.  By the time it returns, tid will be the running
-   thread. */
-extern void VG_(set_running) ( ThreadId tid );
-
-/* Set a thread into a sleeping state.  Before the call, the thread
-   must be runnable, and holding the CPU semaphore.  When this call
-   returns, the thread will be set to the specified sleeping state,
-   and will not be holding the CPU semaphore.  Note that another
-   thread could be running by the time this call returns, so the
-   caller must be careful not to touch any shared state.  It is also
-   the caller's responsibility to actually block until the thread is
-   ready to run again. */
-extern void VG_(set_sleeping) ( ThreadId tid, ThreadStatus state );
-
-/* Yield the CPU for a while */
-extern void VG_(vg_yield)(void);
-
-// The scheduler.
-extern VgSchedReturnCode VG_(scheduler) ( ThreadId tid );
-
-// Do everything which needs doing before the process finally ends,
-// like printing reports, etc
-extern void VG_(shutdown_actions_NORETURN) (
-               ThreadId tid, 
-               VgSchedReturnCode tids_schedretcode 
-            );
-
-extern void VG_(scheduler_init) ( void );
-
-extern void VG_(pp_sched_status) ( void );
-
-// Longjmp back to the scheduler and thus enter the sighandler immediately.
-extern void VG_(resume_scheduler) ( ThreadId tid );
-
-/* If true, a fault is Valgrind-internal (ie, a bug) */
-extern Bool VG_(my_fault);
-
 /* ---------------------------------------------------------------------
    Exports of vg_signals.c
    ------------------------------------------------------------------ */
index 33da84fcfa2a62344b4574f64c5bdc6b95b39bb7..efc2331562c3e2cc4f66dc891ed910874b5e23d6 100644 (file)
@@ -7,5 +7,4 @@ noinst_HEADERS = \
 noinst_LIBRARIES = libos.a
 
 libos_a_SOURCES = \
-       core_os.c \
-       sema.c
+       core_os.c
index 78e80449bfee38aca6739728bea6e1be2b47a461..f59fce93a5d2eb33d80ab2e8999916fe60497573 100644 (file)
 #ifndef __LINUX_CORE_OS_H
 #define __LINUX_CORE_OS_H
 
-/* Not really a semaphore, but use a pipe for a token-passing scheme */
-typedef struct {
-   Int pipe[2];
-   Int owner_thread;           /* who currently has it */
-} vg_sema_t;
-
-void VGO_(sema_init)(vg_sema_t *);
-void VGO_(sema_deinit)(vg_sema_t *);
-void VGO_(sema_down)(vg_sema_t *sema);
-void VGO_(sema_up)(vg_sema_t *sema);
-
 /* OS-specific thread state */
 typedef struct {
    /* who we are */
diff --git a/coregrind/m_scheduler/Makefile.am b/coregrind/m_scheduler/Makefile.am
new file mode 100644 (file)
index 0000000..f569e77
--- /dev/null
@@ -0,0 +1,12 @@
+include $(top_srcdir)/Makefile.all.am
+include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am
+
+noinst_HEADERS = \
+       priv_sema.h
+
+noinst_LIBRARIES = libscheduler.a
+
+libscheduler_a_SOURCES = \
+       scheduler.c \
+       sema.c
+
diff --git a/coregrind/m_scheduler/priv_sema.h b/coregrind/m_scheduler/priv_sema.h
new file mode 100644 (file)
index 0000000..f78ba82
--- /dev/null
@@ -0,0 +1,54 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Private scheduler header.                        priv_sema.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PRIV_SEMA_H
+#define __PRIV_SEMA_H
+
+/* Not really a semaphore, but use a pipe for a token-passing scheme */
+/* Not really a semaphore, but use a pipe for a token-passing scheme */
+typedef struct {
+   Int pipe[2];
+   Int owner_thread;           /* who currently has it */
+} vg_sema_t;
+
+// Nb: this may be OS-specific, but let's not factor it out until we
+// implement an OS port for which this isn't ok.  Then we can rename them
+// VGO_(sema_init)(), etc.
+void VG_(sema_init)   ( vg_sema_t *sema );
+void VG_(sema_deinit) ( vg_sema_t *sema );
+void VG_(sema_down)   ( vg_sema_t *sema );
+void VG_(sema_up)     ( vg_sema_t *sema );
+
+#endif   // __PRIV_SEMA_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
+
similarity index 98%
rename from coregrind/vg_scheduler.c
rename to coregrind/m_scheduler/scheduler.c
index 4ddf9d3fc9e6905630ba6a4a400fb4ad426df86d..20f5832f4a2dfa01e1c80a8d525e9dc8b85ac3cb 100644 (file)
@@ -1,6 +1,6 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Thread scheduling.                            vg_scheduler.c ---*/
+/*--- Thread scheduling.                               scheduler.c ---*/
 /*--------------------------------------------------------------------*/
 
 /*
 #include "pub_core_errormgr.h"
 #include "pub_core_options.h"
 #include "pub_core_replacemalloc.h"
+#include "pub_core_scheduler.h"
 #include "pub_core_stacktrace.h"
 #include "pub_core_syscalls.h"
 #include "pub_core_tooliface.h"
 #include "pub_core_translate.h"
 #include "pub_core_transtab.h"
 #include "vki_unistd.h"
+#include "priv_sema.h"
 
 /* ---------------------------------------------------------------------
    Types and globals for the scheduler.
@@ -263,7 +265,7 @@ void VG_(set_running)(ThreadId tid)
    
    tst->status = VgTs_Runnable;
    
-   VGO_(sema_down)(&run_sema);
+   VG_(sema_down)(&run_sema);
    if (running_tid != VG_INVALID_THREADID)
       VG_(printf)("tid %d found %d running\n", tid, running_tid);
    vg_assert(running_tid == VG_INVALID_THREADID);
@@ -325,7 +327,7 @@ void VG_(set_sleeping)(ThreadId tid, ThreadStatus sleepstate)
 
    /* Release the run_sema; this will reschedule any runnable
       thread. */
-   VGO_(sema_up)(&run_sema);
+   VG_(sema_up)(&run_sema);
 
    if (VG_(clo_trace_sched)) {
       Char buf[50];
@@ -357,7 +359,7 @@ void VG_(exit_thread)(ThreadId tid)
    /* There should still be a valid exitreason for this thread */
    vg_assert(VG_(threads)[tid].exitreason != VgSrc_None);
 
-   VGO_(sema_up)(&run_sema);
+   VG_(sema_up)(&run_sema);
 }
 
 /* Kill a thread.  This interrupts whatever a thread is doing, and
@@ -608,9 +610,9 @@ static void sched_fork_cleanup(ThreadId me)
    }
 
    /* re-init and take the sema */
-   VGO_(sema_deinit)(&run_sema);
-   VGO_(sema_init)(&run_sema);
-   VGO_(sema_down)(&run_sema);
+   VG_(sema_deinit)(&run_sema);
+   VG_(sema_init)(&run_sema);
+   VG_(sema_down)(&run_sema);
 }
 
 
@@ -624,7 +626,7 @@ void VG_(scheduler_init) ( void )
    Int i;
    ThreadId tid_main;
 
-   VGO_(sema_init)(&run_sema);
+   VG_(sema_init)(&run_sema);
 
    for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
       VG_(threads)[i].sig_queue            = NULL;
@@ -1124,5 +1126,5 @@ void scheduler_sanity ( ThreadId tid )
 
 
 /*--------------------------------------------------------------------*/
-/*--- end                                           vg_scheduler.c ---*/
+/*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
similarity index 90%
rename from coregrind/linux/sema.c
rename to coregrind/m_scheduler/sema.c
index 85052e1f3c197f0d134a4659aaa833a1a0b1a350..8d06651fb3cdb75f9aef23b8e693d0f2850ae53a 100644 (file)
@@ -1,6 +1,6 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Semaphore stuff.                                linux/sema.c ---*/
+/*--- Semaphore stuff.                                      sema.c ---*/
 /*--------------------------------------------------------------------*/
 
 /*
@@ -9,7 +9,6 @@
 
    Copyright (C) 2000-2005 Julian Seward
       jseward@acm.org
-   (except where noted below)
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
 */
 
 #include "core.h"
+#include "priv_sema.h"
 
 /* 
    Slower (than the removed futex-based sema scheme) but more portable
    pipe-based token passing scheme.
  */
 
-void VGO_(sema_init)(vg_sema_t *sema)
+void VG_(sema_init)(vg_sema_t *sema)
 {
    VG_(pipe)(sema->pipe);
    sema->pipe[0] = VG_(safe_fd)(sema->pipe[0]);
@@ -48,7 +48,7 @@ void VGO_(sema_init)(vg_sema_t *sema)
    VG_(write)(sema->pipe[1], "T", 1);
 }
 
-void VGO_(sema_deinit)(vg_sema_t *sema)
+void VG_(sema_deinit)(vg_sema_t *sema)
 {
    VG_(close)(sema->pipe[0]);
    VG_(close)(sema->pipe[1]);
@@ -56,7 +56,7 @@ void VGO_(sema_deinit)(vg_sema_t *sema)
 }
 
 /* get a token */
-void VGO_(sema_down)(vg_sema_t *sema)
+void VG_(sema_down)(vg_sema_t *sema)
 {
    Char buf[2] = { 'x' };
    Int ret;
@@ -77,7 +77,7 @@ void VGO_(sema_down)(vg_sema_t *sema)
 }
 
 /* put token back */
-void VGO_(sema_up)(vg_sema_t *sema)
+void VG_(sema_up)(vg_sema_t *sema)
 {
    Int ret;
 
diff --git a/coregrind/pub_core_scheduler.h b/coregrind/pub_core_scheduler.h
new file mode 100644 (file)
index 0000000..9108d2f
--- /dev/null
@@ -0,0 +1,264 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The scheduler.                          pub_core_scheduler.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_SCHEDULER_H
+#define __PUB_CORE_SCHEDULER_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module is the scheduler, which is the main loop
+// controlling the running of all the program's threads.
+// It's at the centre of everything.
+//--------------------------------------------------------------------
+
+/* 
+   Thread state machine:
+
+   Empty -> Init -> Runnable <=> WaitSys/Yielding
+     ^                 |
+     \---- Zombie -----/                      
+ */
+typedef
+   enum ThreadStatus { 
+      VgTs_Empty,      /* this slot is not in use */
+      VgTs_Init,       /* just allocated */
+      VgTs_Runnable,   /* ready to run */
+      VgTs_WaitSys,    /* waiting for a syscall to complete */
+      VgTs_Yielding,   /* temporarily yielding the CPU */
+      VgTs_Zombie,     /* transient state just before exiting */
+   }
+   ThreadStatus;
+
+/* Return codes from the scheduler. */
+typedef
+   enum { 
+      VgSrc_None,       /* not exiting yet */
+      VgSrc_ExitSyscall, /* client called exit().  This is the normal
+                            route out. */
+      VgSrc_FatalSig    /* Killed by the default action of a fatal
+                           signal */
+   }
+   VgSchedReturnCode;
+
+
+#if defined(VGA_x86)
+   typedef VexGuestX86State   VexGuestArchState;
+#elif defined(VGA_amd64)
+   typedef VexGuestAMD64State VexGuestArchState;
+#elif defined(VGA_arm)
+   typedef VexGuestARMState   VexGuestArchState;
+#else
+#  error Unknown architecture
+#endif
+
+
+typedef 
+   struct {
+      /* --- BEGIN vex-mandated guest state --- */
+
+      /* Saved machine context. */
+      VexGuestArchState vex;
+
+      /* Saved shadow context. */
+      VexGuestArchState vex_shadow;
+
+      /* Spill area. */
+      UChar vex_spill[LibVEX_N_SPILL_BYTES];
+
+      /* --- END vex-mandated guest state --- */
+   } 
+   ThreadArchState;
+
+
+typedef struct {
+   /* ThreadId == 0 (and hence vg_threads[0]) is NEVER USED.
+      The thread identity is simply the index in vg_threads[].
+      ThreadId == 1 is the root thread and has the special property
+      that we don't try and allocate or deallocate its stack.  For
+      convenience of generating error message, we also put the
+      ThreadId in this tid field, but be aware that it should
+      ALWAYS == the index in vg_threads[]. */
+   ThreadId tid;
+
+   /* Current scheduling status. */
+   ThreadStatus status;
+
+   /* This is set if the thread is in the process of exiting for any
+      reason.  The precise details of the exit are in the OS-specific
+      state. */
+   VgSchedReturnCode exitreason;
+
+   /* Architecture-specific thread state. */
+   ThreadArchState arch;
+
+   /* This thread's blocked-signals mask.  Semantics is that for a
+      signal to be delivered to this thread, the signal must not be
+      blocked by this signal mask.  If more than one thread accepts a
+      signal, then it will be delivered to one at random.  If all
+      threads block the signal, it will remain pending until either a
+      thread unblocks it or someone uses sigwaitsig/sigtimedwait. */
+   vki_sigset_t sig_mask;
+
+   /* tmp_sig_mask is usually the same as sig_mask, and is kept in
+      sync whenever sig_mask is changed.  The only time they have
+      different values is during the execution of a sigsuspend, where
+      tmp_sig_mask is the temporary mask which sigsuspend installs.
+      It is only consulted to compute the signal mask applied to a
+      signal handler. */
+   vki_sigset_t tmp_sig_mask;
+
+   /* A little signal queue for signals we can't get the kernel to
+      queue for us.  This is only allocated as needed, since it should
+      be rare. */
+   struct SigQueue *sig_queue;
+
+   /* Syscall the Thread is currently running; -1 if none.  Should only
+      be set while Thread is in VgTs_WaitSys. */
+   Int syscallno;
+
+   /* Client stacks.  When a thread slot is freed, we don't deallocate its
+      stack; we just leave it lying around for the next use of the
+      slot.  If the next use of the slot requires a larger stack,
+      only then is the old one deallocated and a new one
+      allocated. 
+
+      For the main thread (threadid == 0), this mechanism doesn't
+      apply.  We don't know the size of the stack since we didn't
+      allocate it, and furthermore we never reallocate it. */
+
+   /* The allocated size of this thread's stack (permanently zero
+      if this is ThreadId == 0, since we didn't allocate its stack) */
+   SizeT client_stack_szB;
+
+   /* Address of the highest legitimate word in this stack.  This is
+      used for error messages only -- not critical for execution
+      correctness.  Is is set for all stacks, specifically including
+      ThreadId == 0 (the main thread). */
+   Addr client_stack_highest_word;
+
+   /* Alternate signal stack */
+   vki_stack_t altstack;
+
+   /* OS-specific thread state */
+   os_thread_t os_state;
+
+   /* Used in the syscall handlers.  Set to True to indicate that the
+      PRE routine for a syscall has set the syscall result already and
+      so the syscall does not need to be handed to the kernel. */
+   Bool syscall_result_set;
+   
+   /* Per-thread jmp_buf to resume scheduler after a signal */
+   Bool    sched_jmpbuf_valid;
+   jmp_buf sched_jmpbuf;
+}
+ThreadState;
+
+
+/* The thread table. */
+extern ThreadState VG_(threads)[VG_N_THREADS];
+
+/* Allocate a new ThreadState */
+extern ThreadId VG_(alloc_ThreadState)(void);
+
+/* A thread exits.  tid must currently be running. */
+extern void VG_(exit_thread)(ThreadId tid);
+
+/* Kill a thread.  This interrupts whatever a thread is doing, and
+   makes it exit ASAP.  This does not set the exitreason or
+   exitcode. */
+extern void VG_(kill_thread)(ThreadId tid);
+
+/* Check that tid is in range and denotes a non-Empty thread. */
+extern Bool VG_(is_valid_tid) ( ThreadId tid );
+
+/* Get the ThreadState for a particular thread */
+extern ThreadState *VG_(get_ThreadState)(ThreadId tid);
+
+/* Given an LWP id (ie, real kernel thread id), find the corresponding
+   ThreadId */
+extern ThreadId VG_(get_lwp_tid)(Int lwpid);
+
+/* Returns true if a thread is currently running (ie, has the CPU lock) */
+extern Bool VG_(is_running_thread)(ThreadId tid);
+
+/* Returns true if the thread is in the process of exiting */
+extern Bool VG_(is_exiting)(ThreadId tid);
+
+/* Return the number of non-dead Threads */
+extern Int VG_(count_living_threads)(void);
+
+/* Nuke all threads except tid. */
+extern void VG_(nuke_all_threads_except) ( ThreadId me,
+                                           VgSchedReturnCode reason );
+
+/* Make a thread the running thread.  The thread must previously been
+   sleeping, and not holding the CPU semaphore. This will set the
+   thread state to VgTs_Runnable, and the thread will attempt to take
+   the CPU semaphore.  By the time it returns, tid will be the running
+   thread. */
+extern void VG_(set_running) ( ThreadId tid );
+
+/* Set a thread into a sleeping state.  Before the call, the thread
+   must be runnable, and holding the CPU semaphore.  When this call
+   returns, the thread will be set to the specified sleeping state,
+   and will not be holding the CPU semaphore.  Note that another
+   thread could be running by the time this call returns, so the
+   caller must be careful not to touch any shared state.  It is also
+   the caller's responsibility to actually block until the thread is
+   ready to run again. */
+extern void VG_(set_sleeping) ( ThreadId tid, ThreadStatus state );
+
+/* Yield the CPU for a while */
+extern void VG_(vg_yield)(void);
+
+// The scheduler.
+extern VgSchedReturnCode VG_(scheduler) ( ThreadId tid );
+
+// Do everything which needs doing before the process finally ends,
+// like printing reports, etc
+extern void VG_(shutdown_actions_NORETURN) (
+               ThreadId tid, 
+               VgSchedReturnCode tids_schedretcode 
+            );
+
+extern void VG_(scheduler_init) ( void );
+
+extern void VG_(pp_sched_status) ( void );
+
+// Longjmp back to the scheduler and thus enter the sighandler immediately.
+extern void VG_(resume_scheduler) ( ThreadId tid );
+
+/* If true, a fault is Valgrind-internal (ie, a bug) */
+extern Bool VG_(my_fault);
+
+#endif   // __PUB_CORE_SCHEDULER_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/