diff options
Diffstat (limited to 'pthreads/pthread_mutex_timedlock.c')
-rw-r--r-- | pthreads/pthread_mutex_timedlock.c | 228 |
1 files changed, 178 insertions, 50 deletions
diff --git a/pthreads/pthread_mutex_timedlock.c b/pthreads/pthread_mutex_timedlock.c index a2385522d..174531679 100644 --- a/pthreads/pthread_mutex_timedlock.c +++ b/pthreads/pthread_mutex_timedlock.c @@ -109,8 +109,9 @@ int pthread_mutex_timedlock (pthread_mutex_t * mutex, const struct timespec *abstime) { - int result; pthread_mutex_t mx; + int kind; + int result = 0; /* * Let the system deal with invalid pointers. @@ -131,66 +132,193 @@ pthread_mutex_timedlock (pthread_mutex_t * mutex, } mx = *mutex; + kind = mx->kind; - if (mx->kind == PTHREAD_MUTEX_NORMAL) + if (kind >= 0) { - if ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) 1) != 0) - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) - { - if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) - { - return result; - } - } - } - } - else - { - pthread_t self = pthread_self(); - - if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE( - (PTW32_INTERLOCKED_LPLONG) &mx->lock_idx, - (PTW32_INTERLOCKED_LONG) 1, - (PTW32_INTERLOCKED_LONG) 0) == 0) - { - mx->recursive_count = 1; - mx->ownerThread = self; - } - else - { - if (pthread_equal (mx->ownerThread, self)) + if (mx->kind == PTHREAD_MUTEX_NORMAL) + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1) != 0) { - if (mx->kind == PTHREAD_MUTEX_RECURSIVE) - { - mx->recursive_count++; - } - else - { - return EDEADLK; - } - } - else - { - while ((LONG) PTW32_INTERLOCKED_EXCHANGE( - (LPLONG) &mx->lock_idx, - (LONG) -1) != 0) + while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) { - if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) { return result; } - } + } + } + } + else + { + pthread_t self = pthread_self(); + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { mx->recursive_count = 1; mx->ownerThread = self; } - } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (mx->kind == PTHREAD_MUTEX_RECURSIVE) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + mx->recursive_count = 1; + mx->ownerThread = self; + } + } + } } + else + { + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; - return 0; + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + result = ENOTRECOVERABLE; + } + else + { + pthread_t self = pthread_self(); + + kind = -kind - 1; /* Convert to non-robust range */ + + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1) != 0) + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex)) + && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + + if (0 == result || EOWNERDEAD == result) + { + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + } + } + else + { + pthread_t self = pthread_self(); + + if (0 == (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + mx->recursive_count = 1; + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (PTHREAD_MUTEX_RECURSIVE == kind) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex)) + && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + } + else if (0 == result || EOWNERDEAD == result) + { + mx->recursive_count = 1; + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + } + } + } + } + } + + return result; } |