Slide 20
Slide 20 text
IV: “You think this is cheesy?”
/*
* The turnstile hash table is partitioned into two halves: the lower half
* is used for upimutextab[] locks, the upper half for everything else.
* The reason for the distinction is that SOBJ_USER_PI locks present a
* unique problem: the upimutextab[] lock passed to turnstile_block()
* cannot be dropped until the calling thread has blocked on its
* SOBJ_USER_PI lock and willed its priority down the blocking chain.
* At that point, the caller's t_lockp will be one of the turnstile locks.
* If mutex_exit() discovers that the upimutextab[] lock has waiters, it
* must wake them, which forces a lock ordering on us: the turnstile lock
* for the upimutextab[] lock will be acquired in mutex_vector_exit(),
* which will eventually call into turnstile_pi_waive(), which will then
* acquire the caller's thread lock, which in this case is the turnstile
* lock for the SOBJ_USER_PI lock. In general, when two turnstile locks
* must be held at the same time, the lock order must be the address order.
* Therefore, to prevent deadlock in turnstile_pi_waive(), we must ensure
* that upimutextab[] locks *always* hash to lower addresses than any
* other locks. You think this is cheesy? Let's see you do better.
*/