From: Nicholas Nethercote Date: Mon, 30 May 2005 23:20:51 +0000 (+0000) Subject: Modularised m_scheduler. X-Git-Tag: svn/VALGRIND_3_0_0~501 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=27e51698af0e982b92f46fea20a887ee8cda4dfb;p=thirdparty%2Fvalgrind.git Modularised m_scheduler. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3817 --- diff --git a/configure.in b/configure.in index 3cb47c23f8..7f34ac0cda 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 22b8408981..b6f2dbe41e 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -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 \ diff --git a/coregrind/core.h b/coregrind/core.h index 40ba16175a..8dbfa0e396 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -37,11 +37,12 @@ #include "core_os.h" // OS-specific stuff, eg. linux/core_os.h +#include // 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 /* 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 ------------------------------------------------------------------ */ diff --git a/coregrind/linux/Makefile.am b/coregrind/linux/Makefile.am index 33da84fcfa..efc2331562 100644 --- a/coregrind/linux/Makefile.am +++ b/coregrind/linux/Makefile.am @@ -7,5 +7,4 @@ noinst_HEADERS = \ noinst_LIBRARIES = libos.a libos_a_SOURCES = \ - core_os.c \ - sema.c + core_os.c diff --git a/coregrind/linux/core_os.h b/coregrind/linux/core_os.h index 78e80449bf..f59fce93a5 100644 --- a/coregrind/linux/core_os.h +++ b/coregrind/linux/core_os.h @@ -32,17 +32,6 @@ #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 index 0000000000..f569e771e1 --- /dev/null +++ b/coregrind/m_scheduler/Makefile.am @@ -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 index 0000000000..f78ba82eff --- /dev/null +++ b/coregrind/m_scheduler/priv_sema.h @@ -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 ---*/ +/*--------------------------------------------------------------------*/ + diff --git a/coregrind/vg_scheduler.c b/coregrind/m_scheduler/scheduler.c similarity index 98% rename from coregrind/vg_scheduler.c rename to coregrind/m_scheduler/scheduler.c index 4ddf9d3fc9..20f5832f4a 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/m_scheduler/scheduler.c @@ -1,6 +1,6 @@ /*--------------------------------------------------------------------*/ -/*--- Thread scheduling. vg_scheduler.c ---*/ +/*--- Thread scheduling. scheduler.c ---*/ /*--------------------------------------------------------------------*/ /* @@ -64,12 +64,14 @@ #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 ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/linux/sema.c b/coregrind/m_scheduler/sema.c similarity index 90% rename from coregrind/linux/sema.c rename to coregrind/m_scheduler/sema.c index 85052e1f3c..8d06651fb3 100644 --- a/coregrind/linux/sema.c +++ b/coregrind/m_scheduler/sema.c @@ -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 @@ -30,13 +29,14 @@ */ #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 index 0000000000..9108d2f19f --- /dev/null +++ b/coregrind/pub_core_scheduler.h @@ -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 ---*/ +/*--------------------------------------------------------------------*/