Changeset b59318e in mainline
- Timestamp:
- 2018-06-26T17:34:48Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- ab6edb6
- Parents:
- f6372be9
- git-author:
- Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-26 17:01:43)
- git-committer:
- Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-26 17:34:48)
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
abi/include/abi/synch.h
rf6372be9 rb59318e 45 45 /** Interruptible operation. */ 46 46 #define SYNCH_FLAGS_INTERRUPTIBLE (1 << 1) 47 /** Futex operation (makes sleep with timeout composable). */ 48 #define SYNCH_FLAGS_FUTEX (1 << 2) 47 49 48 50 #endif -
kernel/generic/include/proc/thread.h
rf6372be9 rb59318e 112 112 /** If true, the thread can be interrupted from sleep. */ 113 113 bool sleep_interruptible; 114 115 /** 116 * If true, and this thread's sleep returns without a wakeup 117 * (timed out or interrupted), waitq ignores the next wakeup. 118 * This is necessary for futex to be able to handle those conditions. 119 */ 120 bool sleep_composable; 121 114 122 /** Wait queue in which this thread sleeps. */ 115 123 waitq_t *sleep_queue; -
kernel/generic/include/synch/futex.h
rf6372be9 rb59318e 53 53 54 54 extern void futex_init(void); 55 extern sys_errno_t sys_futex_sleep(uintptr_t );55 extern sys_errno_t sys_futex_sleep(uintptr_t, uintptr_t); 56 56 extern sys_errno_t sys_futex_wakeup(uintptr_t); 57 57 -
kernel/generic/include/synch/waitq.h
rf6372be9 rb59318e 62 62 int missed_wakeups; 63 63 64 /** Number of wakeups that need to be ignored due to futex timeout. */ 65 int ignore_wakeups; 66 64 67 /** List of sleeping threads for which there was no missed_wakeup. */ 65 68 list_t sleepers; -
kernel/generic/src/proc/thread.c
rf6372be9 rb59318e 383 383 timeout_initialize(&thread->sleep_timeout); 384 384 thread->sleep_interruptible = false; 385 thread->sleep_composable = false; 385 386 thread->sleep_queue = NULL; 386 387 thread->timeout_pending = false; -
kernel/generic/src/synch/futex.c
rf6372be9 rb59318e 398 398 } 399 399 400 /** Sleep in futex wait queue. 401 * 402 * @param uaddr Userspace address of the futex counter. 400 /** Sleep in futex wait queue with a timeout. 401 * If the sleep times out or is interrupted, the next wakeup is ignored. 402 * The userspace portion of the call must handle this condition. 403 * 404 * @param uaddr Userspace address of the futex counter. 405 * @param timeout Maximum number of useconds to sleep. 0 means no limit. 403 406 * 404 407 * @return If there is no physical mapping for uaddr ENOENT is … … 406 409 * waitq_sleep_timeout(). 407 410 */ 408 sys_errno_t sys_futex_sleep(uintptr_t uaddr )411 sys_errno_t sys_futex_sleep(uintptr_t uaddr, uintptr_t timeout) 409 412 { 410 413 futex_t *futex = get_futex(uaddr); … … 417 420 #endif 418 421 419 errno_t rc = waitq_sleep_timeout( 420 &futex->wq, 0, SYNCH_FLAGS_INTERRUPTIBLE, NULL);422 errno_t rc = waitq_sleep_timeout(&futex->wq, timeout, 423 SYNCH_FLAGS_INTERRUPTIBLE | SYNCH_FLAGS_FUTEX, NULL); 421 424 422 425 #ifdef CONFIG_UDEBUG -
kernel/generic/src/synch/waitq.c
rf6372be9 rb59318e 57 57 #include <adt/list.h> 58 58 #include <arch/cycle.h> 59 #include <mem.h> 59 60 60 61 static void waitq_sleep_timed_out(void *); … … 71 72 void waitq_initialize(waitq_t *wq) 72 73 { 74 memsetb(wq, sizeof(*wq), 0); 73 75 irq_spinlock_initialize(&wq->lock, "wq.lock"); 74 76 list_initialize(&wq->sleepers); 75 wq->missed_wakeups = 0;76 77 } 77 78 … … 114 115 thread->saved_context = thread->sleep_timeout_context; 115 116 do_wakeup = true; 117 if (thread->sleep_composable) 118 wq->ignore_wakeups++; 116 119 thread->sleep_queue = NULL; 117 120 irq_spinlock_unlock(&wq->lock, false); … … 176 179 list_remove(&thread->wq_link); 177 180 thread->saved_context = thread->sleep_interruption_context; 181 if (thread->sleep_composable) 182 wq->ignore_wakeups++; 178 183 do_wakeup = true; 179 184 thread->sleep_queue = NULL; … … 393 398 */ 394 399 irq_spinlock_lock(&THREAD->lock, false); 400 401 THREAD->sleep_composable = (flags & SYNCH_FLAGS_FUTEX); 395 402 396 403 if (flags & SYNCH_FLAGS_INTERRUPTIBLE) { … … 538 545 assert(irq_spinlock_locked(&wq->lock)); 539 546 547 if (wq->ignore_wakeups > 0) { 548 if (mode == WAKEUP_FIRST) { 549 wq->ignore_wakeups--; 550 return; 551 } 552 wq->ignore_wakeups = 0; 553 } 554 540 555 loop: 541 556 if (list_empty(&wq->sleepers)) { -
uspace/lib/c/include/futex.h
rf6372be9 rb59318e 36 36 #define LIBC_FUTEX_H_ 37 37 38 #include <assert.h> 38 39 #include <atomic.h> 39 40 #include <errno.h> … … 98 99 } 99 100 100 /** 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. 101 108 * 102 109 * @param futex Futex. 103 110 * 104 111 * @return ENOENT if there is no such virtual address. 112 * @return ETIMEOUT if timeout expires. 105 113 * @return EOK on success. 106 114 * @return Error code from <errno.h> otherwise. 107 115 * 108 116 */ 109 static inline errno_t futex_down (futex_t *futex)117 static inline errno_t futex_down_composable(futex_t *futex, struct timeval *expires) 110 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 111 137 if ((atomic_signed_t) atomic_predec(&futex->val) < 0) 112 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); 113 139 114 140 return EOK; … … 132 158 } 133 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 134 187 #endif 135 188
Note:
See TracChangeset
for help on using the changeset viewer.