Rev 1103 | Rev 1158 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 1103 | Rev 1156 | ||
|---|---|---|---|
| Line 37... | Line 37... | ||
| 37 | #include <time/timeout.h> |
37 | #include <time/timeout.h> |
| 38 | #include <arch.h> |
38 | #include <arch.h> |
| 39 | #include <context.h> |
39 | #include <context.h> |
| 40 | #include <adt/list.h> |
40 | #include <adt/list.h> |
| 41 | 41 | ||
| - | 42 | static void waitq_timeouted_sleep(void *data); |
|
| - | 43 | ||
| 42 | /** Initialize wait queue |
44 | /** Initialize wait queue |
| 43 | * |
45 | * |
| 44 | * Initialize wait queue. |
46 | * Initialize wait queue. |
| 45 | * |
47 | * |
| 46 | * @param wq Pointer to wait queue to be initialized. |
48 | * @param wq Pointer to wait queue to be initialized. |
| Line 62... | Line 64... | ||
| 62 | * overlap. In that case it behaves just as though there was no |
64 | * overlap. In that case it behaves just as though there was no |
| 63 | * timeout at all. |
65 | * timeout at all. |
| 64 | * |
66 | * |
| 65 | * @param data Pointer to the thread that called waitq_sleep_timeout(). |
67 | * @param data Pointer to the thread that called waitq_sleep_timeout(). |
| 66 | */ |
68 | */ |
| 67 | void waitq_interrupted_sleep(void *data) |
69 | void waitq_timeouted_sleep(void *data) |
| 68 | { |
70 | { |
| 69 | thread_t *t = (thread_t *) data; |
71 | thread_t *t = (thread_t *) data; |
| 70 | waitq_t *wq; |
72 | waitq_t *wq; |
| 71 | bool do_wakeup = false; |
73 | bool do_wakeup = false; |
| 72 | 74 | ||
| Line 98... | Line 100... | ||
| 98 | 100 | ||
| 99 | out: |
101 | out: |
| 100 | spinlock_unlock(&threads_lock); |
102 | spinlock_unlock(&threads_lock); |
| 101 | } |
103 | } |
| 102 | 104 | ||
| - | 105 | /** Interrupt sleeping thread. |
|
| - | 106 | * |
|
| - | 107 | * This routine attempts to interrupt a thread from its sleep in a waitqueue. |
|
| - | 108 | * If the thread is not found sleeping, no action is taken. |
|
| - | 109 | * |
|
| - | 110 | * @param t Thread to be interrupted. |
|
| - | 111 | */ |
|
| - | 112 | void waitq_interrupt_sleep(thread_t *t) |
|
| - | 113 | { |
|
| - | 114 | waitq_t *wq; |
|
| - | 115 | bool do_wakeup = false; |
|
| - | 116 | ipl_t ipl; |
|
| - | 117 | ||
| - | 118 | ipl = interrupts_disable(); |
|
| - | 119 | spinlock_lock(&threads_lock); |
|
| - | 120 | if (!list_member(&t->threads_link, &threads_head)) |
|
| - | 121 | goto out; |
|
| - | 122 | ||
| - | 123 | grab_locks: |
|
| - | 124 | spinlock_lock(&t->lock); |
|
| - | 125 | if ((wq = t->sleep_queue)) { /* assignment */ |
|
| - | 126 | if (!spinlock_trylock(&wq->lock)) { |
|
| - | 127 | spinlock_unlock(&t->lock); |
|
| - | 128 | goto grab_locks; /* avoid deadlock */ |
|
| - | 129 | } |
|
| - | 130 | ||
| - | 131 | list_remove(&t->wq_link); |
|
| - | 132 | t->saved_context = t->sleep_interruption_context; |
|
| - | 133 | do_wakeup = true; |
|
| - | 134 | ||
| - | 135 | spinlock_unlock(&wq->lock); |
|
| - | 136 | t->sleep_queue = NULL; |
|
| - | 137 | } |
|
| - | 138 | spinlock_unlock(&t->lock); |
|
| - | 139 | ||
| - | 140 | if (do_wakeup) |
|
| - | 141 | thread_ready(t); |
|
| - | 142 | ||
| - | 143 | out: |
|
| - | 144 | spinlock_unlock(&threads_lock); |
|
| - | 145 | interrupts_restore(ipl); |
|
| - | 146 | } |
|
| - | 147 | ||
| - | 148 | ||
| 103 | /** Sleep until either wakeup or timeout occurs |
149 | /** Sleep until either wakeup, timeout or interruption occurs |
| 104 | * |
150 | * |
| 105 | * This is a sleep implementation which allows itself to be |
151 | * This is a sleep implementation which allows itself to be |
| 106 | * interrupted from the sleep, restoring a failover context. |
152 | * interrupted from the sleep, restoring a failover context. |
| 107 | * |
153 | * |
| 108 | * Sleepers are organised in FIFO fashion in a structure called wait queue. |
154 | * Sleepers are organised in FIFO fashion in a structure called wait queue. |
| Line 129... | Line 175... | ||
| 129 | * ESYNCH_WOULD_BLOCK means that the sleep failed because at the time |
175 | * ESYNCH_WOULD_BLOCK means that the sleep failed because at the time |
| 130 | * of the call there was no pending wakeup. |
176 | * of the call there was no pending wakeup. |
| 131 | * |
177 | * |
| 132 | * ESYNCH_TIMEOUT means that the sleep timed out. |
178 | * ESYNCH_TIMEOUT means that the sleep timed out. |
| 133 | * |
179 | * |
| - | 180 | * ESYNCH_INTERRUPTED means that somebody interrupted the sleeping thread. |
|
| - | 181 | * |
|
| 134 | * ESYNCH_OK_ATOMIC means that the sleep succeeded and that there was |
182 | * ESYNCH_OK_ATOMIC means that the sleep succeeded and that there was |
| 135 | * a pending wakeup at the time of the call. The caller was not put |
183 | * a pending wakeup at the time of the call. The caller was not put |
| 136 | * asleep at all. |
184 | * asleep at all. |
| 137 | * |
185 | * |
| 138 | * ESYNCH_OK_BLOCKED means that the sleep succeeded; the full sleep was |
186 | * ESYNCH_OK_BLOCKED means that the sleep succeeded; the full sleep was |
| Line 176... | Line 224... | ||
| 176 | spinlock_unlock(&wq->lock); |
224 | spinlock_unlock(&wq->lock); |
| 177 | interrupts_restore(ipl); |
225 | interrupts_restore(ipl); |
| 178 | return ESYNCH_WOULD_BLOCK; |
226 | return ESYNCH_WOULD_BLOCK; |
| 179 | } |
227 | } |
| 180 | } |
228 | } |
| 181 | - | ||
| 182 | 229 | ||
| 183 | /* |
230 | /* |
| 184 | * Now we are firmly decided to go to sleep. |
231 | * Now we are firmly decided to go to sleep. |
| 185 | */ |
232 | */ |
| 186 | spinlock_lock(&THREAD->lock); |
233 | spinlock_lock(&THREAD->lock); |
| - | 234 | ||
| - | 235 | /* |
|
| - | 236 | * Set context that will be restored if the sleep |
|
| - | 237 | * of this thread is ever interrupted. |
|
| - | 238 | */ |
|
| - | 239 | if (!context_save(&THREAD->sleep_interruption_context)) { |
|
| - | 240 | /* Short emulation of scheduler() return code. */ |
|
| - | 241 | spinlock_unlock(&THREAD->lock); |
|
| - | 242 | interrupts_restore(ipl); |
|
| - | 243 | return ESYNCH_INTERRUPTED; |
|
| - | 244 | } |
|
| - | 245 | ||
| 187 | if (usec) { |
246 | if (usec) { |
| 188 | /* We use the timeout variant. */ |
247 | /* We use the timeout variant. */ |
| 189 | if (!context_save(&THREAD->sleep_timeout_context)) { |
248 | if (!context_save(&THREAD->sleep_timeout_context)) { |
| 190 | /* |
- | |
| 191 | * Short emulation of scheduler() return code. |
249 | /* Short emulation of scheduler() return code. */ |
| 192 | */ |
- | |
| 193 | spinlock_unlock(&THREAD->lock); |
250 | spinlock_unlock(&THREAD->lock); |
| 194 | interrupts_restore(ipl); |
251 | interrupts_restore(ipl); |
| 195 | return ESYNCH_TIMEOUT; |
252 | return ESYNCH_TIMEOUT; |
| 196 | } |
253 | } |
| 197 | THREAD->timeout_pending = true; |
254 | THREAD->timeout_pending = true; |
| 198 | timeout_register(&THREAD->sleep_timeout, (__u64) usec, waitq_interrupted_sleep, THREAD); |
255 | timeout_register(&THREAD->sleep_timeout, (__u64) usec, waitq_timeouted_sleep, THREAD); |
| 199 | } |
256 | } |
| 200 | 257 | ||
| 201 | list_append(&THREAD->wq_link, &wq->head); |
258 | list_append(&THREAD->wq_link, &wq->head); |
| 202 | 259 | ||
| 203 | /* |
260 | /* |