59 #include <sys/cdefs.h>
63 #include "opt_kdtrace.h"
64 #include "opt_turnstile_profiling.h"
65 #include "opt_sched.h"
67 #include <sys/param.h>
68 #include <sys/systm.h>
70 #include <sys/kernel.h>
73 #include <sys/mutex.h>
75 #include <sys/queue.h>
76 #include <sys/sched.h>
78 #include <sys/sysctl.h>
79 #include <sys/turnstile.h>
85 #include <sys/lockmgr.h>
95 #define TC_TABLESIZE 128
96 #define TC_MASK (TC_TABLESIZE - 1)
98 #define TC_HASH(lock) (((uintptr_t)(lock) >> TC_SHIFT) & TC_MASK)
99 #define TC_LOOKUP(lock) &turnstile_chains[TC_HASH(lock)]
128 struct lock_object *ts_lockobj;
129 struct thread *ts_owner;
135 #ifdef TURNSTILE_PROFILING
141 #ifdef TURNSTILE_PROFILING
142 u_int turnstile_max_depth;
144 "turnstile profiling");
145 static SYSCTL_NODE(_debug_turnstile, OID_AUTO, chains, CTLFLAG_RD, 0,
146 "turnstile chain stats");
147 SYSCTL_UINT(_debug_turnstile, OID_AUTO, max_depth, CTLFLAG_RD,
148 &turnstile_max_depth, 0,
"maximum depth achieved of a single chain");
158 #ifdef TURNSTILE_PROFILING
159 static void init_turnstile_profiling(
void *arg);
167 static void turnstile_dtor(
void *mem,
int size,
void *arg);
188 THREAD_LOCK_ASSERT(td, MA_OWNED);
189 pri = td->td_priority;
191 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
211 thread_lock_flags(td, MTX_DUPOK);
213 MPASS(td->td_proc != NULL);
214 MPASS(td->td_proc->p_magic == P_MAGIC);
223 if (TD_IS_SLEEPING(td)) {
225 "Sleeping thread (tid %d, pid %d) owns a non-sleepable lock\n",
226 td->td_tid, td->td_proc->p_pid);
228 panic(
"sleeping thread");
235 if (td->td_priority <= pri) {
249 if (TD_IS_RUNNING(td) || TD_ON_RUNQ(td)) {
250 MPASS(td->td_blocked == NULL);
260 KASSERT(td != curthread, (
"Deadlock detected"));
266 KASSERT(TD_ON_LOCK(td), (
267 "thread %d(%s):%d holds %s but isn't blocked on a lock\n",
268 td->td_tid, td->td_name, td->td_state,
269 ts->ts_lockobj->lo_name));
276 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
293 struct thread *td1, *td2;
296 THREAD_LOCK_ASSERT(td, MA_OWNED);
297 MPASS(TD_ON_LOCK(td));
309 if (td->td_turnstile != NULL)
317 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
318 td1 = TAILQ_PREV(td, threadqueue, td_lockq);
319 td2 = TAILQ_NEXT(td, td_lockq);
320 if ((td1 != NULL && td->td_priority < td1->td_priority) ||
321 (td2 != NULL && td->td_priority > td2->td_priority)) {
327 queue = td->td_tsqueue;
328 MPASS(queue == TS_EXCLUSIVE_QUEUE || queue == TS_SHARED_QUEUE);
330 TAILQ_REMOVE(&ts->
ts_blocked[queue], td, td_lockq);
331 TAILQ_FOREACH(td1, &ts->
ts_blocked[queue], td_lockq) {
332 MPASS(td1->td_proc->p_magic == P_MAGIC);
333 if (td1->td_priority > td->td_priority)
338 TAILQ_INSERT_TAIL(&ts->
ts_blocked[queue], td, td_lockq);
340 TAILQ_INSERT_BEFORE(td1, td, td_lockq);
344 "turnstile_adjust_thread: td %d put at tail on [%p] %s",
345 td->td_tid, ts->ts_lockobj, ts->ts_lockobj->lo_name);
348 "turnstile_adjust_thread: td %d moved before %d on [%p] %s",
349 td->td_tid, td1->td_tid, ts->ts_lockobj,
350 ts->ts_lockobj->lo_name);
371 LIST_INIT(&thread0.td_contested);
372 thread0.td_turnstile = NULL;
375 #ifdef TURNSTILE_PROFILING
377 init_turnstile_profiling(
void *arg)
379 struct sysctl_oid *chain_oid;
384 snprintf(chain_name,
sizeof(chain_name),
"%d", i);
385 chain_oid = SYSCTL_ADD_NODE(NULL,
386 SYSCTL_STATIC_CHILDREN(_debug_turnstile_chains), OID_AUTO,
387 chain_name, CTLFLAG_RD, NULL,
"turnstile chain stats");
388 SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
391 SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
396 SYSINIT(turnstile_profiling, SI_SUB_LOCK, SI_ORDER_ANY,
397 init_turnstile_profiling, NULL);
404 turnstile_zone = uma_zcreate(
"TURNSTILE",
sizeof(
struct turnstile),
425 MPASS(TD_ON_LOCK(td));
432 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
433 mtx_assert(&ts->
ts_lock, MA_OWNED);
444 MPASS(td->td_tsqueue == TS_EXCLUSIVE_QUEUE ||
445 td->td_tsqueue == TS_SHARED_QUEUE);
446 if (td == TAILQ_FIRST(&ts->
ts_blocked[td->td_tsqueue]) &&
447 td->td_priority < oldpri) {
460 MPASS(ts->ts_owner == NULL);
466 MPASS(owner->td_proc->p_magic == P_MAGIC);
467 ts->ts_owner = owner;
468 LIST_INSERT_HEAD(&owner->td_contested, ts, ts_link);
476 turnstile_dtor(
void *mem,
int size,
void *arg)
481 MPASS(TAILQ_EMPTY(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]));
482 MPASS(TAILQ_EMPTY(&ts->
ts_blocked[TS_SHARED_QUEUE]));
497 TAILQ_INIT(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]);
500 LIST_INIT(&ts->ts_free);
501 mtx_init(&ts->
ts_lock,
"turnstile lock", NULL, MTX_SPIN | MTX_RECURSE);
521 return (uma_zalloc(turnstile_zone, M_WAITOK));
531 uma_zfree(turnstile_zone, ts);
543 mtx_lock_spin(&tc->tc_lock);
553 mtx_lock_spin(&tc->tc_lock);
554 LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
555 if (ts->ts_lockobj == lock) {
560 ts = curthread->td_turnstile;
563 KASSERT(ts->ts_lockobj == NULL, (
"stale ts_lockobj pointer"));
564 ts->ts_lockobj = lock;
573 struct lock_object *lock;
575 mtx_assert(&ts->
ts_lock, MA_OWNED);
578 lock = ts->ts_lockobj;
579 if (ts == curthread->td_turnstile)
580 ts->ts_lockobj = NULL;
582 mtx_unlock_spin(&tc->tc_lock);
597 mtx_assert(&tc->tc_lock, MA_OWNED);
598 LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
599 if (ts->ts_lockobj == lock) {
615 mtx_unlock_spin(&tc->tc_lock);
622 static struct thread *
625 struct thread *std, *xtd;
627 std = TAILQ_FIRST(&ts->
ts_blocked[TS_SHARED_QUEUE]);
628 xtd = TAILQ_FIRST(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]);
629 if (xtd == NULL || (std != NULL && std->td_priority < xtd->td_priority))
641 struct thread *td, *owner;
644 mtx_assert(&ts->
ts_lock, MA_OWNED);
645 MPASS(ts != curthread->td_turnstile);
654 MPASS(td->td_proc->p_magic == P_MAGIC);
655 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
661 if (td->td_priority < owner->td_priority)
663 thread_unlock(owner);
666 mtx_unlock_spin(&tc->tc_lock);
679 struct thread *td, *td1;
680 struct lock_object *lock;
683 mtx_assert(&ts->
ts_lock, MA_OWNED);
685 MPASS(owner->td_proc->p_magic == P_MAGIC);
686 MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
694 mtx_assert(&tc->tc_lock, MA_OWNED);
695 if (ts == td->td_turnstile) {
696 #ifdef TURNSTILE_PROFILING
698 if (tc->tc_depth > tc->tc_max_depth) {
699 tc->tc_max_depth = tc->tc_depth;
700 if (tc->tc_max_depth > turnstile_max_depth)
701 turnstile_max_depth = tc->tc_max_depth;
704 LIST_INSERT_HEAD(&tc->tc_turnstiles, ts, ts_hash);
706 (
"thread's turnstile has pending threads"));
707 KASSERT(TAILQ_EMPTY(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]),
708 (
"thread's turnstile has exclusive waiters"));
709 KASSERT(TAILQ_EMPTY(&ts->
ts_blocked[TS_SHARED_QUEUE]),
710 (
"thread's turnstile has shared waiters"));
711 KASSERT(LIST_EMPTY(&ts->ts_free),
712 (
"thread's turnstile has a non-empty free list"));
713 MPASS(ts->ts_lockobj != NULL);
715 TAILQ_INSERT_TAIL(&ts->
ts_blocked[queue], td, td_lockq);
719 TAILQ_FOREACH(td1, &ts->
ts_blocked[queue], td_lockq)
720 if (td1->td_priority > td->td_priority)
724 TAILQ_INSERT_BEFORE(td1, td, td_lockq);
726 TAILQ_INSERT_TAIL(&ts->
ts_blocked[queue], td, td_lockq);
727 MPASS(owner == ts->ts_owner);
729 MPASS(td->td_turnstile != NULL);
730 LIST_INSERT_HEAD(&ts->ts_free, td->td_turnstile, ts_hash);
734 td->td_turnstile = NULL;
737 lock = ts->ts_lockobj;
738 td->td_tsqueue = queue;
740 td->td_lockname = lock->lo_name;
741 td->td_blktick =
ticks;
743 mtx_unlock_spin(&tc->tc_lock);
746 if (LOCK_LOG_TEST(lock, 0))
747 CTR4(KTR_LOCK,
"%s: td %d blocked on [%p] %s", __func__,
748 td->td_tid, lock, lock->lo_name);
750 SDT_PROBE0(sched, , , sleep);
752 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
755 if (LOCK_LOG_TEST(lock, 0))
756 CTR4(KTR_LOCK,
"%s: td %d free from blocked on [%p] %s",
757 __func__, td->td_tid, lock, lock->lo_name);
773 mtx_assert(&ts->
ts_lock, MA_OWNED);
774 MPASS(curthread->td_proc->p_magic == P_MAGIC);
775 MPASS(ts->ts_owner == curthread || ts->ts_owner == NULL);
776 MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
783 MPASS(td->td_proc->p_magic == P_MAGIC);
785 TAILQ_REMOVE(&ts->
ts_blocked[queue], td, td_lockq);
787 TAILQ_INSERT_TAIL(&ts->
ts_pending, td, td_lockq);
794 empty = TAILQ_EMPTY(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]) &&
795 TAILQ_EMPTY(&ts->
ts_blocked[TS_SHARED_QUEUE]);
798 mtx_assert(&tc->tc_lock, MA_OWNED);
799 MPASS(LIST_EMPTY(&ts->ts_free));
800 #ifdef TURNSTILE_PROFILING
804 ts = LIST_FIRST(&ts->ts_free);
806 LIST_REMOVE(ts, ts_hash);
807 td->td_turnstile =
ts;
824 mtx_assert(&ts->
ts_lock, MA_OWNED);
825 MPASS(curthread->td_proc->p_magic == P_MAGIC);
826 MPASS(ts->ts_owner == curthread || ts->ts_owner == NULL);
832 mtx_assert(&tc->tc_lock, MA_OWNED);
833 MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
846 TAILQ_FOREACH(td, &ts->
ts_pending, td_lockq) {
847 if (LIST_EMPTY(&ts->ts_free)) {
848 MPASS(TAILQ_NEXT(td, td_lockq) == NULL);
850 #ifdef TURNSTILE_PROFILING
854 ts1 = LIST_FIRST(&ts->ts_free);
856 LIST_REMOVE(ts1, ts_hash);
857 td->td_turnstile = ts1;
875 mtx_assert(&ts->
ts_lock, MA_OWNED);
876 MPASS(ts->ts_owner == curthread || ts->ts_owner == NULL);
883 TAILQ_INIT(&pending_threads);
884 TAILQ_CONCAT(&pending_threads, &ts->
ts_pending, td_lockq);
886 if (TAILQ_EMPTY(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]) &&
887 TAILQ_EMPTY(&ts->
ts_blocked[TS_SHARED_QUEUE]))
888 ts->ts_lockobj = NULL;
906 if (ts->ts_owner != NULL) {
908 LIST_REMOVE(ts, ts_link);
910 LIST_FOREACH(nts, &td->td_contested, ts_link) {
925 while (!TAILQ_EMPTY(&pending_threads)) {
926 td = TAILQ_FIRST(&pending_threads);
927 TAILQ_REMOVE(&pending_threads, td, td_lockq);
928 SDT_PROBE2(sched, , ,
wakeup, td, td->td_proc);
930 THREAD_LOCKPTR_ASSERT(td, &ts->
ts_lock);
931 MPASS(td->td_proc->p_magic == P_MAGIC);
932 MPASS(TD_ON_LOCK(td));
934 MPASS(TD_CAN_RUN(td));
935 td->td_blocked = NULL;
936 td->td_lockname = NULL;
939 td->td_tsqueue = 0xff;
958 mtx_assert(&ts->
ts_lock, MA_OWNED);
959 MPASS(ts->ts_owner == curthread);
961 MPASS(!TAILQ_EMPTY(&ts->
ts_blocked[TS_EXCLUSIVE_QUEUE]) ||
962 !TAILQ_EMPTY(&ts->
ts_blocked[TS_SHARED_QUEUE]));
972 LIST_REMOVE(ts, ts_link);
985 LIST_FOREACH(ts, &td->td_contested, ts_link) {
1004 MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
1005 mtx_assert(&ts->
ts_lock, MA_OWNED);
1007 return (TAILQ_FIRST(&ts->
ts_blocked[queue]));
1019 MPASS(queue == TS_SHARED_QUEUE || queue == TS_EXCLUSIVE_QUEUE);
1020 mtx_assert(&ts->
ts_lock, MA_OWNED);
1022 return (TAILQ_EMPTY(&ts->
ts_blocked[queue]));
1027 print_thread(
struct thread *td,
const char *prefix)
1030 db_printf(
"%s%p (tid %d, pid %d, \"%s\")\n", prefix, td, td->td_tid,
1031 td->td_proc->p_pid, td->td_name[0] !=
'\0' ? td->td_name :
1036 print_queue(
struct threadqueue *queue,
const char *header,
const char *prefix)
1040 db_printf(
"%s:\n", header);
1041 if (TAILQ_EMPTY(queue)) {
1042 db_printf(
"%sempty\n", prefix);
1045 TAILQ_FOREACH(td, queue, td_lockq) {
1046 print_thread(td, prefix);
1050 DB_SHOW_COMMAND(
turnstile, db_show_turnstile)
1054 struct lock_object *lock;
1064 lock = (
struct lock_object *)addr;
1066 LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
1067 if (ts->ts_lockobj == lock)
1074 for (i = 0; i < TC_TABLESIZE; i++)
1080 db_printf(
"Unable to locate a turnstile via %p\n", (
void *)addr);
1083 lock = ts->ts_lockobj;
1084 db_printf(
"Lock: %p - (%s) %s\n", lock, LOCK_CLASS(lock)->lc_name,
1087 print_thread(ts->ts_owner,
"Lock Owner: ");
1089 db_printf(
"Lock Owner: none\n");
1090 print_queue(&ts->ts_blocked[TS_SHARED_QUEUE],
"Shared Waiters",
"\t");
1091 print_queue(&ts->ts_blocked[TS_EXCLUSIVE_QUEUE],
"Exclusive Waiters",
1093 print_queue(&ts->ts_pending,
"Pending Threads",
"\t");
1102 print_lockchain(
struct thread *td,
const char *prefix)
1104 struct lock_object *lock;
1105 struct lock_class *
class;
1112 while (!db_pager_quit) {
1113 db_printf(
"%sthread %d (pid %d, %s) ", prefix, td->td_tid,
1114 td->td_proc->p_pid, td->td_name[0] !=
'\0' ? td->td_name :
1116 switch (td->td_state) {
1118 db_printf(
"is inactive\n");
1121 db_printf(
"can run\n");
1124 db_printf(
"is on a run queue\n");
1127 db_printf(
"running on CPU %d\n", td->td_oncpu);
1130 if (TD_ON_LOCK(td)) {
1131 ts = td->td_blocked;
1132 lock = ts->ts_lockobj;
1133 class = LOCK_CLASS(lock);
1134 db_printf(
"blocked on lock %p (%s) \"%s\"\n",
1135 lock, class->lc_name, lock->lo_name);
1136 if (ts->ts_owner == NULL)
1141 db_printf(
"inhibited\n");
1144 db_printf(
"??? (%#x)\n", td->td_state);
1150 DB_SHOW_COMMAND(lockchain, db_show_lockchain)
1156 td = db_lookup_thread(addr, TRUE);
1160 print_lockchain(td,
"");
1163 DB_SHOW_ALL_COMMAND(chains, db_show_allchains)
1170 FOREACH_PROC_IN_SYSTEM(p) {
1171 FOREACH_THREAD_IN_PROC(p, td) {
1172 if (TD_ON_LOCK(td) && LIST_EMPTY(&td->td_contested)) {
1173 db_printf(
"chain %d:\n", i++);
1174 print_lockchain(td,
" ");
1181 DB_SHOW_ALIAS(allchains, db_show_allchains)
1188 print_sleepchain(struct thread *td, const
char *prefix)
1190 struct thread *owner;
1196 while (!db_pager_quit) {
1197 db_printf(
"%sthread %d (pid %d, %s) ", prefix, td->td_tid,
1198 td->td_proc->p_pid, td->td_name[0] !=
'\0' ? td->td_name :
1200 switch (td->td_state) {
1202 db_printf(
"is inactive\n");
1205 db_printf(
"can run\n");
1208 db_printf(
"is on a run queue\n");
1211 db_printf(
"running on CPU %d\n", td->td_oncpu);
1214 if (TD_ON_SLEEPQ(td)) {
1215 if (lockmgr_chain(td, &owner) ||
1216 sx_chain(td, &owner)) {
1222 db_printf(
"sleeping on %p \"%s\"\n",
1223 td->td_wchan, td->td_wmesg);
1226 db_printf(
"inhibited\n");
1229 db_printf(
"??? (%#x)\n", td->td_state);
1235 DB_SHOW_COMMAND(sleepchain, db_show_sleepchain)
1241 td = db_lookup_thread(addr, TRUE);
1245 print_sleepchain(td,
"");
1248 static void print_waiters(
struct turnstile *ts,
int indent);
1251 print_waiter(
struct thread *td,
int indent)
1258 for (i = 0; i < indent; i++)
1260 print_thread(td,
"thread ");
1261 LIST_FOREACH(ts, &td->td_contested, ts_link)
1262 print_waiters(ts, indent + 1);
1266 print_waiters(struct
turnstile *ts,
int indent)
1268 struct lock_object *lock;
1269 struct lock_class *
class;
1275 lock = ts->ts_lockobj;
1276 class = LOCK_CLASS(lock);
1277 for (i = 0; i < indent; i++)
1279 db_printf(
"lock %p (%s) \"%s\"\n", lock, class->lc_name, lock->lo_name);
1280 TAILQ_FOREACH(td, &ts->ts_blocked[TS_EXCLUSIVE_QUEUE], td_lockq)
1281 print_waiter(td, indent + 1);
1282 TAILQ_FOREACH(td, &ts->
ts_blocked[TS_SHARED_QUEUE], td_lockq)
1283 print_waiter(td, indent + 1);
1285 print_waiter(td, indent + 1);
1288 DB_SHOW_COMMAND(locktree, db_show_locktree)
1290 struct lock_object *lock;
1291 struct lock_class *
class;
1297 lock = (
struct lock_object *)addr;
1299 LIST_FOREACH(ts, &tc->tc_turnstiles, ts_hash)
1300 if (ts->ts_lockobj == lock)
1303 class = LOCK_CLASS(lock);
1304 db_printf(
"lock %p (%s) \"%s\"\n", lock, class->lc_name,
1307 print_waiters(ts, 0);
void kdb_backtrace_thread(struct thread *td)
void turnstile_adjust(struct thread *td, u_char oldpri)
int snprintf(char *str, size_t size, const char *format,...)
void turnstile_broadcast(struct turnstile *ts, int queue)
static SYSCTL_NODE(_debug, OID_AUTO, cpufreq, CTLFLAG_RD, NULL,"cpufreq debugging")
static int turnstile_init(void *mem, int size, int flags)
void turnstile_unpend(struct turnstile *ts, int owner_type)
void panic(const char *fmt,...)
SDT_PROBE_DEFINE(sched,,, sleep)
TAILQ_HEAD(note_info_list, note_info)
void turnstile_disown(struct turnstile *ts)
struct turnstile * turnstile_lookup(struct lock_object *lock)
SYSCTL_UINT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW,&idletick, 0,"Run periodic events when idle")
struct turnstile * turnstile_alloc(void)
void mi_switch(int flags, struct thread *newtd)
SDT_PROVIDER_DECLARE(sched)
static void turnstile_setowner(struct turnstile *ts, struct thread *owner)
struct thread * turnstile_head(struct turnstile *ts, int queue)
void turnstile_free(struct turnstile *ts)
void sched_add(struct thread *td, int flags)
static int turnstile_adjust_thread(struct turnstile *ts, struct thread *td)
void thread_lock_set(struct thread *td, struct mtx *new)
void sched_lend_prio(struct thread *td, u_char prio)
static void propagate_priority(struct thread *td)
void turnstile_wait(struct turnstile *ts, struct thread *owner, int queue)
static struct thread * turnstile_first_waiter(struct turnstile *ts)
void turnstile_chain_unlock(struct lock_object *lock)
int turnstile_signal(struct turnstile *ts, int queue)
struct thread * kdb_thread
int printf(const char *fmt,...)
static long empty[CPUSTATES]
void turnstile_claim(struct turnstile *ts)
struct threadqueue ts_pending
static uma_zone_t turnstile_zone
void mtx_init(struct mtx *m, const char *name, const char *type, int opts)
SYSINIT(turnstile0, SI_SUB_LOCK, SI_ORDER_ANY, init_turnstile0, NULL)
struct threadqueue ts_blocked[2]
void init_turnstiles(void)
struct turnstile * turnstile_trywait(struct lock_object *lock)
void turnstile_cancel(struct turnstile *ts)
void turnstile_chain_lock(struct lock_object *lock)
static void turnstile_fini(void *mem, int size)
static struct turnstile_chain turnstile_chains[TC_TABLESIZE]
static void init_turnstile0(void *dummy)
void mtx_destroy(struct mtx *m)
static struct mtx td_contested_lock
void sched_unlend_prio(struct thread *td, u_char prio)
int turnstile_empty(struct turnstile *ts, int queue)
SDT_PROBE_DEFINE2(sched,,, wakeup,"struct thread *","struct proc *")