From: Tom Hughes Date: Sun, 17 Oct 2004 15:00:20 +0000 (+0000) Subject: Implement pthread_mutex_timedlock. This resolves bug 78422. X-Git-Tag: svn/VALGRIND_3_0_0~1514 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b7229cb4fca08ea87860884fbc4dda0c81d9f3b6;p=thirdparty%2Fvalgrind.git Implement pthread_mutex_timedlock. This resolves bug 78422. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2780 --- diff --git a/coregrind/core.h b/coregrind/core.h index 89d93a8925..666eb2299b 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -509,8 +509,9 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); /* 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 diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c index b16038055f..df06d9cd5b 100644 --- a/coregrind/vg_libpthread.c +++ b/coregrind/vg_libpthread.c @@ -1347,6 +1347,41 @@ int __pthread_mutex_lock(pthread_mutex_t *mutex) } +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; + 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; + ms_end + = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970); + 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; @@ -3376,6 +3411,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) diff --git a/coregrind/vg_libpthread_unimp.c b/coregrind/vg_libpthread_unimp.c index a5fb0b3d83..f40c57d9cf 100644 --- a/coregrind/vg_libpthread_unimp.c +++ b/coregrind/vg_libpthread_unimp.c @@ -136,7 +136,7 @@ void pthread_getcpuclockid ( void ) { unimp("pthread_getcpuclockid"); } //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"); } diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index 5ce5bb3aa5..66d638f127 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -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 ); @@ -667,6 +668,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; @@ -766,7 +771,9 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) 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) @@ -1884,6 +1891,29 @@ void do__apply_in_new_thread ( ThreadId parent_tid, */ /* 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 ) @@ -1932,13 +1962,17 @@ void release_one_thread_waiting_on_mutex ( vg_pthread_mutex_t* 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); @@ -1985,7 +2019,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). */ @@ -2014,6 +2048,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", @@ -2910,11 +2947,15 @@ void do_client_request ( ThreadId tid, UInt* arg ) /* 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: @@ -3218,6 +3259,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 @@ -3242,7 +3284,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);