Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 8a18d5b in mainline


Ignore:
Timestamp:
2018-11-11T15:47:39Z (3 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
269bc459
Parents:
0b5203b
git-author:
Jakub Jermar <jakub@…> (2018-11-10 16:22:29)
git-committer:
Jakub Jermar <jakub@…> (2018-11-11 15:47:39)
Message:

Preallocate the waitq handle

This fixes a race condition (a missing wakeup) when the wakeup was
faster than the thread going to sleep and no handle was allocated yet.
The handle get preallocated to avoid a possible allocation failure in
wakeup.

We also switched to using atomic_compare_exchange_weak_explicit() to fix
ARMv4 and ARMv5 builds.

Location:
uspace/lib/c/generic
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/private/futex.h

    r0b5203b r8a18d5b  
    4646typedef struct futex {
    4747        volatile atomic_int val;
    48         volatile atomic_int alloc_lock;
    49         cap_waitq_handle_t whandle;
     48        volatile atomic_int lock;
     49        volatile cap_waitq_handle_t whandle;
    5050
    5151#ifdef CONFIG_DEBUG_FUTEX
     
    9191#endif
    9292
     93static errno_t allocate_waitq(futex_t *futex)
     94{
     95        int expected = 0;
     96        while (!atomic_compare_exchange_weak_explicit(&futex->lock, &expected,
     97            1, memory_order_acquire, memory_order_relaxed))
     98                expected = 0;
     99
     100        if (futex->whandle == CAP_NIL) {
     101                errno_t rc = __SYSCALL1(SYS_WAITQ_CREATE,
     102                    (sysarg_t) &futex->whandle);
     103                if (rc != EOK) {
     104                        atomic_store_explicit(&futex->lock, 0,
     105                            memory_order_release);
     106                        return rc;
     107                }
     108        }
     109
     110        atomic_store_explicit(&futex->lock, 0, memory_order_release);
     111        return EOK;
     112}
     113
    93114/** Down the futex with timeout, composably.
    94115 *
     
    111132{
    112133        // TODO: Add tests for this.
     134
     135        // Preallocate the waitq handle so that we don't need to risk a failure
     136        // during wakeup
     137        if (futex->whandle == CAP_NIL) {
     138                errno_t rc = allocate_waitq(futex);
     139                if (rc != EOK)
     140                        return rc;
     141        }
    113142
    114143        if (atomic_fetch_sub_explicit(&futex->val, 1, memory_order_acquire) > 0)
     
    134163
    135164                assert(timeout > 0);
    136         }
    137 
    138         if (futex->whandle == CAP_NIL) {
    139                 while (atomic_exchange_explicit(&futex->alloc_lock, 1,
    140                     memory_order_acquire) == 1)
    141                         ;
    142                 if (futex->whandle == CAP_NIL) {
    143                         errno_t rc = __SYSCALL1(SYS_WAITQ_CREATE,
    144                             (sysarg_t) &futex->whandle);
    145                         if (rc != EOK) {
    146                                 atomic_store_explicit(&futex->alloc_lock, 0,
    147                                     memory_order_release);
    148                                 return rc;
    149                         }
    150                 }
    151 
    152                 atomic_store_explicit(&futex->alloc_lock, 0,
    153                     memory_order_release);
    154165        }
    155166
  • uspace/lib/c/generic/thread/futex.c

    r0b5203b r8a18d5b  
    5353{
    5454        atomic_store_explicit(&futex->val, val, memory_order_relaxed);
    55         atomic_store_explicit(&futex->alloc_lock, 0, memory_order_relaxed);
     55        atomic_store_explicit(&futex->lock, 0, memory_order_relaxed);
    5656        futex->whandle = CAP_NIL;
    5757}
Note: See TracChangeset for help on using the changeset viewer.