Changes in uspace/lib/c/include/futex.h [b59318e:a35b458] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/include/futex.h
rb59318e ra35b458 36 36 #define LIBC_FUTEX_H_ 37 37 38 #include <assert.h>39 38 #include <atomic.h> 40 39 #include <errno.h> 41 40 #include <libc.h> 42 #include <time.h>43 41 44 42 typedef struct futex { 45 43 atomic_t val; 46 #ifdef CONFIG_DEBUG_FUTEX47 _Atomic void *owner;44 #ifdef FUTEX_UPGRADABLE 45 int upgraded; 48 46 #endif 49 47 } futex_t; 50 48 49 51 50 extern void futex_initialize(futex_t *futex, int value); 52 51 53 #ifdef CONFIG_DEBUG_FUTEX 52 #ifdef FUTEX_UPGRADABLE 53 #include <rcu.h> 54 54 55 #define FUTEX_INITIALIZE(val) {{ (val) }, NULL } 56 #define FUTEX_INITIALIZER FUTEX_INITIALIZE(1) 55 #define FUTEX_INITIALIZE(val) {{ (val) }, 0} 57 56 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 }) 64 64 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 }) 68 82 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 90 extern int _upgrade_futexes; 91 92 extern void futex_upgrade_all_and_wait(void); 72 93 73 94 #else 74 95 75 96 #define FUTEX_INITIALIZE(val) {{ (val) }} 76 #define FUTEX_INITIALIZER FUTEX_INITIALIZE(1)77 97 78 98 #define futex_lock(fut) (void) futex_down((fut)) … … 80 100 #define futex_unlock(fut) (void) futex_up((fut)) 81 101 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 85 103 86 # endif104 #define FUTEX_INITIALIZER FUTEX_INITIALIZE(1) 87 105 88 106 /** Try to down the futex. … … 99 117 } 100 118 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. 108 120 * 109 121 * @param futex Futex. 110 122 * 111 123 * @return ENOENT if there is no such virtual address. 112 * @return ETIMEOUT if timeout expires.113 124 * @return EOK on success. 114 125 * @return Error code from <errno.h> otherwise. 115 126 * 116 127 */ 117 static inline errno_t futex_down _composable(futex_t *futex, struct timeval *expires)128 static inline errno_t futex_down(futex_t *futex) 118 129 { 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 137 130 if ((atomic_signed_t) atomic_predec(&futex->val) < 0) 138 return (errno_t) __SYSCALL 2(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count, (sysarg_t) timeout);131 return (errno_t) __SYSCALL1(SYS_FUTEX_SLEEP, (sysarg_t) &futex->val.count); 139 132 140 133 return EOK; … … 158 151 } 159 152 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() on164 * failure is necessary to prevent breakage due to certain race165 * 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 187 153 #endif 188 154
Note:
See TracChangeset
for help on using the changeset viewer.