- /*
- * Walks the chain of turnstiles and their owners to propagate the priority
- * of the thread being blocked to all the threads holding locks that have to
- * release their locks before this thread can run again.
- */
- /*
- * 这样做的目的就是防止优先级翻转,但我不明白为什么涉及多个turnstile,按理一个锁只涉及一个turnstile,参数的线程是被block的那个线程
- */
- static void
- propagate_priority(struct thread *td)
- {
- struct turnstile *ts;
- int pri;
- THREAD_LOCK_ASSERT(td, MA_OWNED);
- pri = td->td_priority;
- ts = td->td_blocked;
- THREAD_LOCKPTR_ASSERT(td, &ts->ts_lock);
- /*
- * Grab a recursive lock on this turnstile chain so it stays locked
- * for the whole operation. The caller expects us to return with
- * the original lock held. We only ever lock down the chain so
- * the lock order is constant.
- */
- mtx_lock_spin(&ts->ts_lock);
- for (;;) {
- td = ts->ts_owner; /*拥有锁的那个thread*/
- if (td == NULL) {
- /*
- * This might be a read lock with no owner. There's
- * not much we can do, so just bail.
- */
- mtx_unlock_spin(&ts->ts_lock);
- return;
- }
- thread_lock_flags(td, MTX_DUPOK);
- mtx_unlock_spin(&ts->ts_lock);
- MPASS(td->td_proc != NULL);
- MPASS(td->td_proc->p_magic == P_MAGIC);
- /*
- * If the thread is asleep, then we are probably about
- * to deadlock. To make debugging this easier, just
- * panic and tell the user which thread misbehaved so
- * they can hopefully get a stack trace from the truly
- * misbehaving thread.
- */
- if (TD_IS_SLEEPING(td)) {/*如果拥有锁的线程在sleep,则直接panic,所以获得mutex锁后不调用msleep或者tsleep这类的函数否则新线程起来等这个锁的时候会挂*/
- printf(
- "Sleeping thread (tid %d, pid %d) owns a non-sleepable lock\n",
- td->td_tid, td->td_proc->p_pid);
- #ifdef DDB
- db_trace_thread(td, -1);
- #endif
- panic("sleeping thread");
- }
- /*
- * If this thread already has higher priority than the
- * thread that is being blocked, we are finished.
- */
- /*看这意思是优先级数值越小,则优先级越高,如果执行的优先级比较高,则没事*/
- if (td->td_priority <= pri) {
- thread_unlock(td);
- return;
- }
- /*
- * Bump this thread's priority.
- */
- sched_lend_prio(td, pri);/*调整有锁线程的优先级,让他快点跑完*/
- /*
- * If lock holder is actually running or on the run queue
- * then we are done.
- */
- if (TD_IS_RUNNING(td) || TD_ON_RUNQ(td)) {
- MPASS(td->td_blocked == NULL);
- thread_unlock(td);
- return;
- }
- #ifndef SMP
- /*
- * For UP, we check to see if td is curthread (this shouldn't
- * ever happen however as it would mean we are in a deadlock.)
- */
- KASSERT(td != curthread, ("Deadlock detected"));
- #endif
- /*
- * If we aren't blocked on a lock, we should be.
- */
- KASSERT(TD_ON_LOCK(td), (
- "thread %d(%s):%d holds %s but isn't blocked on a lock\n",
- td->td_tid, td->td_name, td->td_state,
- ts->ts_lockobj->lo_name));
- /*
- * Pick up the lock that td is blocked on.
- */
- ts = td->td_blocked;
- MPASS(ts != NULL);
- THREAD_LOCKPTR_ASSERT(td, &ts->ts_lock);
- /* Resort td on the list if needed. */
- if (!turnstile_adjust_thread(ts, td)) {
- mtx_unlock_spin(&ts->ts_lock);
- return;
- }
- /* The thread lock is released as ts lock above. */
- }
- }
阅读(863) | 评论(0) | 转发(0) |