* Places the current thread on the sleep queue for the specified wait * channel. If INVARIANTS is enabled, then it associates the passed in * lock with the sleepq to make sure it is held when that sleep queue is * woken up. */
| 306 | * woken up. |
| 307 | */ |
| 308 | void |
| 309 | sleepq_add(const void *wchan, struct lock_object *lock, const char *wmesg, |
| 310 | int flags, int queue) |
| 311 | { |
| 312 | struct sleepqueue_chain *sc; |
| 313 | struct sleepqueue *sq; |
| 314 | struct thread *td; |
| 315 | |
| 316 | td = curthread; |
| 317 | sc = SC_LOOKUP(wchan); |
| 318 | mtx_assert(&sc->sc_lock, MA_OWNED); |
| 319 | MPASS(td->td_sleepqueue != NULL); |
| 320 | MPASS(wchan != NULL); |
| 321 | MPASS((queue >= 0) && (queue < NR_SLEEPQS)); |
| 322 | |
| 323 | /* If this thread is not allowed to sleep, die a horrible death. */ |
| 324 | if (__predict_false(!THREAD_CAN_SLEEP())) { |
| 325 | #ifdef EPOCH_TRACE |
| 326 | epoch_trace_list(curthread); |
| 327 | #endif |
| 328 | KASSERT(0, |
| 329 | ("%s: td %p to sleep on wchan %p with sleeping prohibited", |
| 330 | __func__, td, wchan)); |
| 331 | } |
| 332 | |
| 333 | /* Look up the sleep queue associated with the wait channel 'wchan'. */ |
| 334 | sq = sleepq_lookup(wchan); |
| 335 | |
| 336 | /* |
| 337 | * If the wait channel does not already have a sleep queue, use |
| 338 | * this thread's sleep queue. Otherwise, insert the current thread |
| 339 | * into the sleep queue already in use by this wait channel. |
| 340 | */ |
| 341 | if (sq == NULL) { |
| 342 | #ifdef INVARIANTS |
| 343 | int i; |
| 344 | |
| 345 | sq = td->td_sleepqueue; |
| 346 | for (i = 0; i < NR_SLEEPQS; i++) { |
| 347 | KASSERT(TAILQ_EMPTY(&sq->sq_blocked[i]), |
| 348 | ("thread's sleep queue %d is not empty", i)); |
| 349 | KASSERT(sq->sq_blockedcnt[i] == 0, |
| 350 | ("thread's sleep queue %d count mismatches", i)); |
| 351 | } |
| 352 | KASSERT(LIST_EMPTY(&sq->sq_free), |
| 353 | ("thread's sleep queue has a non-empty free list")); |
| 354 | KASSERT(sq->sq_wchan == NULL, ("stale sq_wchan pointer")); |
| 355 | sq->sq_lock = lock; |
| 356 | #endif |
| 357 | #ifdef SLEEPQUEUE_PROFILING |
| 358 | sc->sc_depth++; |
| 359 | if (sc->sc_depth > sc->sc_max_depth) { |
| 360 | sc->sc_max_depth = sc->sc_depth; |
| 361 | if (sc->sc_max_depth > sleepq_max_depth) |
| 362 | sleepq_max_depth = sc->sc_max_depth; |
| 363 | } |
| 364 | #endif |
| 365 | sq = td->td_sleepqueue; |
no test coverage detected