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