threads that valgrind can handle. No recompile is needed.
Part of fixing BZ #337869.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14932
searching/extracting errors in output files mixing valgrind
errors with program output.
+* New Option --max-threads=<number> can be used to increase the
+ number of threads valgrind can handle. The default is 500 threads
+ which should be more than enough for most applications.
+
* ==================== FIXED BUGS ====================
The following bugs have been fixed or resolved. Note that "n-i-bz"
/* struct timeval syscalltime[VG_N_THREADS]; */
#if CLG_MICROSYSTIME
-ULong syscalltime[VG_N_THREADS];
+ULong *syscalltime;
#else
-UInt syscalltime[VG_N_THREADS];
+UInt *syscalltime;
#endif
static
VG_(track_post_deliver_signal)( & CLG_(post_signal) );
CLG_(set_clo_defaults)();
+
+ syscalltime = CLG_MALLOC("cl.main.pci.1",
+ VG_N_THREADS * sizeof syscalltime[0]);
+ for (UInt i = 0; i < VG_N_THREADS; ++i) {
+ syscalltime[i] = 0;
+ }
}
VG_DETERMINE_INTERFACE_VERSION(CLG_(pre_clo_init))
/* current running thread */
ThreadId CLG_(current_tid);
-static thread_info* thread[VG_N_THREADS];
+static thread_info** thread;
thread_info** CLG_(get_threads)()
{
void CLG_(init_threads)()
{
- Int i;
+ UInt i;
+
+ thread = CLG_MALLOC("cl.threads.it.1", VG_N_THREADS * sizeof thread[0]);
+
for(i=0;i<VG_N_THREADS;i++)
thread[i] = 0;
CLG_(current_tid) = VG_INVALID_THREADID;
" recovered by stack scanning [5]\n"
" --resync-filter=no|yes|verbose [yes on MacOS, no on other OSes]\n"
" attempt to avoid expensive address-space-resync operations\n"
+" --max-threads=<number> maximum number of threads that valgrind can\n"
+" handle [%d]\n"
"\n";
const HChar usage2[] =
default_redzone_size /* char* */,
VG_(clo_vgdb_poll) /* int */,
VG_(vgdb_prefix_default)() /* char* */,
- N_SECTORS_DEFAULT /* int */
+ N_SECTORS_DEFAULT /* int */,
+ MAX_THREADS_DEFAULT /* int */
);
if (VG_(details).name) {
VG_(printf)(" user options for %s:\n", VG_(details).name);
else if VG_INT_CLO(str, "--max-stackframe", VG_(clo_max_stackframe)) {}
else if VG_INT_CLO(str, "--main-stacksize", VG_(clo_main_stacksize)) {}
+ // Set up VG_(clo_max_threads); needed for VG_(tl_pre_clo_init)
+ else if VG_INT_CLO(str, "--max-threads", VG_(clo_max_threads)) {}
+
// Set up VG_(clo_sim_hints). This is needed a.o. for an inner
// running in an outer, to have "no-inner-prefix" enabled
// as early as possible.
"no-nptl-pthread-stackcache",
VG_(clo_sim_hints)) {}
}
+
+ /* For convenience */
+ VG_N_THREADS = VG_(clo_max_threads);
}
/* The main processing for command line options. See comments above
else if VG_STREQ( arg, "-d") {}
else if VG_STREQN(17, arg, "--max-stackframe=") {}
else if VG_STREQN(17, arg, "--main-stacksize=") {}
+ else if VG_STREQN(14, arg, "--max-threads=") {}
else if VG_STREQN(12, arg, "--sim-hints=") {}
else if VG_STREQN(15, arg, "--profile-heap=") {}
else if VG_STREQN(20, arg, "--core-redzone-size=") {}
Bool VG_(clo_show_below_main)= False;
Bool VG_(clo_show_emwarns) = False;
Word VG_(clo_max_stackframe) = 2000000;
+UInt VG_(clo_max_threads) = MAX_THREADS_DEFAULT;
Word VG_(clo_main_stacksize) = 0; /* use client's rlimit.stack */
Bool VG_(clo_wait_for_gdb) = False;
VgSmc VG_(clo_smc_check) = Vg_SmcStack;
return i;
}
}
- VG_(printf)("vg_alloc_ThreadState: no free slots available\n");
- VG_(printf)("Increase VG_N_THREADS, rebuild and try again.\n");
- VG_(core_panic)("VG_N_THREADS is too low");
+ VG_(printf)("Use --max-threads=INT to specify a larger number of threads\n"
+ "and rerun valgrind\n");
+ VG_(core_panic)("Max number of threads is too low");
/*NOTREACHED*/
}
#include "pub_core_signals.h" // For VG_SIGVGKILL, VG_(poll_signals)
#include "pub_core_syscall.h"
#include "pub_core_machine.h"
+#include "pub_core_mallocfree.h"
#include "pub_core_syswrap.h"
#include "priv_types_n_macros.h"
}
SyscallInfo;
-SyscallInfo syscallInfo[VG_N_THREADS];
-
+SyscallInfo *syscallInfo;
/* The scheduler needs to be able to zero out these records after a
fork, hence this is exported from m_syswrap. */
void VG_(clear_syscallInfo) ( Int tid )
{
+ vg_assert(syscallInfo);
vg_assert(tid >= 0 && tid < VG_N_THREADS);
VG_(memset)( & syscallInfo[tid], 0, sizeof( syscallInfo[tid] ));
syscallInfo[tid].status.what = SsIdle;
if (init_done)
return;
init_done = True;
+
+ syscallInfo = VG_(malloc)("scinfo", VG_N_THREADS * sizeof syscallInfo[0]);
+
for (i = 0; i < VG_N_THREADS; i++) {
VG_(clear_syscallInfo)( i );
}
#include "pub_core_vki.h"
#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
#include "pub_core_threadstate.h"
+#include "pub_core_mallocfree.h" // VG_(malloc)
#include "pub_core_libcassert.h"
#include "pub_core_inner.h"
#if defined(ENABLE_INNER_CLIENT_REQUEST)
ThreadId VG_(running_tid) = VG_INVALID_THREADID;
-ThreadState VG_(threads)[VG_N_THREADS]
- __attribute__((aligned(LibVEX_GUEST_STATE_ALIGN)));
+ThreadState *VG_(threads);
+UInt VG_N_THREADS;
/*------------------------------------------------------------*/
/*--- Operations. ---*/
void VG_(init_Threads)(void)
{
ThreadId tid;
+ UChar *addr, *aligned_addr;
+
+ addr = VG_(malloc)("init_Threads",
+ VG_N_THREADS * sizeof VG_(threads)[0] + LibVEX_GUEST_STATE_ALIGN - 1);
+
+ // Align
+ aligned_addr = addr + (Addr)addr % LibVEX_GUEST_STATE_ALIGN;
+ VG_(threads) = (ThreadState *)aligned_addr;
for (tid = 1; tid < VG_N_THREADS; tid++) {
INNER_REQUEST(
be? */
extern Word VG_(clo_main_stacksize);
+/* The maximum number of threads we support. */
+#define MAX_THREADS_DEFAULT 500
+extern UInt VG_(clo_max_threads);
+
/* If the same IP is found twice in a backtrace in a sequence of max
VG_(clo_merge_recursive_frames) frames, then the recursive call
is merged in the backtrace.
/* A statically allocated array of threads. NOTE: [0] is
never used, to simplify the simulation of initialisers for
LinuxThreads. */
-extern ThreadState VG_(threads)[VG_N_THREADS];
+extern ThreadState *VG_(threads);
// The running thread. m_scheduler should be the only other module
// to write to this.
static ULong s_conflict_set_bitmap2_creation_count;
static ThreadId s_vg_running_tid = VG_INVALID_THREADID;
DrdThreadId DRD_(g_drd_running_tid) = DRD_INVALID_THREADID;
-ThreadInfo DRD_(g_threadinfo)[DRD_N_THREADS];
+ThreadInfo* DRD_(g_threadinfo);
struct bitmap* DRD_(g_conflict_set);
Bool DRD_(verify_conflict_set);
static Bool s_trace_context_switches = False;
void DRD_(thread_init)(void)
{
+ DRD_(g_threadinfo) = VG_(malloc)("drd.main.ti.1",
+ DRD_N_THREADS * sizeof DRD_(g_threadinfo)[0]);
+ for (UInt i = 0; i < DRD_N_THREADS; ++i) {
+ static ThreadInfo initval;
+ DRD_(g_threadinfo)[i] = initval;
+ }
}
/**
*/
DrdThreadId DRD_(VgThreadIdToDrdThreadId)(const ThreadId tid)
{
- int i;
+ UInt i;
if (tid == VG_INVALID_THREADID)
return DRD_INVALID_THREADID;
/** Allocate a new DRD thread ID for the specified Valgrind thread ID. */
static DrdThreadId DRD_(VgThreadIdToNewDrdThreadId)(const ThreadId tid)
{
- int i;
+ UInt i;
tl_assert(DRD_(VgThreadIdToDrdThreadId)(tid) == DRD_INVALID_THREADID);
/** Convert a POSIX thread ID into a DRD thread ID. */
DrdThreadId DRD_(PtThreadIdToDrdThreadId)(const PThreadId tid)
{
- int i;
+ UInt i;
if (tid != INVALID_POSIX_THREADID)
{
static void DRD_(thread_delayed_delete)(const DrdThreadId tid)
{
- int j;
+ UInt j;
DRD_(g_threadinfo)[tid].vg_thread_exists = False;
DRD_(g_threadinfo)[tid].posix_thread_exists = False;
Int DRD_(thread_get_threads_on_alt_stack)(void)
{
- int i, n = 0;
+ int n = 0;
- for (i = 1; i < DRD_N_THREADS; i++)
+ for (UInt i = 1; i < DRD_N_THREADS; i++)
n += DRD_(g_threadinfo)[i].on_alt_stack;
return n;
}
*/
extern DrdThreadId DRD_(g_drd_running_tid);
/** Per-thread information managed by DRD. */
-extern ThreadInfo DRD_(g_threadinfo)[DRD_N_THREADS];
+extern ThreadInfo* DRD_(g_threadinfo);
/** Conflict set for the currently running thread. */
extern struct bitmap* DRD_(g_conflict_set);
extern Bool DRD_(verify_conflict_set);
static __inline__
Bool DRD_(thread_address_on_any_stack)(const Addr a)
{
- int i;
+ UInt i;
for (i = 1; i < DRD_N_THREADS; i++)
{
* a shadow stack of StackFrames, which is a double-linked list
* an stack block interval tree
*/
-static struct _StackFrame* shadowStacks[VG_N_THREADS];
+static struct _StackFrame** shadowStacks;
-static WordFM* /* StackTreeNode */ siTrees[VG_N_THREADS];
+static WordFM** /* StackTreeNode */ siTrees;
-static QCache qcaches[VG_N_THREADS];
+static QCache* qcaches;
/* Additionally, there is one global variable interval tree
static void ourGlobals_init ( void )
{
Word i;
+
+ shadowStacks = sg_malloc( "di.sg_main.oGi.2",
+ VG_N_THREADS * sizeof shadowStacks[0] );
+ siTrees = sg_malloc( "di.sg_main.oGi.3", VG_N_THREADS * sizeof siTrees[0] );
+ qcaches = sg_malloc( "di.sg_main.oGi.4", VG_N_THREADS * sizeof qcaches[0] );
+
for (i = 0; i < VG_N_THREADS; i++) {
shadowStacks[i] = NULL;
siTrees[i] = NULL;
+ qcaches[i] = (QCache){};
}
invalidate_all_QCaches();
giTree = VG_(newFM)( sg_malloc, "di.sg_main.oGi.1", sg_free,
Lock at 0x........ was first observed
at 0x........: pthread_mutex_init (hg_intercepts.c:...)
- by 0x........: main (locked_vs_unlocked2.c:58)
- Address 0x........ is 0 bytes inside data symbol "mx2a"
+ by 0x........: main (locked_vs_unlocked2.c:59)
+ Address 0x........ is 0 bytes inside data symbol "mx2b"
Lock at 0x........ was first observed
at 0x........: pthread_mutex_init (hg_intercepts.c:...)
- by 0x........: main (locked_vs_unlocked2.c:59)
- Address 0x........ is 0 bytes inside data symbol "mx2b"
+ by 0x........: main (locked_vs_unlocked2.c:58)
+ Address 0x........ is 0 bytes inside data symbol "mx2a"
Lock at 0x........ was first observed
at 0x........: pthread_mutex_init (hg_intercepts.c:...)
#include "pub_tool_basics.h" // ThreadID
-/* The maximum number of pthreads that we support. This is
- deliberately not very high since our implementation of some of the
- scheduler algorithms is surely O(N) in the number of threads, since
- that's simple, at least. And (in practice) we hope that most
- programs do not need many threads. */
-#define VG_N_THREADS 500
+/* The maximum number of pthreads that we support. */
+extern UInt VG_N_THREADS;
/* Special magic value for an invalid ThreadId. It corresponds to
LinuxThreads using zero as the initial value for
recovered by stack scanning [5]
--resync-filter=no|yes|verbose [yes on MacOS, no on other OSes]
attempt to avoid expensive address-space-resync operations
+ --max-threads=<number> maximum number of threads that valgrind can
+ handle [500]
user options for Nulgrind:
(none)
recovered by stack scanning [5]
--resync-filter=no|yes|verbose [yes on MacOS, no on other OSes]
attempt to avoid expensive address-space-resync operations
+ --max-threads=<number> maximum number of threads that valgrind can
+ handle [500]
user options for Nulgrind:
(none)