Merge in changes from the 2.4.0 line. This basically brings in the
overhaul of the thread support. Many things are now probably broken,
but at least with --tool=none, simple and not-so-simple threaded and
non-thread programs work.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3265 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/core.h b/coregrind/core.h
index a85b67c..d4ef229 100644
--- a/coregrind/core.h
+++ b/coregrind/core.h
@@ -89,9 +89,9 @@
// Ugly: this is needed by linux/core_os.h
typedef struct _ThreadState ThreadState;
-#include "core_os.h" // OS-specific stuff, eg. linux/core_os.h
#include "core_platform.h" // platform-specific stuff,
// eg. x86-linux/core_platform.h
+#include "core_os.h" // OS-specific stuff, eg. linux/core_os.h
#include "valgrind.h"
@@ -154,24 +154,8 @@
#define VG_SCHEDULING_QUANTUM 50000
/* Number of file descriptors that Valgrind tries to reserve for
- it's own use - two per thread plues a small number of extras. */
-#define VG_N_RESERVED_FDS (VG_N_THREADS*2 + 4)
-
-/* Stack size for a thread. We try and check that they do not go
- beyond it. */
-#define VG_PTHREAD_STACK_SIZE (1 << 20)
-
-/* Number of entries in each thread's cleanup stack. */
-#define VG_N_CLEANUPSTACK 16
-
-/* Number of entries in each thread's fork-handler stack. */
-#define VG_N_FORKHANDLERSTACK 4
-
-/* Max number of callers for context in a suppression. */
-#define VG_N_SUPP_CALLERS 4
-
-/* Numer of entries in each thread's signal queue. */
-#define VG_N_SIGNALQUEUE 8
+ it's own use - just a small constant. */
+#define VG_N_RESERVED_FDS (10)
/* Useful macros */
/* a - alignment - must be a power of 2 */
@@ -230,12 +214,6 @@
VgLogTo_Socket
} VgLogTo;
-/* pid of main process */
-extern Int VG_(main_pid);
-
-/* pgrp of process (global to all threads) */
-extern Int VG_(main_pgrp);
-
/* Application-visible file descriptor limits */
extern Int VG_(fd_soft_limit);
extern Int VG_(fd_hard_limit);
@@ -301,11 +279,12 @@
extern Bool VG_(clo_trace_signals);
/* DEBUG: print symtab details? default: NO */
extern Bool VG_(clo_trace_symtab);
+/* DEBUG: print redirection details? default: NO */
+extern Bool VG_(clo_trace_redir);
/* DEBUG: print thread scheduling events? default: NO */
extern Bool VG_(clo_trace_sched);
-/* DEBUG: print pthread (mutex etc) events? default: 0 (none), 1
- (some), 2 (all) */
-extern Int VG_(clo_trace_pthread_level);
+/* DEBUG: print pthreads calls? default: NO */
+extern Bool VG_(clo_trace_pthreads);
/* Display gory details for the k'th most popular error. default:
Infinity. */
extern Int VG_(clo_dump_error);
@@ -313,13 +292,6 @@
extern Int VG_(clo_backtrace_size);
/* Engage miscellaneous weird hacks needed for some progs. */
extern Char* VG_(clo_weird_hacks);
-/* How often we should poll for signals, assuming we need to poll for
- signals. */
-extern Int VG_(clo_signal_polltime);
-
-/* Low latency syscalls and signals */
-extern Bool VG_(clo_lowlat_syscalls);
-extern Bool VG_(clo_lowlat_signals);
/* Track open file descriptors? */
extern Bool VG_(clo_track_fds);
@@ -337,13 +309,20 @@
/* Test each client pointer dereference to check it's within the
client address space bounds */
extern Bool VG_(clo_pointercheck);
+/* Model the pthread library */
+extern Bool VG_(clo_model_pthreads);
/* HACK: Use hacked version of clone for Quadrics Elan3 drivers */
extern Bool VG_(clo_support_elan3);
/* Set up the libc freeres wrapper */
-extern void VG_(intercept_libc_freeres_wrapper)(Addr);
+extern void VGA_(intercept_libc_freeres_wrapper)(Addr);
+// Clean up the client by calling before the final reports
+extern void VGA_(final_tidyup)(ThreadId tid);
+
+// Arch-specific client requests
+extern Bool VGA_(client_requests)(ThreadId tid, UWord *args);
/* ---------------------------------------------------------------------
Profiling stuff
@@ -486,37 +465,16 @@
#define VG_USERREQ__MALLOC 0x2001
#define VG_USERREQ__FREE 0x2002
-/* (Fn, Arg): Create a new thread and run Fn applied to Arg in it. Fn
- MUST NOT return -- ever. Eventually it will do either __QUIT or
- __WAIT_JOINER. */
+/* Obsolete pthread-related requests */
#define VG_USERREQ__APPLY_IN_NEW_THREAD 0x3001
-
-/* ( no-args ): calling thread disappears from the system forever.
- Reclaim resources. */
#define VG_USERREQ__QUIT 0x3002
-
-/* ( void* ): calling thread waits for joiner and returns the void* to
- it. */
#define VG_USERREQ__WAIT_JOINER 0x3003
-
-/* ( ThreadId, void** ): wait to join a thread. */
#define VG_USERREQ__PTHREAD_JOIN 0x3004
-
-/* Set cancellation state and type for this thread. */
#define VG_USERREQ__SET_CANCELSTATE 0x3005
#define VG_USERREQ__SET_CANCELTYPE 0x3006
-
-/* ( no-args ): Test if we are at a cancellation point. */
#define VG_USERREQ__TESTCANCEL 0x3007
-
-/* ( ThreadId, &thread_exit_wrapper is the only allowable arg ): call
- with this arg to indicate that a cancel is now pending for the
- specified thread. */
#define VG_USERREQ__SET_CANCELPEND 0x3008
-
-/* Set/get detach state for this thread. */
#define VG_USERREQ__SET_OR_GET_DETACH 0x3009
-
#define VG_USERREQ__PTHREAD_GET_THREADID 0x300A
#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x300B
#define VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK 0x300C
@@ -530,56 +488,39 @@
#define VG_USERREQ__PTHREAD_KEY_DELETE 0x3014
#define VG_USERREQ__PTHREAD_SETSPECIFIC_PTR 0x3015
#define VG_USERREQ__PTHREAD_GETSPECIFIC_PTR 0x3016
-#define VG_USERREQ__READ_MILLISECOND_TIMER 0x3017
#define VG_USERREQ__PTHREAD_SIGMASK 0x3018
-#define VG_USERREQ__SIGWAIT 0x3019 /* unused */
+#define VG_USERREQ__SIGWAIT 0x3019
#define VG_USERREQ__PTHREAD_KILL 0x301A
#define VG_USERREQ__PTHREAD_YIELD 0x301B
#define VG_USERREQ__PTHREAD_KEY_VALIDATE 0x301C
-
#define VG_USERREQ__CLEANUP_PUSH 0x3020
#define VG_USERREQ__CLEANUP_POP 0x3021
#define VG_USERREQ__GET_KEY_D_AND_S 0x3022
-
#define VG_USERREQ__NUKE_OTHER_THREADS 0x3023
-
-/* Ask how many signal handler returns have happened to this
- thread. */
-#define VG_USERREQ__GET_N_SIGS_RETURNED 0x3024 /* unused */
-
-/* Get/set entries for a thread's pthread_atfork stack. */
+#define VG_USERREQ__GET_N_SIGS_RETURNED 0x3024
#define VG_USERREQ__SET_FHSTACK_USED 0x3025
#define VG_USERREQ__GET_FHSTACK_USED 0x3026
#define VG_USERREQ__SET_FHSTACK_ENTRY 0x3027
#define VG_USERREQ__GET_FHSTACK_ENTRY 0x3028
-
-/* Denote the finish of __libc_freeres_wrapper(). */
-#define VG_USERREQ__LIBC_FREERES_DONE 0x3029
-
-/* Allocate RT signals */
#define VG_USERREQ__GET_SIGRT_MIN 0x302B
#define VG_USERREQ__GET_SIGRT_MAX 0x302C
#define VG_USERREQ__ALLOC_RTSIG 0x302D
-
-/* Hook for replace_malloc.o to get malloc functions */
#define VG_USERREQ__GET_MALLOCFUNCS 0x3030
-
-/* Get stack information for a thread. */
#define VG_USERREQ__GET_STACK_INFO 0x3033
-
-/* Cosmetic ... */
#define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101
-/* Log a pthread error from client-space. Cosmetic. */
#define VG_USERREQ__PTHREAD_ERROR 0x3102
+
+
+#define VG_USERREQ__READ_MILLISECOND_TIMER 0x3017
+
/* Internal equivalent of VALGRIND_PRINTF . */
#define VG_USERREQ__INTERNAL_PRINTF 0x3103
/* Internal equivalent of VALGRIND_PRINTF_BACKTRACE . */
#define VG_USERREQ__INTERNAL_PRINTF_BACKTRACE 0x3104
-/*
-In core_asm.h:
-#define VG_USERREQ__SIGNAL_RETURNS 0x4001
-*/
+/* Denote the finish of __libc_freeres_wrapper().
+ A synonym for exit. */
+#define VG_USERREQ__LIBC_FREERES_DONE 0x3029
#define VG_INTERCEPT_PREFIX "_vgi__"
#define VG_INTERCEPT_PREFIX_LEN 6
@@ -618,110 +559,41 @@
extern Bool VG_(tl_malloc_called_by_scheduler);
-/* ---------------------------------------------------------------------
- Exports of vg_libpthread.c
- ------------------------------------------------------------------ */
-
-/* Replacements for pthread types, shared between vg_libpthread.c and
- vg_scheduler.c. See comment in vg_libpthread.c above the other
- vg_pthread_*_t types for a description of how these are used. */
-
-struct _vg_pthread_fastlock
-{
- long int __vg_status; /* "Free" or "taken" or head of waiting list */
- int __vg_spinlock; /* Used by compare_and_swap emulation. Also,
- adaptive SMP lock stores spin count here. */
-};
-
-typedef struct
-{
- int __vg_m_reserved; /* Reserved for future use */
- int __vg_m_count; /* Depth of recursive locking */
- /*_pthread_descr*/ void* __vg_m_owner; /* Owner thread (if recursive or errcheck) */
- int __vg_m_kind; /* Mutex kind: fast, recursive or errcheck */
- struct _vg_pthread_fastlock __vg_m_lock; /* Underlying fast lock */
-} vg_pthread_mutex_t;
-
-typedef struct
-{
- struct _vg_pthread_fastlock __vg_c_lock; /* Protect against concurrent access */
- /*_pthread_descr*/ void* __vg_c_waiting; /* Threads waiting on this condition */
-
- // Nb: the following padding removed because it was missing from an
- // earlier glibc, so the size test in the CONVERT macro was failing.
- // --njn
-
- // Padding ensures the size is 48 bytes
- /*char __vg_padding[48 - sizeof(struct _vg_pthread_fastlock)
- - sizeof(void*) - sizeof(long long)];
- long long __vg_align;*/
-} vg_pthread_cond_t;
-
/* ---------------------------------------------------------------------
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_Runnable, /* waiting to be scheduled */
- VgTs_WaitJoiner, /* waiting for someone to do join on me */
- VgTs_WaitJoinee, /* waiting for the thread I did join on */
- VgTs_WaitMX, /* waiting on a mutex */
- VgTs_WaitCV, /* waiting on a condition variable */
+ VgTs_Init, /* just allocated */
+ VgTs_Runnable, /* ready to run */
VgTs_WaitSys, /* waiting for a syscall to complete */
- VgTs_Sleeping, /* sleeping for a while */
+ VgTs_Yielding, /* temporarily yielding the CPU */
+ VgTs_Zombie, /* transient state just before exiting */
}
ThreadStatus;
+/* Return codes from the scheduler. */
typedef
- enum CleanupType {
- VgCt_None, /* this cleanup entry is not initialised */
- VgCt_Function, /* an old-style function pointer cleanup */
- VgCt_Longjmp /* a new-style longjmp based cleanup */
+ 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 */
}
- CleanupType;
+ VgSchedReturnCode;
-/* Information on a thread's stack. */
-typedef
- struct {
- Addr base;
- UInt size;
- UInt guardsize;
- }
- StackInfo;
-
-/* An entry in a threads's cleanup stack. */
-typedef
- struct {
- CleanupType type;
- union {
- struct {
- void (*fn)(void*);
- void* arg;
- } function;
- struct {
- void *ub;
- int ctype;
- } longjmp;
- } data;
- }
- CleanupEntry;
-
-/* An entry in a thread's fork-handler stack. */
-typedef
- struct {
- void (*prepare)(void);
- void (*parent)(void);
- void (*child)(void);
- }
- ForkHandlerEntry;
-
-typedef struct ProxyLWP ProxyLWP;
-
-//typedef
- struct _ThreadState {
+struct _ThreadState {
/* 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
@@ -731,103 +603,45 @@
ALWAYS == the index in vg_threads[]. */
ThreadId tid;
- /* Current scheduling status.
-
- Complications: whenever this is set to VgTs_WaitMX, you
- should also set .m_edx to whatever the required return value
- is for pthread_mutex_lock / pthread_cond_timedwait for when
- the mutex finally gets unblocked. */
+ /* Current scheduling status. */
ThreadStatus status;
- /* When .status == WaitMX, points to the mutex I am waiting for.
- When .status == WaitCV, points to the mutex associated with
- the condition variable indicated by the .associated_cv field.
- In all other cases, should be NULL. */
- vg_pthread_mutex_t* associated_mx;
+ /* 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;
- /* When .status == WaitCV, points to the condition variable I am
- waiting for. In all other cases, should be NULL. */
- void* /*pthread_cond_t* */ associated_cv;
-
- /* If VgTs_Sleeping, this is when we should wake up, measured in
- milliseconds as supplied by VG_(read_millisecond_timer).
-
- If VgTs_WaitCV, this indicates the time at which
- pthread_cond_timedwait should wake up. If == 0xFFFFFFFF,
- this means infinitely far in the future, viz,
- pthread_cond_wait. */
- UInt awaken_at;
-
- /* If VgTs_WaitJoiner, return value, as generated by joinees. */
- void* joinee_retval;
-
- /* If VgTs_WaitJoinee, place to copy the return value to, and
- the identity of the thread we're waiting for. */
- void** joiner_thread_return;
- ThreadId joiner_jee_tid;
-
- /* If VgTs_WaitSys, this is the syscall we're currently running */
- Int syscallno;
-
- /* If VgTs_WaitSys, this is the syscall flags */
- UInt sys_flags;
-
- /* Details about this thread's proxy LWP */
- ProxyLWP *proxy;
-
- /* Whether or not detached. */
- Bool detached;
-
- /* Cancelability state and type. */
- Bool cancel_st; /* False==PTH_CANCEL_DISABLE; True==.._ENABLE */
- Bool cancel_ty; /* False==PTH_CANC_ASYNCH; True==..._DEFERRED */
-
- /* Pointer to fn to call to do cancellation. Indicates whether
- or not cancellation is pending. If NULL, not pending. Else
- should be &thread_exit_wrapper(), indicating that
- cancallation is pending. */
- void (*cancel_pend)(void*);
-
- /* The cleanup stack. */
- Int custack_used;
- CleanupEntry custack[VG_N_CLEANUPSTACK];
-
- /* A pointer to the thread's-specific-data. This is handled almost
- entirely from vg_libpthread.c. We just provide hooks to get and
- set this ptr. This is either NULL, indicating the thread has
- read/written none of its specifics so far, OR points to a
- void*[VG_N_THREAD_KEYS], allocated and deallocated in
- vg_libpthread.c. */
- void** specifics_ptr;
+ /* 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.
-
- sig_mask reflects what the client told us its signal mask should
- be, but isn't necessarily the current signal mask of the proxy
- LWP: it may have more signals blocked because of signal
- handling, or it may be different because of sigsuspend.
- */
+ thread unblocks it or someone uses sigwaitsig/sigtimedwait. */
vki_sigset_t sig_mask;
- /* Effective signal mask. This is the mask which currently
- applies; it may be different from sig_mask while a signal
- handler is running.
- */
- vki_sigset_t eff_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;
- /* Signal queue. This is used when the kernel doesn't route
- signals properly in order to remember the signal information
- while we are routing the signal. It is a circular queue with
- insertions performed at the head and removals at the tail.
- */
- vki_siginfo_t sigqueue[VG_N_SIGNALQUEUE];
- Int sigqueue_head;
- Int sigqueue_tail;
+ /* 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;
+
+ /* A value the Tool wants to pass from its pre-syscall to its
+ post-syscall function. */
+ void *tool_pre_syscall_value;
/* 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
@@ -848,10 +662,6 @@
*/
Addr stack_base;
- /* The allocated size of this thread's stack's guard area (permanently
- zero if this is ThreadId == 0, since we didn't allocate its stack) */
- UInt stack_guard_size;
-
/* 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
@@ -861,61 +671,95 @@
/* Alternate signal stack */
vki_stack_t altstack;
- /* Architecture-specific thread state */
- ThreadArchState arch;
+ /* 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;
+
+ /* Info about the signal we just got */
+ vki_siginfo_t siginfo;
};
//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 );
+extern void VG_(nuke_all_threads_except) ( ThreadId me, VgSchedReturnCode reason );
-/* Give a hint to the scheduler that it may be a good time to find a
- new runnable thread. If prefer_sched != VG_INVALID_THREADID, then
- try to schedule that thread.
-*/
-extern void VG_(need_resched) ( ThreadId prefer_sched );
+/* 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 );
-/* Return codes from the scheduler. */
-typedef
- enum {
- VgSrc_Deadlock, /* no runnable threads and no prospect of any
- even if we wait for a long time */
- VgSrc_ExitSyscall, /* client called exit(). This is the normal
- route out. */
- VgSrc_FatalSig /* Killed by the default action of a fatal
- signal */
- }
- VgSchedReturnCode;
+/* 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. 'fatal_sigNo' is only set if VgSrc_FatalSig is returned.
-extern VgSchedReturnCode VG_(scheduler)
- ( Int* exit_code, ThreadId* last_run_thread, Int* fatal_sigNo );
+// 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)(ThreadId tid);
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) ( Int sigNo, vki_siginfo_t *info );
+extern void VG_(resume_scheduler) ( ThreadId tid );
-// Longjmp, ending the scheduler, when a fatal signal occurs in the client.
-extern void VG_(scheduler_handle_fatal_signal)( Int sigNo );
+/* If true, a fault is Valgrind-internal (ie, a bug) */
+extern Bool VG_(my_fault);
/* The red-zone size which we put at the bottom (highest address) of
thread stacks, for paranoia reasons. This can be arbitrary, and
@@ -946,32 +790,34 @@
SET_THREAD_REG(zztid, zzval, PTHREQ_RET, post_reg_write, \
Vg_CorePThread, zztid, O_PTHREQ_RET, sizeof(UWord))
-
/* ---------------------------------------------------------------------
Exports of vg_signals.c
------------------------------------------------------------------ */
-extern Bool VG_(do_signal_routing); /* whether scheduler LWP has to route signals */
+/* Set the standard set of blocked signals, used wheneever we're not
+ running a client syscall. */
+extern void VG_(block_signals)(ThreadId tid);
-/* RT signal allocation */
-extern Int VG_(sig_rtmin);
-extern Int VG_(sig_rtmax);
-extern Int VG_(sig_alloc_rtsig) ( Int high );
+/* Highest signal the kernel will let us use */
+extern Int VG_(max_signal);
extern void VG_(sigstartup_actions) ( void );
-extern void VG_(deliver_signal) ( ThreadId tid, const vki_siginfo_t *, Bool async );
-extern void VG_(unblock_host_signal) ( Int sigNo );
+/* Modify a thread's state so that when it next runs it will be
+ running in the signal handler (or doing the default action if there
+ is none). */
+extern void VG_(deliver_signal) ( ThreadId tid, const vki_siginfo_t * );
extern Bool VG_(is_sig_ign) ( Int sigNo );
-/* Route pending signals from the scheduler LWP to the appropriate
- thread LWP. */
-extern void VG_(route_signals) ( void );
+/* Poll a thread's set of pending signals, and update the Thread's context to deliver one */
+extern void VG_(poll_signals) ( ThreadId );
/* Fake system calls for signal handling. */
extern void VG_(do_sys_sigaltstack) ( ThreadId tid );
-extern void VG_(do_sys_sigaction) ( ThreadId tid );
+extern Int VG_(do_sys_sigaction) ( Int signo,
+ const struct vki_sigaction *new_act,
+ struct vki_sigaction *old_act );
extern void VG_(do_sys_sigprocmask) ( ThreadId tid, Int how,
vki_sigset_t* set,
vki_sigset_t* oldset );
@@ -979,10 +825,6 @@
vki_sigset_t* set,
vki_sigset_t* oldset );
-/* Modify the current thread's state once we have detected it is
- returning from a signal handler. */
-extern Bool VG_(signal_returns) ( ThreadId tid );
-
/* Handy utilities to block/restore all host signals. */
extern void VG_(block_all_host_signals)
( /* OUT */ vki_sigset_t* saved_mask );
@@ -1001,6 +843,21 @@
extern void VG_(get_sigstack_bounds)( Addr* low, Addr* high );
+/* Extend the stack to cover addr, if possible */
+extern Bool VG_(extend_stack)(Addr addr, UInt maxsize);
+
+/* Returns True if the signal is OK for the client to use */
+extern Bool VG_(client_signal_OK)(Int sigNo);
+
+/* Forces the client's signal handler to SIG_DFL - generally just
+ before using that signal to kill the process. */
+extern void VG_(set_default_handler)(Int sig);
+
+/* Adjust a client's signal mask to match our internal requirements */
+extern void VG_(sanitize_client_sigmask)(ThreadId tid, vki_sigset_t *mask);
+
+/* Wait until a thread-related predicate is true */
+extern void VG_(wait_for_threadstate)(Bool (*pred)(void *), void *arg);
/* ---------------------------------------------------------------------
Exports of vg_mylibc.c
@@ -1053,7 +910,7 @@
extern void VG_(env_unsetenv) ( Char **env, const Char *varname );
extern void VG_(env_remove_valgrind_env_stuff) ( Char** env );
-
+extern void VG_(nanosleep)(struct vki_timespec *);
/* ---------------------------------------------------------------------
Exports of vg_message.c
------------------------------------------------------------------ */
@@ -1063,10 +920,9 @@
extern void VG_(send_bytes_to_logging_sink) ( Char* msg, Int nbytes );
// Functions for printing from code within Valgrind, but which runs on the
-// sim'd CPU. Defined here because needed for vg_libpthread.c,
-// vg_replace_malloc.c, plus the rest of the core. The weak attribute
-// ensures the multiple definitions are not a problem. They must be functions
-// rather than macros so that va_list can be used.
+// sim'd CPU. Defined here because needed for vg_replace_malloc.c. The
+// weak attribute ensures the multiple definitions are not a problem. They
+// must be functions rather than macros so that va_list can be used.
__attribute__((weak))
int
@@ -1101,6 +957,7 @@
extern void VG_(demangle) ( Char* orig, Char* result, Int result_size );
+extern void VG_(reloc_abs_jump) ( UChar *jmp );
/* ---------------------------------------------------------------------
Exports of vg_translate.c
@@ -1142,9 +999,14 @@
Exports of vg_errcontext.c.
------------------------------------------------------------------ */
-extern void VG_(load_suppressions) ( void );
+typedef
+ enum {
+ ThreadErr = -1, // Thread error
+ MutexErr = -2, // Mutex error
+ }
+ CoreErrorKind;
-extern void VG_(record_pthread_error) ( ThreadId tid, Char* msg );
+extern void VG_(load_suppressions) ( void );
extern void VG_(show_all_errors) ( void );
@@ -1157,16 +1019,10 @@
Exports of vg_procselfmaps.c
------------------------------------------------------------------ */
-/* Reads /proc/self/maps into a static buffer which can be parsed by
- VG_(parse_procselfmaps)(). */
-extern void VG_(read_procselfmaps) ( void );
-
-/* Parses /proc/self/maps, calling `record_mapping' for each entry. If
- `read_from_file' is True, /proc/self/maps is read directly, otherwise
- it's read from the buffer filled by VG_(read_procselfmaps_contents)(). */
+/* Parses /proc/self/maps, calling `record_mapping' for each entry. */
extern
void VG_(parse_procselfmaps) (
- void (*record_mapping)( Addr addr, SizeT len, Char rr, Char ww, Char xx,
+ void (*record_mapping)( Addr addr, SizeT len, UInt prot,
UInt dev, UInt ino, ULong foff,
const UChar *filename ) );
@@ -1176,6 +1032,7 @@
------------------------------------------------------------------ */
typedef struct _Segment Segment;
+typedef struct _CodeRedirect CodeRedirect;
extern Bool VG_(is_object_file) ( const void *hdr );
extern void VG_(mini_stack_dump) ( Addr ips[], UInt n_ips );
@@ -1185,12 +1042,46 @@
extern Bool VG_(get_fnname_nodemangle)( Addr a, Char* fnname, Int n_fnname );
+extern Addr VG_(reverse_search_one_symtab) ( const SegInfo* si, const Char* name );
+
/* Set up some default redirects */
extern void VG_(setup_code_redirect_table) ( void );
+extern Bool VG_(resolve_redir_allsegs)(CodeRedirect *redir);
+
+/* ---------------------------------------------------------------------
+ Exports of vg_redir.c
+ ------------------------------------------------------------------ */
/* Redirection machinery */
extern Addr VG_(code_redirect) ( Addr orig );
+extern void VG_(add_redirect_addr)(const Char *from_lib, const Char *from_sym,
+ Addr to_addr);
+extern void VG_(resolve_seg_redirs)(SegInfo *si);
+extern Bool VG_(resolve_redir)(CodeRedirect *redir, const SegInfo *si);
+
+/* Wrapping machinery */
+enum return_type {
+ RT_RETURN,
+ RT_LONGJMP,
+ RT_EXIT,
+};
+
+typedef struct _FuncWrapper FuncWrapper;
+struct _FuncWrapper {
+ void *(*before)(va_list args);
+ void (*after) (void *nonce, enum return_type, Word retval);
+};
+
+extern void VG_(wrap_function)(Addr eip, const FuncWrapper *wrapper);
+extern const FuncWrapper *VG_(is_wrapped)(Addr eip);
+extern Bool VG_(is_wrapper_return)(Addr eip);
+
+/* Primary interface for adding wrappers for client-side functions. */
+extern CodeRedirect *VG_(add_wrapper)(const Char *from_lib, const Char *from_sym,
+ const FuncWrapper *wrapper);
+
+extern Bool VG_(is_resolved)(const CodeRedirect *redir);
/* ---------------------------------------------------------------------
Exports of vg_main.c
@@ -1228,6 +1119,12 @@
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 )
@@ -1274,6 +1171,7 @@
#define SF_CORE (1 << 12) // allocated by core on behalf of the client
#define SF_VALGRIND (1 << 13) // a valgrind-internal mapping - not in client
#define SF_CODE (1 << 14) // segment contains cached code
+#define SF_DEVICE (1 << 15) // device mapping; avoid careless touching
struct _Segment {
UInt prot; // VKI_PROT_*
@@ -1321,42 +1219,22 @@
extern Bool VG_(seg_contains)(const Segment *s, Addr ptr, SizeT size);
extern Bool VG_(seg_overlaps)(const Segment *s, Addr ptr, SizeT size);
-extern void VG_(pad_address_space) (void);
-extern void VG_(unpad_address_space)(void);
+extern Segment *VG_(split_segment)(Addr a);
+
+extern void VG_(pad_address_space) (Addr start);
+extern void VG_(unpad_address_space)(Addr start);
extern REGPARM(2)
void VG_(unknown_SP_update) ( Addr old_SP, Addr new_SP );
-/* ---------------------------------------------------------------------
- Exports of vg_proxylwp.c
- ------------------------------------------------------------------ */
+///* Search /proc/self/maps for changes which aren't reflected in the
+// segment list */
+//extern void VG_(sync_segments)(UInt flags);
-/* Issue a syscall for thread tid */
-extern Int VG_(sys_issue)(ThreadId tid);
+/* Return string for prot */
+extern const HChar *VG_(prot_str)(UInt prot);
-extern void VG_(proxy_init) ( void );
-extern void VG_(proxy_create) ( ThreadId tid );
-extern void VG_(proxy_delete) ( ThreadId tid, Bool force );
-extern void VG_(proxy_results) ( void );
-extern void VG_(proxy_sendsig) ( ThreadId fromTid, ThreadId toTid, Int signo );
-extern void VG_(proxy_setsigmask)(ThreadId tid);
-extern void VG_(proxy_sigack) ( ThreadId tid, const vki_sigset_t *);
-extern void VG_(proxy_abort_syscall) ( ThreadId tid );
-extern void VG_(proxy_waitsig) ( void );
-extern void VG_(proxy_wait_sys) (ThreadId tid, Bool restart);
-
-extern void VG_(proxy_shutdown) ( void ); // shut down the syscall workers
-extern Int VG_(proxy_resfd) ( void ); // FD something can select on to know
- // a syscall finished
-
-/* Sanity-check the whole proxy-LWP machinery */
-void VG_(sanity_check_proxy)(void);
-
-/* Send a signal from a thread's proxy to the thread. This longjmps
- back into the proxy's main loop, so it doesn't return. */
-__attribute__ ((__noreturn__))
-extern void VG_(proxy_handlesig)( const vki_siginfo_t *siginfo,
- Addr ip, Int sysnum );
+//extern void VG_(print_shadow_stats)();
/* ---------------------------------------------------------------------
Exports of vg_syscalls.c
@@ -1365,8 +1243,15 @@
extern HChar* VG_(resolve_filename_nodup)(Int fd);
extern HChar* VG_(resolve_filename)(Int fd);
-extern Bool VG_(pre_syscall) ( ThreadId tid );
-extern void VG_(post_syscall)( ThreadId tid, Bool restart );
+/* Simple Valgrind-internal atfork mechanism */
+extern void VG_(do_atfork_pre) (ThreadId tid);
+extern void VG_(do_atfork_parent)(ThreadId tid);
+extern void VG_(do_atfork_child) (ThreadId tid);
+
+
+extern void VG_(client_syscall) ( ThreadId tid );
+
+extern void VG_(post_syscall) ( ThreadId tid );
extern Bool VG_(is_kerror) ( Word res );
@@ -1389,10 +1274,11 @@
void VG_(record_fd_open)(ThreadId tid, Int fd, char *pathname);
// Flags describing syscall wrappers
-#define Special (1 << 0)
-#define MayBlock (1 << 1)
-#define NBRunInLWP (1 << 2) // non-blocking, but must run in LWP context
-#define PostOnFail (1 << 3)
+#define Special (1 << 0) /* handled specially */
+#define MayBlock (1 << 1) /* may block */
+#define PostOnFail (1 << 2) /* call POST() function on failure */
+#define PadAddr (1 << 3) /* pad+unpad address space around syscall */
+#define Done (1 << 4) /* used if a PRE() did the syscall */
// Templates for generating the PRE and POST macros. For ones that must be
// publically visible, use an empty 'qual', 'prefix' should start with
@@ -1509,6 +1395,7 @@
GEN_SYSCALL_WRAPPER(sys_munlockall);
GEN_SYSCALL_WRAPPER(sys_sched_setparam);
GEN_SYSCALL_WRAPPER(sys_sched_getparam);
+GEN_SYSCALL_WRAPPER(sys_sched_rr_get_interval);
GEN_SYSCALL_WRAPPER(sys_sched_setscheduler);
GEN_SYSCALL_WRAPPER(sys_sched_getscheduler);
GEN_SYSCALL_WRAPPER(sys_sched_yield);
@@ -1533,6 +1420,7 @@
GEN_SYSCALL_WRAPPER(sys_clock_settime);
GEN_SYSCALL_WRAPPER(sys_clock_gettime);
GEN_SYSCALL_WRAPPER(sys_clock_getres);
+GEN_SYSCALL_WRAPPER(sys_clock_nanosleep);
GEN_SYSCALL_WRAPPER(sys_getcwd);
GEN_SYSCALL_WRAPPER(sys_symlink);
GEN_SYSCALL_WRAPPER(sys_getgroups);
@@ -1557,6 +1445,7 @@
GEN_SYSCALL_WRAPPER(sys_flock); // 4.4BSD
GEN_SYSCALL_WRAPPER(sys_poll); // XPG4-UNIX
GEN_SYSCALL_WRAPPER(sys_getrusage); // SVr4, 4.3BSD
+GEN_SYSCALL_WRAPPER(sys_stime); // SVr4, SVID, X/OPEN
GEN_SYSCALL_WRAPPER(sys_settimeofday); // SVr4, 4.3BSD (non-POSIX)
GEN_SYSCALL_WRAPPER(sys_getpriority); // SVr4, 4.4BSD
GEN_SYSCALL_WRAPPER(sys_setpriority); // SVr4, 4.4BSD
@@ -1652,7 +1541,6 @@
GEN_SYSCALL_WRAPPER(sys_fremovexattr); // * L?
GEN_SYSCALL_WRAPPER(sys_sched_setaffinity); // * L?
GEN_SYSCALL_WRAPPER(sys_sched_getaffinity); // * L?
-GEN_SYSCALL_WRAPPER(sys_exit_group); // * ?
GEN_SYSCALL_WRAPPER(sys_lookup_dcookie); // (*/32/64) L
GEN_SYSCALL_WRAPPER(sys_set_tid_address); // * ?
GEN_SYSCALL_WRAPPER(sys_statfs64); // * (?)
@@ -1663,6 +1551,9 @@
GEN_SYSCALL_WRAPPER(sys_mq_timedreceive); // * P?
GEN_SYSCALL_WRAPPER(sys_mq_notify); // * P?
GEN_SYSCALL_WRAPPER(sys_mq_getsetattr); // * P?
+GEN_SYSCALL_WRAPPER(sys_tkill); // * L
+GEN_SYSCALL_WRAPPER(sys_tgkill); // * L
+GEN_SYSCALL_WRAPPER(sys_gettid); // * L?
#undef GEN_SYSCALL_WRAPPER
@@ -1769,6 +1660,7 @@
extern ULong* VG_(tt_fast) [VG_TT_FAST_SIZE];
extern UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
+
extern void VG_(init_tt_tc) ( void );
extern
@@ -1813,7 +1705,7 @@
#define vgPlain_do_syscall6(s,a,b,c,d,e,f) VG_(do_syscall)((s),(a),(b),(c),(d),(e),(f))
extern Int VG_(clone) ( Int (*fn)(void *), void *stack, Int flags, void *arg,
- Int *child_tid, Int *parent_tid);
+ Int *child_tid, Int *parent_tid, vki_modify_ldt_t * );
extern void VG_(sigreturn)(void);
/* ---------------------------------------------------------------------
@@ -1843,6 +1735,7 @@
extern const Char VG_(trampoline_code_start);
extern const Int VG_(trampoline_code_length);
extern const Int VG_(tramp_sigreturn_offset);
+extern const Int VG_(tramp_rt_sigreturn_offset);
extern const Int VG_(tramp_syscall_offset);
/* ---------------------------------------------------------------------
@@ -1865,24 +1758,18 @@
// Returns the architecture and subarchitecture, or indicates
// that this subarchitecture is unable to run Valgrind
// Returns False to indicate we cannot proceed further.
-
extern Bool VGA_(getArchAndSubArch)( /*OUT*/VexArch*,
/*OUT*/VexSubArch* );
-
// Accessors for the ThreadArchState
#define INSTR_PTR(regs) ((regs).vex.ARCH_INSTR_PTR)
#define STACK_PTR(regs) ((regs).vex.ARCH_STACK_PTR)
#define FRAME_PTR(regs) ((regs).vex.ARCH_FRAME_PTR)
-
#define CLREQ_ARGS(regs) ((regs).vex.ARCH_CLREQ_ARGS)
#define PTHREQ_RET(regs) ((regs).vex.ARCH_PTHREQ_RET)
#define CLREQ_RET(regs) ((regs).vex.ARCH_CLREQ_RET)
-
-
// Offsets for the Vex state
#define O_STACK_PTR (offsetof(VexGuestArchState, ARCH_STACK_PTR))
#define O_FRAME_PTR (offsetof(VexGuestArchState, ARCH_FRAME_PTR))
-
#define O_CLREQ_RET (offsetof(VexGuestArchState, ARCH_CLREQ_RET))
#define O_PTHREQ_RET (offsetof(VexGuestArchState, ARCH_PTHREQ_RET))
@@ -1900,6 +1787,32 @@
extern void VGA_(set_arg_and_bogus_ret) ( ThreadId tid, UWord arg, Addr ret );
extern void VGA_(thread_initial_stack) ( ThreadId tid, UWord arg, Addr ret );
+// OS/Platform-specific thread clear (after thread exit)
+extern void VGA_(os_state_clear)(ThreadState *);
+
+// OS/Platform-specific thread init (at scheduler init time)
+extern void VGA_(os_state_init)(ThreadState *);
+
+// Run a thread from beginning to end. Does not return if tid == VG_(master_tid).
+void VGA_(thread_wrapper)(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__));
+
+// Return how many bytes of a thread's Valgrind stack are unused
+Int VGA_(stack_unused)(ThreadId tid);
+
+// Terminate the process. Does not return.
+void VGA_(terminate)(ThreadId tid, VgSchedReturnCode src) __attribute__((__noreturn__));
+
+// wait until all other threads are dead
+extern void VGA_(reap_threads)(ThreadId self);
+
+// handle an arch-specific client request
+extern Bool VGA_(client_request)(ThreadId tid, UWord *args);
+
// Symtab stuff
extern UInt* VGA_(reg_addr_from_tst) ( Int regno, ThreadArchState* );
@@ -1909,22 +1822,17 @@
// For attaching the debugger
extern Int VGA_(ptrace_setregs_from_tst) ( Int pid, ThreadArchState* arch );
+// Used by leakcheck
+extern void VGA_(mark_from_registers)(ThreadId tid, void (*marker)(Addr));
+
// Signal stuff
extern void VGA_(push_signal_frame) ( ThreadId tid, Addr sp_top_of_frame,
const vki_siginfo_t *siginfo,
void *handler, UInt flags,
- const vki_sigset_t *mask);
-extern Int VGA_(pop_signal_frame) ( ThreadId tid );
+ const vki_sigset_t *mask,
+ void *restorer );
-// libpthread stuff
-typedef struct _ThreadArchAux ThreadArchAux;
-
-void VGA_(thread_create) ( ThreadArchAux *aux );
-void VGA_(thread_wrapper)( ThreadArchAux *aux );
-void VGA_(thread_exit) ( void );
-
-Bool VGA_(has_tls) ( void );
-
+////typedef struct _ThreadArchAux ThreadArchAux;
#define MY__STRING(__str) #__str
// Assertion to use in code running on the simulated CPU.
@@ -1964,7 +1872,7 @@
struct SyscallTableEntry {
UInt *flags_ptr;
- void (*before)(ThreadId tid, ThreadState *tst);
+ void (*before)(ThreadId tid, ThreadState *tst /*, UInt *flags*/);
void (*after) (ThreadId tid, ThreadState *tst);
};
@@ -1984,54 +1892,67 @@
extern void VGA_(restart_syscall)(ThreadArchState* arch);
-/* We need our own copy of VG_(do_syscall)() to handle a special
- race-condition. If we've got signals unblocked, and we take a
- signal in the gap either just before or after the syscall, we may
- end up not running the syscall at all, or running it more than
- once.
-
- The solution is to make the signal handler derive the proxy's
- precise state by looking to see which eip it is executing at
- exception time.
-
- Ranges:
-
- VGA_(sys_before) ... VGA_(sys_restarted):
- Setting up register arguments and running state. If
- interrupted, then the syscall should be considered to return
- ERESTARTSYS.
-
- VGA_(sys_restarted):
- If interrupted and eip==VGA_(sys_restarted), then either the syscall
- was about to start running, or it has run, was interrupted and
- the kernel wants to restart it. eax still contains the
- syscall number. If interrupted, then the syscall return value
- should be ERESTARTSYS.
-
- VGA_(sys_after):
- If interrupted and eip==VGA_(sys_after), the syscall either just
- finished, or it was interrupted and the kernel doesn't want to
- restart it. Either way, eax equals the correct return value
- (either the actual return value, or EINTR).
-
- VGA_(sys_after) ... VGA_(sys_done):
- System call is complete, but the state hasn't been updated,
- nor has the result been written back. eax contains the return
- value.
-
- Freakin' horrible...
+/*
+ Perform a syscall on behalf of a client thread, using a specific
+ signal mask. On completion, the signal mask is set to restore_mask
+ (which presumably blocks almost everything). If a signal happens
+ during the syscall, the handler should call
+ VGA_(interrupted_syscall)() to adjust the thread's context to do the
+ right thing.
*/
-extern const Addr VGA_(sys_before), VGA_(sys_restarted),
- VGA_(sys_after), VGA_(sys_done);
+extern void VGA_(client_syscall)(Int syscallno, ThreadState *tst,
+ const vki_sigset_t *syscall_mask);
-extern void VGA_(do_thread_syscall)
- ( UWord sys,
- UWord arg1, UWord arg2, UWord arg3,
- UWord arg4, UWord arg5, UWord arg6,
- /*OUT*/HWord *resultP,
- /*enum PXState*/Int *stateP,
- /*enum PXState*/Int poststate
- );
+/*
+ Fix up the thread's state because a syscall may have been
+ interrupted with a signal. Returns True if the syscall completed
+ (either interrupted or finished normally), or False if it was
+ restarted (or the signal didn't actually interrupt a syscall).
+ */
+extern void VGA_(interrupted_syscall)(ThreadId tid,
+ struct vki_ucontext *uc,
+ Bool restart);
+
+
+///* ---------------------------------------------------------------------
+// Thread modelling
+// ------------------------------------------------------------------ */
+//extern void VG_(tm_thread_create) (ThreadId creator, ThreadId tid, Bool detached);
+//extern void VG_(tm_thread_exit) (ThreadId tid);
+//extern Bool VG_(tm_thread_exists) (ThreadId tid);
+//extern void VG_(tm_thread_detach) (ThreadId tid);
+//extern void VG_(tm_thread_join) (ThreadId joiner, ThreadId joinee);
+//extern void VG_(tm_thread_switchto)(ThreadId tid);
+//
+//extern void VG_(tm_mutex_init) (ThreadId tid, Addr mutexp);
+//extern void VG_(tm_mutex_destroy)(ThreadId tid, Addr mutexp);
+//extern void VG_(tm_mutex_trylock)(ThreadId tid, Addr mutexp);
+//extern void VG_(tm_mutex_giveup) (ThreadId tid, Addr mutexp);
+//extern void VG_(tm_mutex_acquire)(ThreadId tid, Addr mutexp);
+//extern void VG_(tm_mutex_tryunlock)(ThreadId tid, Addr mutexp);
+//extern void VG_(tm_mutex_unlock) (ThreadId tid, Addr mutexp);
+//extern Bool VG_(tm_mutex_exists) (Addr mutexp);
+//
+//extern UInt VG_(tm_error_update_extra) (Error *err);
+//extern Bool VG_(tm_error_equal) (VgRes res, Error *e1, Error *e2);
+//extern void VG_(tm_error_print) (Error *err);
+//
+//extern void VG_(tm_init) ();
+//
+//extern void VG_(tm_cond_init) (ThreadId tid, Addr condp);
+//extern void VG_(tm_cond_destroy) (ThreadId tid, Addr condp);
+//extern void VG_(tm_cond_wait) (ThreadId tid, Addr condp, Addr mutexp);
+//extern void VG_(tm_cond_wakeup) (ThreadId tid, Addr condp, Addr mutexp);
+//extern void VG_(tm_cond_signal) (ThreadId tid, Addr condp);
+//
+///* ----- pthreads ----- */
+//extern void VG_(pthread_init) ();
+//extern void VG_(pthread_startfunc_wrapper)(Addr wrapper);
+//
+//struct vg_pthread_newthread_data {
+// void *(*startfunc)(void *arg);
+// void *arg;
+//};
/* ---------------------------------------------------------------------
Finally - autoconf-generated settings