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 | /* |