Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/include/futex.h

    rb59318e ra35b458  
    3636#define LIBC_FUTEX_H_
    3737
    38 #include <assert.h>
    3938#include <atomic.h>
    4039#include <errno.h>
    4140#include <libc.h>
    42 #include <time.h>
    4341
    4442typedef struct futex {
    4543        atomic_t val;
    46 #ifdef CONFIG_DEBUG_FUTEX
    47         _Atomic void *owner;
     44#ifdef FUTEX_UPGRADABLE
     45        int upgraded;
    4846#endif
    4947} futex_t;
    5048
     49
    5150extern void futex_initialize(futex_t *futex, int value);
    5251
    53 #ifdef CONFIG_DEBUG_FUTEX
     52#ifdef FUTEX_UPGRADABLE
     53#include <rcu.h>
    5454
    55 #define FUTEX_INITIALIZE(val) {{ (val) }, NULL }
    56 #define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
     55#define FUTEX_INITIALIZE(val) {{ (val) }, 0}
    5756
    58 void __futex_assert_is_locked(futex_t *, const char *);
    59 void __futex_assert_is_not_locked(futex_t *, const char *);
    60 void __futex_lock(futex_t *, const char *);
    61 void __futex_unlock(futex_t *, const char *);
    62 bool __futex_trylock(futex_t *, const char *);
    63 void __futex_give_to(futex_t *, void *, const char *);
     57#define futex_lock(fut) \
     58({ \
     59        rcu_read_lock(); \
     60        (fut)->upgraded = rcu_access(_upgrade_futexes); \
     61        if ((fut)->upgraded) \
     62                (void) futex_down((fut)); \
     63})
    6464
    65 #define futex_lock(futex) __futex_lock((futex), #futex)
    66 #define futex_unlock(futex) __futex_unlock((futex), #futex)
    67 #define futex_trylock(futex) __futex_trylock((futex), #futex)
     65#define futex_trylock(fut) \
     66({ \
     67        rcu_read_lock(); \
     68        int _upgraded = rcu_access(_upgrade_futexes); \
     69        if (_upgraded) { \
     70                int _acquired = futex_trydown((fut)); \
     71                if (!_acquired) { \
     72                        rcu_read_unlock(); \
     73                } else { \
     74                        (fut)->upgraded = true; \
     75                } \
     76                _acquired; \
     77        } else { \
     78                (fut)->upgraded = false; \
     79                1; \
     80        } \
     81})
    6882
    69 #define futex_give_to(futex, new_owner) __futex_give_to((futex), (new_owner), #futex)
    70 #define futex_assert_is_locked(futex) __futex_assert_is_locked((futex), #futex)
    71 #define futex_assert_is_not_locked(futex) __futex_assert_is_not_locked((futex), #futex)
     83#define futex_unlock(fut) \
     84({ \
     85        if ((fut)->upgraded) \
     86                (void) futex_up((fut)); \
     87        rcu_read_unlock(); \
     88})
     89
     90extern int _upgrade_futexes;
     91
     92extern void futex_upgrade_all_and_wait(void);
    7293
    7394#else
    7495
    7596#define FUTEX_INITIALIZE(val) {{ (val) }}
    76 #define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    7797
    7898#define futex_lock(fut)     (void) futex_down((fut))
     
    80100#define futex_unlock(fut)   (void) futex_up((fut))
    81101
    82 #define futex_give_to(fut, owner) ((void)0)
    83 #define futex_assert_is_locked(fut) assert((atomic_signed_t) (fut)->val.count <= 0)
    84 #define futex_assert_is_not_locked(fut) ((void)0)
     102#endif
    85103
    86 #endif
     104#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    87105
    88106/** Try to down the futex.
     
    99117}
    100118
    101 /** Down the futex with timeout, composably.
    102  *
    103  * This means that when the operation fails due to a timeout or being
    104  * interrupted, the next futex_up() is ignored, which allows certain kinds of
    105  * composition of synchronization primitives.
    106  *
    107  * In most other circumstances, regular futex_down_timeout() is a better choice.
     119/** Down the futex.
    108120 *
    109121 * @param futex Futex.
    110122 *
    111123 * @return ENOENT if there is no such virtual address.
    112  * @return ETIMEOUT if timeout expires.
    113124 * @return EOK on success.
    114125 * @return Error code from <errno.h> otherwise.
    115126 *
    116127 */
    117 static inline errno_t futex_down_composable(futex_t *futex, struct timeval *expires)
     128static inline errno_t futex_down(futex_t *futex)
    118129{
    119         // TODO: Add tests for this.
    120 
    121         /* No timeout by default. */
    122         suseconds_t timeout = 0;
    123 
    124         if (expires) {
    125                 struct timeval tv;
    126                 getuptime(&tv);
    127                 if (tv_gteq(&tv, expires)) {
    128                         /* We can't just return ETIMEOUT. That wouldn't be composable. */
    129                         timeout = 1;
    130                 } else {
    131                         timeout = tv_sub_diff(expires, &tv);
    132                 }
    133 
    134                 assert(timeout > 0);
    135         }
    136 
    137130        if ((atomic_signed_t) atomic_predec(&futex->val) < 0)
    138                 return (errno_t) __SYSCALL2(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count, (sysarg_t) timeout);
     131                return (errno_t) __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count);
    139132
    140133        return EOK;
     
    158151}
    159152
    160 static inline errno_t futex_down_timeout(futex_t *futex, struct timeval *expires)
    161 {
    162         /*
    163          * This combination of a "composable" sleep followed by futex_up() on
    164          * failure is necessary to prevent breakage due to certain race
    165          * conditions.
    166          */
    167         errno_t rc = futex_down_composable(futex, expires);
    168         if (rc != EOK)
    169                 futex_up(futex);
    170         return rc;
    171 }
    172 
    173 /** Down the futex.
    174  *
    175  * @param futex Futex.
    176  *
    177  * @return ENOENT if there is no such virtual address.
    178  * @return EOK on success.
    179  * @return Error code from <errno.h> otherwise.
    180  *
    181  */
    182 static inline errno_t futex_down(futex_t *futex)
    183 {
    184         return futex_down_timeout(futex, NULL);
    185 }
    186 
    187153#endif
    188154
Note: See TracChangeset for help on using the changeset viewer.