Mega-merge of my last 2 weeks hacking. This basically does the groundwork
for pthread_* support. Major changes:
* Valgrind now contains a (skeletal!) user-space pthreads
implementation. The exciting bits are in new file vg_scheduler.c.
This contains thread management and scheduling, including nasty crud
to do with making some syscalls (read,write,nanosleep) nonblocking.
Also implementation of pthread_ functions: create join
mutex_{create,destroy,lock,unlock} and cancel.
* As a side effect of the above, major improvements to signal handling
and to the client-request machinery. This is now used to intercept
malloc/free etc too; the hacky way this is done before is gone.
Another side effect is that vg_dispatch.S is greatly simplified.
Also, the horrible hacks to do with delivering signals to threads
blocked in syscalls are gone, since the new mechanisms cover this case
easily.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@52 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/vg_main.c b/vg_main.c
index 2fb92cf..6e5c01a 100644
--- a/vg_main.c
+++ b/vg_main.c
@@ -99,8 +99,6 @@
Int VGOFF_(helper_value_check2_fail) = INVALID_OFFSET;
Int VGOFF_(helper_value_check1_fail) = INVALID_OFFSET;
Int VGOFF_(helper_value_check0_fail) = INVALID_OFFSET;
-Int VGOFF_(helper_do_syscall) = INVALID_OFFSET;
-Int VGOFF_(helper_do_client_request) = INVALID_OFFSET;
Int VGOFF_(helperc_LOADV4) = INVALID_OFFSET;
Int VGOFF_(helperc_LOADV2) = INVALID_OFFSET;
Int VGOFF_(helperc_LOADV1) = INVALID_OFFSET;
@@ -110,7 +108,6 @@
Int VGOFF_(handle_esp_assignment) = INVALID_OFFSET;
Int VGOFF_(fpu_write_check) = INVALID_OFFSET;
Int VGOFF_(fpu_read_check) = INVALID_OFFSET;
-Int VGOFF_(helper_request_normal_exit) = INVALID_OFFSET;
/* This is the actual defn of baseblock. */
@@ -305,14 +302,6 @@
= alloc_BaB_1_set( (Addr) & VG_(helper_DAS) );
VGOFF_(helper_DAA)
= alloc_BaB_1_set( (Addr) & VG_(helper_DAA) );
-
- VGOFF_(helper_request_normal_exit)
- = alloc_BaB_1_set( (Addr) & VG_(helper_request_normal_exit) );
-
- VGOFF_(helper_do_syscall)
- = alloc_BaB_1_set( (Addr) & VG_(helper_do_syscall) );
- VGOFF_(helper_do_client_request)
- = alloc_BaB_1_set( (Addr) & VG_(helper_do_client_request) );
}
@@ -336,17 +325,6 @@
/* Counts downwards in vg_run_innerloop. */
UInt VG_(dispatch_ctr);
-/* If vg_dispatch_ctr is set to 1 to force a stop, its
- previous value is saved here. */
-UInt VG_(dispatch_ctr_SAVED);
-
-/* This is why vg_run_innerloop() exited. */
-UInt VG_(interrupt_reason);
-
-/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
-jmp_buf VG_(toploop_jmpbuf);
-/* ... and if so, here's the signal which caused it to do so. */
-Int VG_(longjmpd_on_signal);
/* 64-bit counter for the number of basic blocks done. */
ULong VG_(bbs_done);
@@ -423,10 +401,12 @@
/* Counts pertaining to internal sanity checking. */
-
UInt VG_(sanity_fast_count) = 0;
UInt VG_(sanity_slow_count) = 0;
+/* Counts pertaining to the scheduler. */
+UInt VG_(num_scheduling_events_MINOR) = 0;
+UInt VG_(num_scheduling_events_MAJOR) = 0;
/* ---------------------------------------------------------------------
@@ -482,176 +462,6 @@
/* ---------------------------------------------------------------------
- Top level simulation loop.
- ------------------------------------------------------------------ */
-
-/* Create a translation of the client basic block beginning at
- orig_addr, and add it to the translation cache & translation table.
- This probably doesn't really belong here, but, hey ... */
-void VG_(create_translation_for) ( Addr orig_addr )
-{
- Addr trans_addr;
- TTEntry tte;
- Int orig_size, trans_size;
- /* Ensure there is space to hold a translation. */
- VG_(maybe_do_lru_pass)();
- VG_(translate)( orig_addr, &orig_size, &trans_addr, &trans_size );
- /* Copy data at trans_addr into the translation cache.
- Returned pointer is to the code, not to the 4-byte
- header. */
- /* Since the .orig_size and .trans_size fields are
- UShort, be paranoid. */
- vg_assert(orig_size > 0 && orig_size < 65536);
- vg_assert(trans_size > 0 && trans_size < 65536);
- tte.orig_size = orig_size;
- tte.orig_addr = orig_addr;
- tte.trans_size = trans_size;
- tte.trans_addr = VG_(copy_to_transcache)
- ( trans_addr, trans_size );
- tte.mru_epoch = VG_(current_epoch);
- /* Free the intermediary -- was allocated by VG_(emit_code). */
- VG_(jitfree)( (void*)trans_addr );
- /* Add to trans tab and set back pointer. */
- VG_(add_to_trans_tab) ( &tte );
- /* Update stats. */
- VG_(this_epoch_in_count) ++;
- VG_(this_epoch_in_osize) += orig_size;
- VG_(this_epoch_in_tsize) += trans_size;
- VG_(overall_in_count) ++;
- VG_(overall_in_osize) += orig_size;
- VG_(overall_in_tsize) += trans_size;
- /* Record translated area for SMC detection. */
- VG_(smc_mark_original) (
- VG_(baseBlock)[VGOFF_(m_eip)], orig_size );
-}
-
-
-/* Runs the client program from %EIP (baseBlock[off_eip]) until it
- asks to exit, or until vg_bbs_to_go jumps have happened (the latter
- case is for debugging). */
-
-void VG_(toploop) ( void )
-{
- volatile UInt dispatch_ctr_SAVED;
- volatile Int done_this_time;
-
- /* For the LRU structures, records when the epoch began. */
- volatile ULong epoch_started_at = 0;
-
- while (True) {
- next_outer_loop:
-
- /* Age the LRU structures if an epoch has been completed. */
- if (VG_(bbs_done) - epoch_started_at >= VG_BBS_PER_EPOCH) {
- VG_(current_epoch)++;
- epoch_started_at = VG_(bbs_done);
- if (VG_(clo_verbosity) > 2) {
- UInt tt_used, tc_used;
- VG_(get_tt_tc_used) ( &tt_used, &tc_used );
- VG_(message)(Vg_UserMsg,
- "%lu bbs, in: %d (%d -> %d), out %d (%d -> %d), TT %d, TC %d",
- VG_(bbs_done),
- VG_(this_epoch_in_count),
- VG_(this_epoch_in_osize),
- VG_(this_epoch_in_tsize),
- VG_(this_epoch_out_count),
- VG_(this_epoch_out_osize),
- VG_(this_epoch_out_tsize),
- tt_used, tc_used
- );
- }
- VG_(this_epoch_in_count) = 0;
- VG_(this_epoch_in_osize) = 0;
- VG_(this_epoch_in_tsize) = 0;
- VG_(this_epoch_out_count) = 0;
- VG_(this_epoch_out_osize) = 0;
- VG_(this_epoch_out_tsize) = 0;
- }
-
- /* Figure out how many bbs to ask vg_run_innerloop to do. */
- if (VG_(bbs_to_go) >= VG_SIGCHECK_INTERVAL)
- VG_(dispatch_ctr) = 1 + VG_SIGCHECK_INTERVAL;
- else
- VG_(dispatch_ctr) = 1 + (UInt)VG_(bbs_to_go);
-
- /* ... and remember what we asked for. */
- dispatch_ctr_SAVED = VG_(dispatch_ctr);
-
- /* Now have a go at doing them. */
- VG_(interrupt_reason) = VG_Y_SIGCHECK;
- if (__builtin_setjmp(VG_(toploop_jmpbuf)) == 0) {
- /* try this ... */
- VG_(run_innerloop)();
- /* We get here if the client didn't take a fault. */
- switch (VG_(interrupt_reason)) {
- case VG_Y_SIGCHECK:
- /* The counter fell to zero and no other situation has
- been detected. */
- vg_assert(VG_(dispatch_ctr) == 0);
- done_this_time = dispatch_ctr_SAVED - 1;
- VG_(bbs_to_go) -= (ULong)done_this_time;
- VG_(bbs_done) += (ULong)done_this_time;
- /* Exit if the debug run has ended. */
- if (VG_(bbs_to_go) == 0) goto debug_stop;
- VG_(deliver_signals)();
- VG_(do_sanity_checks)(False);
- goto next_outer_loop;
- case VG_Y_EXIT:
- /* The target program tried to exit. */
- done_this_time = dispatch_ctr_SAVED - VG_(dispatch_ctr_SAVED);
- done_this_time --;
- VG_(bbs_to_go) -= (ULong)done_this_time;
- VG_(bbs_done) += (ULong)done_this_time;
- return;
- case VG_Y_SMC:
- /* A write to original code was detected. */
- done_this_time = dispatch_ctr_SAVED - VG_(dispatch_ctr_SAVED);
- VG_(bbs_to_go) -= (ULong)done_this_time;
- VG_(bbs_done) += (ULong)done_this_time;
- VG_(flush_transtab)();
- goto next_outer_loop;
- case VG_Y_TRANSLATE: {
- /* Need to provide a translation of code at vg_m_eip. */
- done_this_time = dispatch_ctr_SAVED - VG_(dispatch_ctr);
- vg_assert(done_this_time > 0);
- done_this_time --;
- VG_(bbs_to_go) -= (ULong)done_this_time;
- VG_(bbs_done) += (ULong)done_this_time;
- VG_(create_translation_for)(VG_(baseBlock)[VGOFF_(m_eip)]);
- goto next_outer_loop;
- }
- default:
- VG_(panic)("vg_toploop: invalid interrupt reason");
- }
- } else {
- /* We get here if the client took a fault, which caused our
- signal handler to longjmp. */
- done_this_time = dispatch_ctr_SAVED - VG_(dispatch_ctr);
- VG_(bbs_to_go) -= (ULong)done_this_time;
- VG_(bbs_done) += (ULong)done_this_time;
- if (VG_(interrupt_reason) == VG_Y_EXIT) return;
- VG_(deliver_signals)();
- VG_(do_sanity_checks)(False);
- VG_(unblock_host_signal)(VG_(longjmpd_on_signal));
- }
- }
-
- /* NOTREACHED */
-
- debug_stop:
- /* If we exited because of a debug stop, print the translation
- of the last block executed -- by translating it again, and
- throwing away the result. */
- VG_(printf)(
- "======vvvvvvvv====== LAST TRANSLATION ======vvvvvvvv======\n");
- VG_(translate)( VG_(baseBlock)[VGOFF_(m_eip)], NULL, NULL, NULL );
- VG_(printf)("\n");
- VG_(printf)(
- "======^^^^^^^^====== LAST TRANSLATION ======^^^^^^^^======\n");
-}
-
-
-/* ---------------------------------------------------------------------
Processing of command-line options.
------------------------------------------------------------------ */
@@ -705,7 +515,7 @@
VG_(clo_optimise) = True;
VG_(clo_instrument) = True;
VG_(clo_cleanup) = True;
- VG_(clo_client_perms) = False;
+ VG_(clo_client_perms) = True;
VG_(clo_smc_check) = /* VG_CLO_SMC_SOME */ VG_CLO_SMC_NONE;
VG_(clo_trace_syscalls) = False;
VG_(clo_trace_signals) = False;
@@ -1014,6 +824,7 @@
bad_option("--gdb-attach=yes and --trace-children=yes");
}
+#if 0
if (VG_(clo_client_perms) && !VG_(clo_instrument)) {
VG_(message)(Vg_UserMsg, "");
VG_(message)(Vg_UserMsg,
@@ -1023,6 +834,7 @@
if (VG_(clo_client_perms))
vg_assert(VG_(clo_instrument));
+#endif
VG_(clo_logfile_fd) = eventually_logfile_fd;
@@ -1106,8 +918,9 @@
static void vg_show_counts ( void )
{
VG_(message)(Vg_DebugMsg,
- " dispatch: %lu basic blocks, %d tt_fast misses.",
- VG_(bbs_done), VG_(tt_fast_misses));
+ " lru: %d epochs, %d clearings.",
+ VG_(current_epoch),
+ VG_(number_of_lrus) );
VG_(message)(Vg_DebugMsg,
"translate: new %d (%d -> %d), discard %d (%d -> %d).",
VG_(overall_in_count),
@@ -1117,9 +930,10 @@
VG_(overall_out_osize),
VG_(overall_out_tsize) );
VG_(message)(Vg_DebugMsg,
- " lru: %d epochs, %d clearings.",
- VG_(current_epoch),
- VG_(number_of_lrus) );
+ " dispatch: %lu basic blocks, %d/%d sched events, %d tt_fast misses.",
+ VG_(bbs_done), VG_(num_scheduling_events_MAJOR),
+ VG_(num_scheduling_events_MINOR),
+ VG_(tt_fast_misses));
VG_(message)(Vg_DebugMsg,
"reg-alloc: %d t-req-spill, "
"%d+%d orig+spill uis, %d total-reg-r.",
@@ -1150,7 +964,8 @@
void VG_(main) ( void )
{
- Int i;
+ Int i;
+ VgSchedReturnCode src;
/* Set up our stack sanity-check words. */
for (i = 0; i < 10; i++) {
@@ -1211,11 +1026,18 @@
VG_(message)(Vg_UserMsg, "");
VG_(bbs_to_go) = VG_(clo_stop_after);
- VG_(toploop)();
+
+ VG_(scheduler_init)();
+ src = VG_(scheduler)();
if (VG_(clo_verbosity) > 0)
VG_(message)(Vg_UserMsg, "");
+ if (src == VgSrc_Deadlock) {
+ VG_(message)(Vg_UserMsg,
+ "Warning: pthread scheduler exited due to deadlock");
+ }
+
if (VG_(clo_instrument)) {
VG_(show_all_errors)();
VG_(clientmalloc_done)();
@@ -1226,8 +1048,9 @@
if (VG_(clo_leak_check)) VG_(detect_memory_leaks)();
}
VG_(running_on_simd_CPU) = False;
-
- VG_(do_sanity_checks)(True /*include expensive checks*/ );
+
+ VG_(do_sanity_checks)( 0 /* root thread */,
+ True /*include expensive checks*/ );
if (VG_(clo_verbosity) > 1)
vg_show_counts();
@@ -1262,6 +1085,7 @@
}
/* Prepare to restore state to the real CPU. */
+ VG_(load_thread_state)(0);
VG_(copy_baseBlock_to_m_state_static)();
/* This pushes a return address on the simulator's stack, which
@@ -1349,116 +1173,6 @@
}
-/*-------------------------------------------------------------*/
-/*--- Replace some C lib things with equivs which don't get ---*/
-/*--- spurious value warnings. THEY RUN ON SIMD CPU! ---*/
-/*-------------------------------------------------------------*/
-
-char* strrchr ( const char* s, int c )
-{
- UChar ch = (UChar)((UInt)c);
- UChar* p = (UChar*)s;
- UChar* last = NULL;
- while (True) {
- if (*p == ch) last = p;
- if (*p == 0) return last;
- p++;
- }
-}
-
-char* strchr ( const char* s, int c )
-{
- UChar ch = (UChar)((UInt)c);
- UChar* p = (UChar*)s;
- while (True) {
- if (*p == ch) return p;
- if (*p == 0) return NULL;
- p++;
- }
-}
-
-char* strcat ( char* dest, const char* src )
-{
- Char* dest_orig = dest;
- while (*dest) dest++;
- while (*src) *dest++ = *src++;
- *dest = 0;
- return dest_orig;
-}
-
-unsigned int strlen ( const char* str )
-{
- UInt i = 0;
- while (str[i] != 0) i++;
- return i;
-}
-
-char* strcpy ( char* dest, const char* src )
-{
- Char* dest_orig = dest;
- while (*src) *dest++ = *src++;
- *dest = 0;
- return dest_orig;
-}
-
-int strncmp ( const char* s1, const char* s2, unsigned int nmax )
-{
- unsigned int n = 0;
- while (True) {
- if (n >= nmax) return 0;
- if (*s1 == 0 && *s2 == 0) return 0;
- if (*s1 == 0) return -1;
- if (*s2 == 0) return 1;
-
- if (*(UChar*)s1 < *(UChar*)s2) return -1;
- if (*(UChar*)s1 > *(UChar*)s2) return 1;
-
- s1++; s2++; n++;
- }
-}
-
-int strcmp ( const char* s1, const char* s2 )
-{
- while (True) {
- if (*s1 == 0 && *s2 == 0) return 0;
- if (*s1 == 0) return -1;
- if (*s2 == 0) return 1;
-
- if (*(char*)s1 < *(char*)s2) return -1;
- if (*(char*)s1 > *(char*)s2) return 1;
-
- s1++; s2++;
- }
-}
-
-void* memchr(const void *s, int c, unsigned int n)
-{
- unsigned int i;
- UChar c0 = (UChar)c;
- UChar* p = (UChar*)s;
- for (i = 0; i < n; i++)
- if (p[i] == c0) return (void*)(&p[i]);
- return NULL;
-}
-
-void* memcpy( void *dst, const void *src, unsigned int len )
-{
- register char *d;
- register char *s;
- if ( dst > src ) {
- d = (char *)dst + len - 1;
- s = (char *)src + len - 1;
- while ( len-- )
- *d-- = *s--;
- } else if ( dst < src ) {
- d = (char *)dst;
- s = (char *)src;
- while ( len-- )
- *d++ = *s++;
- }
- return dst;
-}
-
/*--------------------------------------------------------------------*/
/*--- end vg_main.c ---*/
/*--------------------------------------------------------------------*/