aboutsummaryrefslogtreecommitdiff
path: root/pthreads/pthread_mutex_timedlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'pthreads/pthread_mutex_timedlock.c')
-rw-r--r--pthreads/pthread_mutex_timedlock.c228
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;
}