* Put all blocked threads on the pending list. This must be called with * the turnstile chain locked. */
| 877 | * the turnstile chain locked. |
| 878 | */ |
| 879 | void |
| 880 | turnstile_broadcast(struct turnstile *ts, int queue) |
| 881 | { |
| 882 | struct turnstile_chain *tc __unused; |
| 883 | struct turnstile *ts1; |
| 884 | struct thread *td; |
| 885 | |
| 886 | MPASS(ts != NULL); |
| 887 | mtx_assert(&ts->ts_lock, MA_OWNED); |
| 888 | MPASS(curthread->td_proc->p_magic == P_MAGIC); |
| 889 | MPASS(ts->ts_owner == curthread || ts->ts_owner == NULL); |
| 890 | /* |
| 891 | * We must have the chain locked so that we can remove the empty |
| 892 | * turnstile from the hash queue. |
| 893 | */ |
| 894 | tc = TC_LOOKUP(ts->ts_lockobj); |
| 895 | mtx_assert(&tc->tc_lock, MA_OWNED); |
| 896 | MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE); |
| 897 | |
| 898 | /* |
| 899 | * Transfer the blocked list to the pending list. |
| 900 | */ |
| 901 | mtx_lock_spin(&td_contested_lock); |
| 902 | TAILQ_CONCAT(&ts->ts_pending, &ts->ts_blocked[queue], td_lockq); |
| 903 | mtx_unlock_spin(&td_contested_lock); |
| 904 | |
| 905 | /* |
| 906 | * Give a turnstile to each thread. The last thread gets |
| 907 | * this turnstile if the turnstile is empty. |
| 908 | */ |
| 909 | TAILQ_FOREACH(td, &ts->ts_pending, td_lockq) { |
| 910 | if (LIST_EMPTY(&ts->ts_free)) { |
| 911 | MPASS(TAILQ_NEXT(td, td_lockq) == NULL); |
| 912 | ts1 = ts; |
| 913 | #ifdef TURNSTILE_PROFILING |
| 914 | tc->tc_depth--; |
| 915 | #endif |
| 916 | } else |
| 917 | ts1 = LIST_FIRST(&ts->ts_free); |
| 918 | MPASS(ts1 != NULL); |
| 919 | LIST_REMOVE(ts1, ts_hash); |
| 920 | td->td_turnstile = ts1; |
| 921 | } |
| 922 | } |
| 923 | |
| 924 | static u_char |
| 925 | turnstile_calc_unlend_prio_locked(struct thread *td) |
no test coverage detected