Index: coregrind/core.h =================================================================== RCS file: /home/kde/valgrind/coregrind/core.h,v retrieving revision 1.31 diff -u -3 -p -r1.31 core.h --- coregrind/core.h 26 Sep 2004 18:44:06 -0000 1.31 +++ coregrind/core.h 27 Sep 2004 21:33:17 -0000 @@ -509,8 +509,9 @@ extern Bool VG_(is_empty_arena) ( Arena /* Set/get detach state for this thread. */ #define VG_USERREQ__SET_OR_GET_DETACH 0x3009 -#define VG_USERREQ__PTHREAD_GET_THREADID 0x300B -#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x300C +#define VG_USERREQ__PTHREAD_GET_THREADID 0x300A +#define VG_USERREQ__PTHREAD_MUTEX_LOCK 0x300B +#define VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK 0x300C #define VG_USERREQ__PTHREAD_MUTEX_TRYLOCK 0x300D #define VG_USERREQ__PTHREAD_MUTEX_UNLOCK 0x300E #define VG_USERREQ__PTHREAD_COND_WAIT 0x300F Index: coregrind/vg_libpthread.c =================================================================== RCS file: /home/kde/valgrind/coregrind/vg_libpthread.c,v retrieving revision 1.163 diff -u -3 -p -r1.163 vg_libpthread.c --- coregrind/vg_libpthread.c 27 Sep 2004 18:55:55 -0000 1.163 +++ coregrind/vg_libpthread.c 27 Sep 2004 21:33:18 -0000 @@ -1328,6 +1328,52 @@ int __pthread_mutex_lock(pthread_mutex_t } +int __pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abstime ) +{ + int res; + unsigned int ms_now, ms_end; + struct timeval timeval_now; + unsigned long long int ull_ms_now_after_1970; + unsigned long long int ull_ms_end_after_1970; + unsigned long long int ull_ms_now; + unsigned long long int ull_ms_end; + vg_pthread_mutex_t* vg_mutex; + CONVERT(mutex, mutex, vg_mutex); + + VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */, + VG_USERREQ__READ_MILLISECOND_TIMER, + 0, 0, 0, 0); + my_assert(ms_now != 0xFFFFFFFF); + res = gettimeofday(&timeval_now, NULL); + my_assert(res == 0); + + ull_ms_now_after_1970 + = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec)) + + ((unsigned long long int)(timeval_now.tv_usec / 1000)); + ull_ms_end_after_1970 + = 1000ULL * ((unsigned long long int)(abstime->tv_sec)) + + ((unsigned long long int)(abstime->tv_nsec / 1000000)); + if (ull_ms_end_after_1970 < ull_ms_now_after_1970) + ull_ms_end_after_1970 = ull_ms_now_after_1970; + ull_ms_now = ((unsigned long long int)(ms_now)); + ull_ms_end = ull_ms_now + (ull_ms_end_after_1970 - ull_ms_now_after_1970); + if (ull_ms_end >= (unsigned long long int)(0xFFFFFFFFUL)) { + /* use 0xFFFFFFFEUL because 0xFFFFFFFFUL is reserved for no timeout + * (the fine difference between a long wait and a possible abort + * due to a detected deadlock). + */ + ms_end = 0xFFFFFFFEUL; + } else { + ms_end = (unsigned int)(ull_ms_end); + } + VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */, + VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK, + vg_mutex, ms_end, 0, 0); + return res; +} + + int __pthread_mutex_trylock(pthread_mutex_t *mutex) { int res; @@ -3347,6 +3393,7 @@ int __libc_allocate_rtsig (int high) B'stard. ------------------------------------------------------------------ */ strong_alias(__pthread_mutex_lock, pthread_mutex_lock) +strong_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock) strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock) strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock) strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init) Index: coregrind/vg_libpthread_unimp.c =================================================================== RCS file: /home/kde/valgrind/coregrind/vg_libpthread_unimp.c,v retrieving revision 1.46 diff -u -3 -p -r1.46 vg_libpthread_unimp.c --- coregrind/vg_libpthread_unimp.c 15 Aug 2004 14:11:12 -0000 1.46 +++ coregrind/vg_libpthread_unimp.c 27 Sep 2004 21:33:18 -0000 @@ -136,7 +136,7 @@ void pthread_getcpuclockid ( void ) { u //void pthread_mutex_destroy ( void ) { unimp("pthread_mutex_destroy"); } //void pthread_mutex_init ( void ) { unimp("pthread_mutex_init"); } //void pthread_mutex_lock ( void ) { unimp("pthread_mutex_lock"); } -void pthread_mutex_timedlock ( void ) { unimp("pthread_mutex_timedlock"); } +//void pthread_mutex_timedlock ( void ) { unimp("pthread_mutex_timedlock"); } //void pthread_mutex_trylock ( void ) { unimp("pthread_mutex_trylock"); } //void pthread_mutex_unlock ( void ) { unimp("pthread_mutex_unlock"); } //void pthread_mutexattr_destroy ( void ) { unimp("pthread_mutexattr_destroy"); } Index: coregrind/vg_scheduler.c =================================================================== RCS file: /home/kde/valgrind/coregrind/vg_scheduler.c,v retrieving revision 1.185 diff -u -3 -p -r1.185 vg_scheduler.c --- coregrind/vg_scheduler.c 13 Sep 2004 13:16:40 -0000 1.185 +++ coregrind/vg_scheduler.c 27 Sep 2004 21:33:19 -0000 @@ -96,6 +96,7 @@ static Addr __libc_freeres_wrapper; /* Forwards */ static void do_client_request ( ThreadId tid, UInt* args ); static void scheduler_sanity ( void ); +static void do_pthread_mutex_timedlock_TIMEOUT ( ThreadId tid ); static void do_pthread_cond_timedwait_TIMEOUT ( ThreadId tid ); static void maybe_rendezvous_joiners_and_joinees ( void ); @@ -599,16 +600,18 @@ void idle ( void ) } if (tp != NULL) { - delta = tp->time - now; - vg_assert(delta >= 0); + vg_assert(tp->time >= now); + /* limit the signed int delta to INT_MAX */ + if ((tp->time - now) <= 0x7FFFFFFFU) { + delta = tp->time - now; + } else { + delta = 0x7FFFFFFF; + } } if (wicked) delta = 0; } - /* gotta wake up for something! */ - vg_assert(fd != -1 || delta != -1); - /* If we need to do signal routing, then poll for pending signals every VG_(clo_signal_polltime) mS */ if (VG_(do_signal_routing) && (delta > VG_(clo_signal_polltime) || delta == -1)) @@ -621,6 +624,9 @@ void idle ( void ) print_sched_event(0, msg_buf); } + /* gotta wake up for something! */ + vg_assert(fd != -1 || delta != -1); + VG_(poll)(pollfd, fd != -1 ? 1 : 0, delta); /* See if there's anything on the timeout list which needs @@ -653,6 +659,10 @@ void idle ( void ) tst->status = VgTs_Runnable; break; + case VgTs_WaitMX: + do_pthread_mutex_timedlock_TIMEOUT(tst->tid); + break; + case VgTs_WaitCV: do_pthread_cond_timedwait_TIMEOUT(tst->tid); break; @@ -752,7 +762,9 @@ VgSchedReturnCode do_scheduler ( Int* ex if (tid_next >= VG_N_THREADS) tid_next = 1; if (VG_(threads)[tid_next].status == VgTs_Sleeping || VG_(threads)[tid_next].status == VgTs_WaitSys - || (VG_(threads)[tid_next].status == VgTs_WaitCV + || (VG_(threads)[tid_next].status == VgTs_WaitMX + && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF) + || (VG_(threads)[tid_next].status == VgTs_WaitCV && VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF)) n_in_bounded_wait ++; if (VG_(threads)[tid_next].status != VgTs_Empty) @@ -1861,6 +1873,29 @@ void do__apply_in_new_thread ( ThreadId */ /* Helper fns ... */ +static +void do_pthread_mutex_timedlock_TIMEOUT ( ThreadId tid ) +{ + Char msg_buf[100]; + vg_pthread_mutex_t* mx; + + vg_assert(VG_(is_valid_tid)(tid) + && VG_(threads)[tid].status == VgTs_WaitMX + && VG_(threads)[tid].awaken_at != 0xFFFFFFFF); + mx = VG_(threads)[tid].associated_mx; + vg_assert(mx != NULL); + + VG_(threads)[tid].status = VgTs_Runnable; + SET_PTHREQ_RETVAL(tid, ETIMEDOUT); /* pthread_mutex_lock return value */ + VG_(threads)[tid].associated_mx = NULL; + + if (VG_(clo_trace_pthread_level) >= 1) { + VG_(sprintf)(msg_buf, "pthread_mutex_timedlock mx %p: TIMEOUT", mx); + print_pthread_event(tid, msg_buf); + } +} + + static void release_one_thread_waiting_on_mutex ( vg_pthread_mutex_t* mutex, Char* caller ) @@ -1909,13 +1944,17 @@ void release_one_thread_waiting_on_mutex static void do_pthread_mutex_lock( ThreadId tid, Bool is_trylock, - vg_pthread_mutex_t* mutex ) + vg_pthread_mutex_t* mutex, + UInt ms_end ) { Char msg_buf[100]; Char* caller = is_trylock ? "pthread_mutex_trylock" : "pthread_mutex_lock "; + /* If ms_end == 0xFFFFFFFF, wait forever (no timeout). Otherwise, + ms_end is the ending millisecond. */ + if (VG_(clo_trace_pthread_level) >= 2) { VG_(sprintf)(msg_buf, "%s mx %p ...", caller, mutex ); print_pthread_event(tid, msg_buf); @@ -1962,7 +2001,7 @@ void do_pthread_mutex_lock( ThreadId tid } /* Someone has it already. */ - if ((ThreadId)mutex->__vg_m_owner == tid) { + if ((ThreadId)mutex->__vg_m_owner == tid && ms_end == 0xFFFFFFFF) { /* It's locked -- by me! */ if (mutex->__vg_m_kind == PTHREAD_MUTEX_RECURSIVE_NP) { /* return 0 (success). */ @@ -1991,6 +2030,9 @@ void do_pthread_mutex_lock( ThreadId tid VG_(threads)[tid].status = VgTs_WaitMX; VG_(threads)[tid].associated_mx = mutex; + VG_(threads)[tid].awaken_at = ms_end; + if (ms_end != 0xFFFFFFFF) + add_timeout(tid, ms_end); SET_PTHREQ_RETVAL(tid, 0); /* pth_mx_lock success value */ if (VG_(clo_trace_pthread_level) >= 1) { VG_(sprintf)(msg_buf, "%s mx %p: BLOCK", @@ -2887,11 +2929,15 @@ void do_client_request ( ThreadId tid, U /* Some of these may make thread tid non-runnable, but the scheduler checks for that on return from this function. */ case VG_USERREQ__PTHREAD_MUTEX_LOCK: - do_pthread_mutex_lock( tid, False, (void *)(arg[1]) ); + do_pthread_mutex_lock( tid, False, (void *)(arg[1]), 0xFFFFFFFF ); + break; + + case VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK: + do_pthread_mutex_lock( tid, False, (void *)(arg[1]), arg[2] ); break; case VG_USERREQ__PTHREAD_MUTEX_TRYLOCK: - do_pthread_mutex_lock( tid, True, (void *)(arg[1]) ); + do_pthread_mutex_lock( tid, True, (void *)(arg[1]), 0xFFFFFFFF ); break; case VG_USERREQ__PTHREAD_MUTEX_UNLOCK: @@ -3195,6 +3241,7 @@ void scheduler_sanity ( void ) */ vg_assert(VG_(threads)[top->tid].awaken_at != top->time || VG_(threads)[top->tid].status == VgTs_Sleeping || + VG_(threads)[top->tid].status == VgTs_WaitMX || VG_(threads)[top->tid].status == VgTs_WaitCV); #endif @@ -3219,7 +3266,8 @@ void scheduler_sanity ( void ) /* 1 */ vg_assert(mx != NULL); /* 2 */ vg_assert(mx->__vg_m_count > 0); /* 3 */ vg_assert(VG_(is_valid_tid)((ThreadId)mx->__vg_m_owner)); - /* 4 */ vg_assert((UInt)i != (ThreadId)mx->__vg_m_owner); + /* 4 */ vg_assert((UInt)i != (ThreadId)mx->__vg_m_owner || + VG_(threads)[i].awaken_at != 0xFFFFFFFF); } else if (VG_(threads)[i].status == VgTs_WaitCV) { vg_assert(cv != NULL);