Changes in kernel/generic/src/synch/waitq.c [1d432f9:6ec34bb] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/synch/waitq.c
r1d432f9 r6ec34bb 33 33 /** 34 34 * @file 35 * @brief 35 * @brief Wait queue. 36 36 * 37 37 * Wait queue is the basic synchronization primitive upon which all … … 41 41 * fashion. Conditional operation as well as timeouts and interruptions 42 42 * are supported. 43 *44 43 */ 45 44 … … 57 56 #include <arch/cycle.h> 58 57 59 static void waitq_sleep_timed_out(void * );58 static void waitq_sleep_timed_out(void *data); 60 59 61 60 /** Initialize wait queue … … 63 62 * Initialize wait queue. 64 63 * 65 * @param wq Pointer to wait queue to be initialized. 66 * 64 * @param wq Pointer to wait queue to be initialized. 67 65 */ 68 66 void waitq_initialize(waitq_t *wq) 69 67 { 70 irq_spinlock_initialize(&wq->lock, "wq.lock");68 spinlock_initialize(&wq->lock, "waitq_lock"); 71 69 list_initialize(&wq->head); 72 70 wq->missed_wakeups = 0; … … 83 81 * timeout at all. 84 82 * 85 * @param data Pointer to the thread that called waitq_sleep_timeout(). 86 * 83 * @param data Pointer to the thread that called waitq_sleep_timeout(). 87 84 */ 88 85 void waitq_sleep_timed_out(void *data) 89 86 { 90 thread_t *thread = (thread_t *) data; 87 thread_t *t = (thread_t *) data; 88 waitq_t *wq; 91 89 bool do_wakeup = false; 92 90 DEADLOCK_PROBE_INIT(p_wqlock); 93 94 irq_spinlock_lock(&threads_lock, false);95 if (!thread_exists(t hread))91 92 spinlock_lock(&threads_lock); 93 if (!thread_exists(t)) 96 94 goto out; 97 95 98 96 grab_locks: 99 irq_spinlock_lock(&thread->lock, false); 100 101 waitq_t *wq; 102 if ((wq = thread->sleep_queue)) { /* Assignment */ 103 if (!irq_spinlock_trylock(&wq->lock)) { 104 irq_spinlock_unlock(&thread->lock, false); 97 spinlock_lock(&t->lock); 98 if ((wq = t->sleep_queue)) { /* assignment */ 99 if (!spinlock_trylock(&wq->lock)) { 100 spinlock_unlock(&t->lock); 105 101 DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD); 106 /* Avoid deadlock */ 107 goto grab_locks; 108 } 109 110 list_remove(&thread->wq_link); 111 thread->saved_context = thread->sleep_timeout_context; 102 goto grab_locks; /* avoid deadlock */ 103 } 104 105 list_remove(&t->wq_link); 106 t->saved_context = t->sleep_timeout_context; 112 107 do_wakeup = true; 113 t hread->sleep_queue = NULL;114 irq_spinlock_unlock(&wq->lock, false);115 } 116 117 t hread->timeout_pending = false;118 irq_spinlock_unlock(&thread->lock, false);108 t->sleep_queue = NULL; 109 spinlock_unlock(&wq->lock); 110 } 111 112 t->timeout_pending = false; 113 spinlock_unlock(&t->lock); 119 114 120 115 if (do_wakeup) 121 thread_ready(t hread);122 116 thread_ready(t); 117 123 118 out: 124 irq_spinlock_unlock(&threads_lock, false);119 spinlock_unlock(&threads_lock); 125 120 } 126 121 … … 130 125 * If the thread is not found sleeping, no action is taken. 131 126 * 132 * @param t hreadThread to be interrupted.133 * 134 */ 135 void waitq_interrupt_sleep(thread_t *thread) 136 { 127 * @param t Thread to be interrupted. 128 */ 129 void waitq_interrupt_sleep(thread_t *t) 130 { 131 waitq_t *wq; 137 132 bool do_wakeup = false; 133 ipl_t ipl; 138 134 DEADLOCK_PROBE_INIT(p_wqlock); 139 140 irq_spinlock_lock(&threads_lock, true); 141 if (!thread_exists(thread)) 135 136 ipl = interrupts_disable(); 137 spinlock_lock(&threads_lock); 138 if (!thread_exists(t)) 142 139 goto out; 143 140 144 141 grab_locks: 145 irq_spinlock_lock(&thread->lock, false); 146 147 waitq_t *wq; 148 if ((wq = thread->sleep_queue)) { /* Assignment */ 149 if (!(thread->sleep_interruptible)) { 142 spinlock_lock(&t->lock); 143 if ((wq = t->sleep_queue)) { /* assignment */ 144 if (!(t->sleep_interruptible)) { 150 145 /* 151 146 * The sleep cannot be interrupted. 152 *153 147 */ 154 irq_spinlock_unlock(&thread->lock, false);148 spinlock_unlock(&t->lock); 155 149 goto out; 156 150 } 157 158 if (! irq_spinlock_trylock(&wq->lock)) {159 irq_spinlock_unlock(&thread->lock, false);151 152 if (!spinlock_trylock(&wq->lock)) { 153 spinlock_unlock(&t->lock); 160 154 DEADLOCK_PROBE(p_wqlock, DEADLOCK_THRESHOLD); 161 /* Avoid deadlock */ 162 goto grab_locks; 163 } 164 165 if ((thread->timeout_pending) && 166 (timeout_unregister(&thread->sleep_timeout))) 167 thread->timeout_pending = false; 168 169 list_remove(&thread->wq_link); 170 thread->saved_context = thread->sleep_interruption_context; 155 goto grab_locks; /* avoid deadlock */ 156 } 157 158 if (t->timeout_pending && timeout_unregister(&t->sleep_timeout)) 159 t->timeout_pending = false; 160 161 list_remove(&t->wq_link); 162 t->saved_context = t->sleep_interruption_context; 171 163 do_wakeup = true; 172 t hread->sleep_queue = NULL;173 irq_spinlock_unlock(&wq->lock, false);174 } 175 irq_spinlock_unlock(&thread->lock, false);176 164 t->sleep_queue = NULL; 165 spinlock_unlock(&wq->lock); 166 } 167 spinlock_unlock(&t->lock); 168 177 169 if (do_wakeup) 178 thread_ready(t hread);179 170 thread_ready(t); 171 180 172 out: 181 irq_spinlock_unlock(&threads_lock, true); 173 spinlock_unlock(&threads_lock); 174 interrupts_restore(ipl); 182 175 } 183 176 … … 187 180 * is sleeping interruptibly. 188 181 * 189 * @param wq Pointer to wait queue. 190 * 182 * @param wq Pointer to wait queue. 191 183 */ 192 184 void waitq_unsleep(waitq_t *wq) 193 185 { 194 irq_spinlock_lock(&wq->lock, true); 195 186 ipl_t ipl; 187 188 ipl = interrupts_disable(); 189 spinlock_lock(&wq->lock); 190 196 191 if (!list_empty(&wq->head)) { 197 thread_t *t hread = list_get_instance(wq->head.next, thread_t, wq_link);192 thread_t *t; 198 193 199 irq_spinlock_lock(&thread->lock, false); 200 201 ASSERT(thread->sleep_interruptible); 202 203 if ((thread->timeout_pending) && 204 (timeout_unregister(&thread->sleep_timeout))) 205 thread->timeout_pending = false; 206 207 list_remove(&thread->wq_link); 208 thread->saved_context = thread->sleep_interruption_context; 209 thread->sleep_queue = NULL; 210 211 irq_spinlock_unlock(&thread->lock, false); 212 thread_ready(thread); 213 } 214 215 irq_spinlock_unlock(&wq->lock, true); 216 } 217 218 #define PARAM_NON_BLOCKING(flags, usec) \ 219 (((flags) & SYNCH_FLAGS_NON_BLOCKING) && ((usec) == 0)) 194 t = list_get_instance(wq->head.next, thread_t, wq_link); 195 spinlock_lock(&t->lock); 196 ASSERT(t->sleep_interruptible); 197 if (t->timeout_pending && timeout_unregister(&t->sleep_timeout)) 198 t->timeout_pending = false; 199 list_remove(&t->wq_link); 200 t->saved_context = t->sleep_interruption_context; 201 t->sleep_queue = NULL; 202 spinlock_unlock(&t->lock); 203 thread_ready(t); 204 } 205 206 spinlock_unlock(&wq->lock); 207 interrupts_restore(ipl); 208 } 220 209 221 210 /** Sleep until either wakeup, timeout or interruption occurs … … 229 218 * and all the *_timeout() functions use it. 230 219 * 231 * @param wq 232 * @param usec 233 * @param flags 220 * @param wq Pointer to wait queue. 221 * @param usec Timeout in microseconds. 222 * @param flags Specify mode of the sleep. 234 223 * 235 224 * The sleep can be interrupted only if the 236 225 * SYNCH_FLAGS_INTERRUPTIBLE bit is specified in flags. 237 * 226 * 238 227 * If usec is greater than zero, regardless of the value of the 239 228 * SYNCH_FLAGS_NON_BLOCKING bit in flags, the call will not return until either 240 * timeout, interruption or wakeup comes. 229 * timeout, interruption or wakeup comes. 241 230 * 242 231 * If usec is zero and the SYNCH_FLAGS_NON_BLOCKING bit is not set in flags, … … 246 235 * call will immediately return, reporting either success or failure. 247 236 * 248 * @return ESYNCH_WOULD_BLOCK, meaning that the sleep failed because at the 249 * time of the call there was no pending wakeup 250 * @return ESYNCH_TIMEOUT, meaning that the sleep timed out. 251 * @return ESYNCH_INTERRUPTED, meaning that somebody interrupted the sleeping 252 * thread. 253 * @return ESYNCH_OK_ATOMIC, meaning that the sleep succeeded and that there 254 * was a pending wakeup at the time of the call. The caller was not put 255 * asleep at all. 256 * @return ESYNCH_OK_BLOCKED, meaning that the sleep succeeded; the full sleep 257 * was attempted. 258 * 259 */ 260 int waitq_sleep_timeout(waitq_t *wq, uint32_t usec, unsigned int flags) 261 { 262 ASSERT((!PREEMPTION_DISABLED) || (PARAM_NON_BLOCKING(flags, usec))); 263 264 ipl_t ipl = waitq_sleep_prepare(wq); 265 int rc = waitq_sleep_timeout_unsafe(wq, usec, flags); 237 * @return Returns one of ESYNCH_WOULD_BLOCK, ESYNCH_TIMEOUT, 238 * ESYNCH_INTERRUPTED, ESYNCH_OK_ATOMIC and 239 * ESYNCH_OK_BLOCKED. 240 * 241 * @li ESYNCH_WOULD_BLOCK means that the sleep failed because at the time of 242 * the call there was no pending wakeup. 243 * 244 * @li ESYNCH_TIMEOUT means that the sleep timed out. 245 * 246 * @li ESYNCH_INTERRUPTED means that somebody interrupted the sleeping thread. 247 * 248 * @li ESYNCH_OK_ATOMIC means that the sleep succeeded and that there was 249 * a pending wakeup at the time of the call. The caller was not put 250 * asleep at all. 251 * 252 * @li ESYNCH_OK_BLOCKED means that the sleep succeeded; the full sleep was 253 * attempted. 254 */ 255 int waitq_sleep_timeout(waitq_t *wq, uint32_t usec, int flags) 256 { 257 ipl_t ipl; 258 int rc; 259 260 ipl = waitq_sleep_prepare(wq); 261 rc = waitq_sleep_timeout_unsafe(wq, usec, flags); 266 262 waitq_sleep_finish(wq, rc, ipl); 267 263 return rc; … … 273 269 * and interrupts disabled. 274 270 * 275 * @param wq Wait queue. 276 * 277 * @return Interrupt level as it existed on entry to this function. 278 * 271 * @param wq Wait queue. 272 * 273 * @return Interrupt level as it existed on entry to this function. 279 274 */ 280 275 ipl_t waitq_sleep_prepare(waitq_t *wq) … … 284 279 restart: 285 280 ipl = interrupts_disable(); 286 287 if (THREAD) { /* Needed during system initiailzation */281 282 if (THREAD) { /* needed during system initiailzation */ 288 283 /* 289 284 * Busy waiting for a delayed timeout. … … 292 287 * Simply, the thread is not allowed to go to sleep if 293 288 * there are timeouts in progress. 294 *295 289 */ 296 irq_spinlock_lock(&THREAD->lock, false); 297 290 spinlock_lock(&THREAD->lock); 298 291 if (THREAD->timeout_pending) { 299 irq_spinlock_unlock(&THREAD->lock, false);292 spinlock_unlock(&THREAD->lock); 300 293 interrupts_restore(ipl); 301 294 goto restart; 302 295 } 303 304 irq_spinlock_unlock(&THREAD->lock, false); 305 } 306 307 irq_spinlock_lock(&wq->lock, false); 296 spinlock_unlock(&THREAD->lock); 297 } 298 299 spinlock_lock(&wq->lock); 308 300 return ipl; 309 301 } … … 315 307 * lock is released. 316 308 * 317 * @param wq Wait queue. 318 * @param rc Return code of waitq_sleep_timeout_unsafe(). 319 * @param ipl Interrupt level returned by waitq_sleep_prepare(). 320 * 309 * @param wq Wait queue. 310 * @param rc Return code of waitq_sleep_timeout_unsafe(). 311 * @param ipl Interrupt level returned by waitq_sleep_prepare(). 321 312 */ 322 313 void waitq_sleep_finish(waitq_t *wq, int rc, ipl_t ipl) … … 325 316 case ESYNCH_WOULD_BLOCK: 326 317 case ESYNCH_OK_ATOMIC: 327 irq_spinlock_unlock(&wq->lock, false);318 spinlock_unlock(&wq->lock); 328 319 break; 329 320 default: 330 321 break; 331 322 } 332 333 323 interrupts_restore(ipl); 334 324 } … … 340 330 * and followed by a call to waitq_sleep_finish(). 341 331 * 342 * @param wq See waitq_sleep_timeout(). 343 * @param usec See waitq_sleep_timeout(). 344 * @param flags See waitq_sleep_timeout(). 345 * 346 * @return See waitq_sleep_timeout(). 347 * 348 */ 349 int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, unsigned int flags) 350 { 351 /* Checks whether to go to sleep at all */ 332 * @param wq See waitq_sleep_timeout(). 333 * @param usec See waitq_sleep_timeout(). 334 * @param flags See waitq_sleep_timeout(). 335 * 336 * @return See waitq_sleep_timeout(). 337 */ 338 int waitq_sleep_timeout_unsafe(waitq_t *wq, uint32_t usec, int flags) 339 { 340 /* checks whether to go to sleep at all */ 352 341 if (wq->missed_wakeups) { 353 342 wq->missed_wakeups--; 354 343 return ESYNCH_OK_ATOMIC; 355 } else { 356 if (PARAM_NON_BLOCKING(flags, usec)) { 357 /* Return immediatelly instead of going to sleep */ 344 } 345 else { 346 if ((flags & SYNCH_FLAGS_NON_BLOCKING) && (usec == 0)) { 347 /* return immediatelly instead of going to sleep */ 358 348 return ESYNCH_WOULD_BLOCK; 359 349 } … … 362 352 /* 363 353 * Now we are firmly decided to go to sleep. 364 *365 354 */ 366 irq_spinlock_lock(&THREAD->lock, false);367 355 spinlock_lock(&THREAD->lock); 356 368 357 if (flags & SYNCH_FLAGS_INTERRUPTIBLE) { 358 369 359 /* 370 360 * If the thread was already interrupted, 371 361 * don't go to sleep at all. 372 *373 362 */ 374 363 if (THREAD->interrupted) { 375 irq_spinlock_unlock(&THREAD->lock, false);376 irq_spinlock_unlock(&wq->lock, false);364 spinlock_unlock(&THREAD->lock); 365 spinlock_unlock(&wq->lock); 377 366 return ESYNCH_INTERRUPTED; 378 367 } 379 368 380 369 /* 381 370 * Set context that will be restored if the sleep 382 371 * of this thread is ever interrupted. 383 *384 372 */ 385 373 THREAD->sleep_interruptible = true; … … 387 375 /* Short emulation of scheduler() return code. */ 388 376 THREAD->last_cycle = get_cycle(); 389 irq_spinlock_unlock(&THREAD->lock, false);377 spinlock_unlock(&THREAD->lock); 390 378 return ESYNCH_INTERRUPTED; 391 379 } 392 } else 380 381 } else { 393 382 THREAD->sleep_interruptible = false; 394 383 } 384 395 385 if (usec) { 396 386 /* We use the timeout variant. */ … … 398 388 /* Short emulation of scheduler() return code. */ 399 389 THREAD->last_cycle = get_cycle(); 400 irq_spinlock_unlock(&THREAD->lock, false);390 spinlock_unlock(&THREAD->lock); 401 391 return ESYNCH_TIMEOUT; 402 392 } 403 404 393 THREAD->timeout_pending = true; 405 394 timeout_register(&THREAD->sleep_timeout, (uint64_t) usec, 406 395 waitq_sleep_timed_out, THREAD); 407 396 } 408 397 409 398 list_append(&THREAD->wq_link, &wq->head); 410 399 411 400 /* 412 401 * Suspend execution. 413 *414 402 */ 415 403 THREAD->state = Sleeping; 416 404 THREAD->sleep_queue = wq; 417 418 irq_spinlock_unlock(&THREAD->lock, false);419 405 406 spinlock_unlock(&THREAD->lock); 407 420 408 /* wq->lock is released in scheduler_separated_stack() */ 421 scheduler(); 409 scheduler(); 422 410 423 411 return ESYNCH_OK_BLOCKED; 424 412 } 413 425 414 426 415 /** Wake up first thread sleeping in a wait queue … … 432 421 * timeout. 433 422 * 434 * @param wq Pointer to wait queue. 435 * @param mode Wakeup mode. 436 * 423 * @param wq Pointer to wait queue. 424 * @param mode Wakeup mode. 437 425 */ 438 426 void waitq_wakeup(waitq_t *wq, wakeup_mode_t mode) 439 427 { 440 irq_spinlock_lock(&wq->lock, true); 428 ipl_t ipl; 429 430 ipl = interrupts_disable(); 431 spinlock_lock(&wq->lock); 432 441 433 _waitq_wakeup_unsafe(wq, mode); 442 irq_spinlock_unlock(&wq->lock, true); 434 435 spinlock_unlock(&wq->lock); 436 interrupts_restore(ipl); 443 437 } 444 438 … … 448 442 * assumes wq->lock is already locked and interrupts are already disabled. 449 443 * 450 * @param wq Pointer to wait queue. 451 * @param mode If mode is WAKEUP_FIRST, then the longest waiting 452 * thread, if any, is woken up. If mode is WAKEUP_ALL, then 453 * all waiting threads, if any, are woken up. If there are 454 * no waiting threads to be woken up, the missed wakeup is 455 * recorded in the wait queue. 456 * 444 * @param wq Pointer to wait queue. 445 * @param mode If mode is WAKEUP_FIRST, then the longest waiting 446 * thread, if any, is woken up. If mode is WAKEUP_ALL, then 447 * all waiting threads, if any, are woken up. If there are 448 * no waiting threads to be woken up, the missed wakeup is 449 * recorded in the wait queue. 457 450 */ 458 451 void _waitq_wakeup_unsafe(waitq_t *wq, wakeup_mode_t mode) 459 452 { 453 thread_t *t; 460 454 size_t count = 0; 461 455 462 ASSERT(interrupts_disabled()); 463 ASSERT(irq_spinlock_locked(&wq->lock)); 464 465 loop: 456 loop: 466 457 if (list_empty(&wq->head)) { 467 458 wq->missed_wakeups++; 468 if ( (count) && (mode == WAKEUP_ALL))459 if (count && mode == WAKEUP_ALL) 469 460 wq->missed_wakeups--; 470 471 461 return; 472 462 } 473 463 474 464 count++; 475 t hread_t *thread= list_get_instance(wq->head.next, thread_t, wq_link);465 t = list_get_instance(wq->head.next, thread_t, wq_link); 476 466 477 467 /* … … 485 475 * invariant must hold: 486 476 * 487 * t hread->sleep_queue != NULL <=> threadsleeps in a wait queue477 * t->sleep_queue != NULL <=> t sleeps in a wait queue 488 478 * 489 479 * For an observer who locks the thread, the invariant 490 480 * holds only when the lock is held prior to removing 491 481 * it from the wait queue. 492 *493 482 */ 494 irq_spinlock_lock(&thread->lock, false); 495 list_remove(&thread->wq_link); 496 497 if ((thread->timeout_pending) && 498 (timeout_unregister(&thread->sleep_timeout))) 499 thread->timeout_pending = false; 500 501 thread->sleep_queue = NULL; 502 irq_spinlock_unlock(&thread->lock, false); 503 504 thread_ready(thread); 505 483 spinlock_lock(&t->lock); 484 list_remove(&t->wq_link); 485 486 if (t->timeout_pending && timeout_unregister(&t->sleep_timeout)) 487 t->timeout_pending = false; 488 t->sleep_queue = NULL; 489 spinlock_unlock(&t->lock); 490 491 thread_ready(t); 492 506 493 if (mode == WAKEUP_ALL) 507 494 goto loop; 508 495 } 509 496 510 /** Get the missed wakeups count.511 *512 * @param wq Pointer to wait queue.513 * @return The wait queue's missed_wakeups count.514 */515 int waitq_count_get(waitq_t *wq)516 {517 int cnt;518 519 irq_spinlock_lock(&wq->lock, true);520 cnt = wq->missed_wakeups;521 irq_spinlock_unlock(&wq->lock, true);522 523 return cnt;524 }525 526 /** Set the missed wakeups count.527 *528 * @param wq Pointer to wait queue.529 * @param val New value of the missed_wakeups count.530 */531 void waitq_count_set(waitq_t *wq, int val)532 {533 irq_spinlock_lock(&wq->lock, true);534 wq->missed_wakeups = val;535 irq_spinlock_unlock(&wq->lock, true);536 }537 538 497 /** @} 539 498 */
Note:
See TracChangeset
for help on using the changeset viewer.