分类: BSD
2005-10-17 14:00:01
/*-
* 跳过BSD版权申明
*/
#include
__FBSDID("$FreeBSD: src/sys/kern/kern_mutex.c,v 1.147.2.3 2004/10/16 02:14:59 ups Exp $");
#include "opt_adaptive_mutexes.h"
#include "opt_ddb.h"
#include "opt_mprof.h"
#include "opt_mutex_wake_all.h"
#include "opt_sched.h" /*以上是编译时产生的头文件,根据配置文件而产生*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*
* 单个线程唤醒需要修复以避免优先权继承竞争条件
*/
#ifndef MUTEX_WAKE_ALL
#define MUTEX_WAKE_ALL
#endif
/*
* 内部使用的宏.
*/
#define mtx_unowned(m) ((m)->mtx_lock == MTX_UNOWNED)/* 该互斥体还没有被其他线程拥有时返回真*/
#define mtx_owner(m) (mtx_unowned((m)) ? NULL
: (struct thread *)((m)->mtx_lock & MTX_FLAGMASK))/* 该互斥体已经被某线程拥有时返回该线程地址指针,否则返回空*/
/* 以下是对于可睡眠或自旋的互斥体定义其所属锁的类,关于lock_class是在src/sys/sys/lock.h文件中有定义.
*/
struct lock_class lock_class_mtx_sleep = {
"sleep mutex",
LC_SLEEPLOCK | LC_RECURSABLE /*属于可睡眠并可嵌套的一类锁,lock_class结构是mtx结构的一成员,说明互斥体的锁的属性*/
};
struct lock_class lock_class_mtx_spin = {
"spin mutex",
LC_SPINLOCK | LC_RECURSABLE /*属于可自旋并可嵌套的一类锁*/
};
/*
* 系统范围内的互斥体
*/
struct mtx sched_lock;/*用于进程调度的互斥体*/
struct mtx Giant; /*用于全局代码的互斥体*/
#ifdef MUTEX_PROFILING
...关于一些调试代码我在这不予以讨论
#endif
/* __mtx_*宏的内连函数版本,可用于从汇编语言调用,实际上是mtx_lock函数对他进行调用
* mtx_lock(m)即为:_mtx_lock_flags(struct mtx *m,0,LOCK_FILE, LOCK_LINE)
*/
void
_mtx_lock_flags(struct mtx *m, int opts, const char *file, int line)
{
MPASS(curthread != NULL); /*检查当前线程,curthread为当前正在运行线程,该指针不能为空*/
KASSERT(m->mtx_object.lo_class == &lock_class_mtx_sleep,
("mtx_lock() of spin mutex %s @ %s:%d", m->mtx_object.lo_name,
file, line)); /*也是一检查宏,因为整个函数是针对可睡眠互斥体,如果互斥体m属于自旋互斥体则报错*/
WITNESS_CHECKORDER(&m->mtx_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE,
file, line);/*witness_checkorder函数将检查线程占用多个锁时,是否会引起死锁等,该函数在/sys/kern/subr_witness.c中*/
_get_sleep_lock(m, curthread, opts, file, line);
/* _get_sleep_lock实际上是一宏,在文件mutex.h头文件中定义:
#ifndef _get_sleep_lock
#define _get_sleep_lock(mp, tid, opts, file, line) do {
struct thread *_tid = (tid);
if (!_obtain_lock((mp), _tid))
_mtx_lock_sleep((mp), _tid, (opts), (file), (line));
} while (0)
#endif
意思是获得互斥体mp如果不成功,则调用_mtx_lock_sleep函数,该函数将在下面讲解.
*/
LOCK_LOG_LOCK("LOCK", &m->mtx_object, opts, m->mtx_recurse, file, line);
WITNESS_LOCK(&m->mtx_object, opts | LOP_EXCLUSIVE, file, line);
}
void
_mtx_unlock_flags(struct mtx *m, int opts, const char *file, int line)
{
MPASS(curthread != NULL);
KASSERT(m->mtx_object.lo_class == &lock_class_mtx_sleep,
("mtx_unlock() of spin mutex %s @ %s:%d", m->mtx_object.lo_name,
file, line));
WITNESS_UNLOCK(&m->mtx_object, opts | LOP_EXCLUSIVE, file, line);
LOCK_LOG_LOCK("UNLOCK", &m->mtx_object, opts, m->mtx_recurse, file,
line);
mtx_assert(m, MA_OWNED);
_rel_sleep_lock(m, curthread, opts, file, line);
}
void
_mtx_lock_spin_flags(struct mtx *m, int opts, const char *file, int line)
{
MPASS(curthread != NULL);
KASSERT(m->mtx_object.lo_class == &lock_class_mtx_spin,
("mtx_lock_spin() of sleep mutex %s @ %s:%d",
m->mtx_object.lo_name, file, line));
WITNESS_CHECKORDER(&m->mtx_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE,
file, line);
#if defined(SMP) || LOCK_DEBUG > 0 || 1
_get_spin_lock(m, curthread, opts, file, line);
#else
critical_enter();
#endif
LOCK_LOG_LOCK("LOCK", &m->mtx_object, opts, m->mtx_recurse, file,
line);
WITNESS_LOCK(&m->mtx_object, opts | LOP_EXCLUSIVE, file, line);
}
void
_mtx_unlock_spin_flags(struct mtx *m, int opts, const char *file, int line)
{
MPASS(curthread != NULL);
KASSERT(m->mtx_object.lo_class == &lock_class_mtx_spin,
("mtx_unlock_spin() of sleep mutex %s @ %s:%d",
m->mtx_object.lo_name, file, line));
WITNESS_UNLOCK(&m->mtx_object, opts | LOP_EXCLUSIVE, file, line);
LOCK_LOG_LOCK("UNLOCK", &m->mtx_object, opts, m->mtx_recurse, file,
line);
mtx_assert(m, MA_OWNED);
#if defined(SMP) || LOCK_DEBUG > 0 || 1
_rel_spin_lock(m);
#else
critical_exit();
#endif
}
/*
* 目前来看,该函数到和互斥体的支撑函数没有多大关系.申明调用宏的只有vnode,signal.proc和if四个部分
* 其中只有vnode和if在代码中用到了该函数.该函数用于那些知道本身不能进行阻塞的线程. 在这只是快速
* 取得互斥体后返回.
*/
int
_mtx_trylock(struct mtx *m, int opts, const char *file, int line)
{
int rval;
MPASS(curthread != NULL);/*只是检查*/
if (mtx_owned(m) && (m->mtx_object.lo_flags & LO_RECURSABLE) != 0) {/*如果当前线程已经拥有该互斥体并且该互斥体的锁属性允许嵌套*/
m->mtx_recurse++;/*嵌套数加1*/
atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);/*原子操作过程.原形在/sys/i386/include/atomic.h头文件中.*/
/*为一内连函数,由ATOMIC_PTR(set)展开后为该函数,函数最后为*/
/*atomic_set_int((volatile u_int *)p, v),实际上就是(*(u_int*)(P) |= (V))*/
/*意思是:使mtx_lock加上MTX_RECURSED已经被嵌套标志.*/
rval = 1;/**/
} else
rval = _obtain_lock(m, curthread);/*_obtain_lock函数在我写的mutex.h头文件中有解释,用于获取m,成功返回非0值*/
LOCK_LOG_TRY("LOCK", &m->mtx_object, opts, rval, file, line);/*记录操作*/
if (rval)/*如果获取互斥体成功*/
WITNESS_LOCK(&m->mtx_object, opts | LOP_EXCLUSIVE | LOP_TRYLOCK,
file, line);
return (rval);
}
/*
* _mtx_lock_sleep: the tougher part of acquiring an MTX_DEF lock.
*
* We call this if the lock is either contested (i.e. we need to go to
* sleep waiting for it), or if we need to recurse on it.
*/
void
_mtx_lock_sleep(struct mtx *m, struct thread *td, int opts, const char *file,
int line)
{
struct turnstile *ts;
#if defined(SMP) && !defined(NO_ADAPTIVE_MUTEXES)
struct thread *owner;
#endif
uintptr_t v;
#ifdef KTR
int cont_logged = 0;
#endif
if (mtx_owned(m)) {
KASSERT((m->mtx_object.lo_flags & LO_RECURSABLE) != 0,
("_mtx_lock_sleep: recursed on non-recursive mutex %s @ %s:%d
",
m->mtx_object.lo_name, file, line));
m->mtx_recurse++;
atomic_set_ptr(&m->mtx_lock, MTX_RECURSED);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_sleep: %p recursing", m);
return;
}
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR4(KTR_LOCK,
"_mtx_lock_sleep: %s contested (lock=%p) at %s:%d",
m->mtx_object.lo_name, (void *)m->mtx_lock, file, line);
while (!_obtain_lock(m, td)) {
ts = turnstile_lookup(&m->mtx_object);
v = m->mtx_lock;
/*
* Check if the lock has been released while spinning for
* the turnstile chain lock.
*/
if (v == MTX_UNOWNED) {
turnstile_release(&m->mtx_object);
cpu_spinwait();
continue;
}
#ifdef MUTEX_WAKE_ALL
MPASS(v != MTX_CONTESTED);
#else
/*
* The mutex was marked contested on release. This means that
* there are other threads blocked on it. Grab ownership of
* it and propagate its priority to the current thread if
* necessary.
*/
if (v == MTX_CONTESTED) {
MPASS(ts != NULL);
m->mtx_lock = (uintptr_t)td | MTX_CONTESTED;
turnstile_claim(ts);
break;
}
#endif
/*
* If the mutex isn't already contested and a failure occurs
* setting the contested bit, the mutex was either released
* or the state of the MTX_RECURSED bit changed.
*/
if ((v & MTX_CONTESTED) == 0 &&
!atomic_cmpset_ptr(&m->mtx_lock, (void *)v,
(void *)(v | MTX_CONTESTED))) {
turnstile_release(&m->mtx_object);
cpu_spinwait();
continue;
}
#if defined(SMP) && !defined(NO_ADAPTIVE_MUTEXES)
/*
* If the current owner of the lock is executing on another
* CPU, spin instead of blocking.
*/
owner = (struct thread *)(v & MTX_FLAGMASK);
#ifdef ADAPTIVE_GIANT
if (TD_IS_RUNNING(owner)) {
#else
if (m != &Giant && TD_IS_RUNNING(owner)) {
#endif
turnstile_release(&m->mtx_object);
while (mtx_owner(m) == owner && TD_IS_RUNNING(owner)) {
cpu_spinwait();
}
continue;
}
#endif /* SMP && !NO_ADAPTIVE_MUTEXES */
/*
* We definitely must sleep for this lock.
*/
mtx_assert(m, MA_NOTOWNED);
#ifdef KTR
if (!cont_logged) {
CTR6(KTR_CONTENTION,
"contention: %p at %s:%d wants %s, taken by %s:%d",
td, file, line, m->mtx_object.lo_name,
WITNESS_FILE(&m->mtx_object),
WITNESS_LINE(&m->mtx_object));
cont_logged = 1;
}
#endif
/*
* Block on the turnstile.
*/
turnstile_wait(ts, &m->mtx_object, mtx_owner(m));
}
#ifdef KTR
if (cont_logged) {
CTR4(KTR_CONTENTION,
"contention end: %s acquired by %p at %s:%d",
m->mtx_object.lo_name, td, file, line);
}
#endif
return;
}
/*
* _mtx_lock_spin: the tougher part of acquiring an MTX_SPIN lock.
*
* This is only called if we need to actually spin for the lock. Recursion
* is handled inline.
*/
void
_mtx_lock_spin(struct mtx *m, struct thread *td, int opts, const char *file,
int line)
{
int i = 0;
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_spin: %p spinning", m);
for (;;) {/*无限循环,直到获取互斥体m*/
if (_obtain_lock(m, td))/*获取互斥体m,返回非0值为成功.详见我在mutex.h中的分析*/
break;/*获得后退出循环*/
/* Give interrupts a chance while we spin. */
critical_exit();
/* 函数作用是从临界区退出.我们来看看该函数的原形:
------------>
void
critical_exit(void)
{
struct thread *td;
td = curthread; -------->取当前线程
KASSERT(td->td_critnest != 0, ("critical_exit: td_critnest == 0"));如果该线程没进入临界区则错误
这里要做个说明,线程在建立时,td_critnest被置为1,因为默认将等待上下文的切换,而这种切换是置于临界区的.
if (td->td_critnest == 1) { ----------》如果该线程只进入临界区1次(没嵌套)
if (td->td_pflags & TDP_WAKEPROC0) {
td->td_pflags &= ~TDP_WAKEPROC0;
wakeup(&proc0);
}
#ifdef PREEMPTION
mtx_assert(&sched_lock, MA_NOTOWNED);
if (td->td_pflags & TDP_OWEPREEMPT) {
mtx_lock_spin(&sched_lock);
mi_switch(SW_INVOL, NULL);
mtx_unlock_spin(&sched_lock);
}
#endif
td->td_critnest = 0;-------->标志将退出临界区
cpu_critical_exit(td); ----------》退出临界区(与cpu_critical_enter相对应)
} else { --------->如果多次进入临界区
td->td_critnest--; -----------------》临界区进入次数减1
}
}
*/
while (m->mtx_lock != MTX_UNOWNED) {
if (i++ < 10000000) {
cpu_spinwait();/*汇编语句pause,实际上是等待中断的发生.希望占有该互斥体的线程解锁*/
continue;
}
if (i < 60000000)/*循环等待这么多次后还没解锁*/
DELAY(1);
else if (!kdb_active) {
printf("spin lock %s held by %p for > 5 seconds
",
m->mtx_object.lo_name, (void *)m->mtx_lock);
#ifdef WITNESS /*如果打开了WITNESS监测*/
witness_display_spinlock(&m->mtx_object,mtx_owner(m));/*显示WITNESS情况*/
#endif
panic("spin lock held too long");/*系统通知哪个线程序拥有该锁时间太长*/
}
cpu_spinwait();/*继续等待中断发生以解除该互斥体*/
}
critical_enter();/*互斥体已经解除锁,进入临界区*/
}
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
return;
}
/*
* _mtx_unlock_sleep: the tougher part of releasing an MTX_DEF lock.
*
* We are only called here if the lock is recursed or contested (i.e. we
* need to wake up a blocked thread).
*/
void
_mtx_unlock_sleep(struct mtx *m, int opts, const char *file, int line)
{
struct turnstile *ts;
#ifndef PREEMPTION
struct thread *td, *td1;
#endif
if (mtx_recursed(m)) {
if (--(m->mtx_recurse) == 0)
atomic_clear_ptr(&m->mtx_lock, MTX_RECURSED);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p unrecurse", m);
return;
}
ts = turnstile_lookup(&m->mtx_object);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p contested", m);
#if defined(SMP) && !defined(NO_ADAPTIVE_MUTEXES)
if (ts == NULL) {
_release_lock_quick(m);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p no sleepers", m);
turnstile_release(&m->mtx_object);
return;
}
#else
MPASS(ts != NULL);
#endif
#ifndef PREEMPTION
/* XXX */
td1 = turnstile_head(ts);
#endif
#ifdef MUTEX_WAKE_ALL
turnstile_broadcast(ts);
_release_lock_quick(m);
#else
if (turnstile_signal(ts)) {
_release_lock_quick(m);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p not held", m);
} else {
m->mtx_lock = MTX_CONTESTED;
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR1(KTR_LOCK, "_mtx_unlock_sleep: %p still contested",
m);
}
#endif
turnstile_unpend(ts);
#ifndef PREEMPTION
/*
* XXX: This is just a hack until preemption is done. However,
* once preemption is done we need to either wrap the
* turnstile_signal() and release of the actual lock in an
* extra critical section or change the preemption code to
* always just set a flag and never do instant-preempts.
*/
td = curthread;
if (td->td_critnest > 0 || td1->td_priority >= td->td_priority)
return;
mtx_lock_spin(&sched_lock);
if (!TD_IS_RUNNING(td1)) {
#ifdef notyet
if (td->td_ithd != NULL) {
struct ithd *it = td->td_ithd;
if (it->it_interrupted) {
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK,
"_mtx_unlock_sleep: %p interrupted %p",
it, it->it_interrupted);
intr_thd_fixup(it);
}
}
#endif
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK,
"_mtx_unlock_sleep: %p switching out lock=%p", m,
(void *)m->mtx_lock);
mi_switch(SW_INVOL, NULL);
if (LOCK_LOG_TEST(&m->mtx_object, opts))
CTR2(KTR_LOCK, "_mtx_unlock_sleep: %p resuming lock=%p",
m, (void *)m->mtx_lock);
}
mtx_unlock_spin(&sched_lock);
#endif
return;
}
/*
* All the unlocking of MTX_SPIN locks is done inline.
* See the _rel_spin_lock() macro for the details.
*/
/*
* The backing function for the INVARIANTS-enabled mtx_assert()
*/
#ifdef INVARIANT_SUPPORT
void
_mtx_assert(struct mtx *m, int what, const char *file, int line)
{
if (panicstr != NULL)
return;
switch (what) {
case MA_OWNED:
case MA_OWNED | MA_RECURSED:
case MA_OWNED | MA_NOTRECURSED:
if (!mtx_owned(m))
panic("mutex %s not owned at %s:%d",
m->mtx_object.lo_name, file, line);
if (mtx_recursed(m)) {
if ((what & MA_NOTRECURSED) != 0)
panic("mutex %s recursed at %s:%d",
m->mtx_object.lo_name, file, line);
} else if ((what & MA_RECURSED) != 0) {
panic("mutex %s unrecursed at %s:%d",
m->mtx_object.lo_name, file, line);
}
break;
case MA_NOTOWNED:
if (mtx_owned(m))
panic("mutex %s owned at %s:%d",
m->mtx_object.lo_name, file, line);
break;
default:
panic("unknown mtx_assert at %s:%d", file, line);
}
}
#endif
/*
* 由宏 MTX_SYSINIT() 调用的函数.该宏定义在mutex.h头文件中.
*/
void
mtx_sysinit(void *arg)
{
struct mtx_args *margs = arg;
mtx_init(margs->ma_mtx, margs->ma_desc, NULL, margs->ma_opts);
}
/* 该函数用于初始化一个具体的互斥体
* 参数m指向一要初始化的互斥体结构.比如网卡设备驱动(如:fxp的驱动程序)的if_XXXvar.h中一般都有XXX_softc结构.
* 在该结构中一般都有mtx成员,且初始化一般都会在XXX_attach函数中调用.
* 参数name是互斥体的名称
* 参数type是对互斥体类型的一个说明,有些互斥体在初始化时不做说明,只是简单的用前面的参数name来代替
* 参数opts是互斥体的一些属性,各属性的意义请查看我在mutex.h头文件中所做的说明
*/
void
mtx_init(struct mtx *m, const char *name, const char *type, int opts)
{
struct lock_object *lock;
MPASS((opts & ~(MTX_SPIN | MTX_QUIET | MTX_RECURSE |
MTX_NOWITNESS | MTX_DUPOK)) == 0);
/*opts中只要有上述的标志中的一种就被系统认为是合法的.这实际上是对系统扩充时(加入其他互斥体)的检查*/
#ifdef MUTEX_DEBUG
/* 调试代码在这不讨论 */
mtx_validate(m);
#endif
lock = &m->mtx_object;/*lock指向该互斥体结构中的lock_object成员结构*/
KASSERT((lock->lo_flags & LO_INITIALIZED) == 0,/*因为该互斥体还未被初始化,所以不应该有已经初始化标志LO_INITIALIZED*/
("mutex "%s" %p already initialized", name, m));
bzero(m, sizeof(*m));/*对整个互斥体m清0,准备初始化*/
if (opts & MTX_SPIN)/*如果opts参数中有MTX_SPIN,说明该互斥体是属于可自旋的互斥体*/
lock->lo_class = &lock_class_mtx_spin;/*该互斥体的锁的属性结构指向可自旋锁类结构*/
else
lock->lo_class = &lock_class_mtx_sleep;/*否则指向可睡眠锁结构*/
/*关于锁类型的属性,在本文件开始部分已经介绍过两中,即lock_class_mtx_spin和lock_class_mtx_sleep.实际上在系统中还有一种
他是在文件/sys/kern/kern_sx.c中的lock_class_sx类型的锁,目前我们不对他进行讨论.
*/
lock->lo_name = name;/*锁的名称.*/
/*我们随意看个例子,如if_vr.c(即威盛网卡的驱动程序)中,在驱动初始化链接设备到ifnet结构链中(函数vr_attach):
mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,MTX_DEF);
*/
lock->lo_type = type != NULL ? type : name;/*如果参数type为空就只用锁名字的指针*/
if (opts & MTX_QUIET) /*以下4个if语句是统一mutex和该lock的标志*/
lock->lo_flags = LO_QUIET;
if (opts & MTX_RECURSE)
lock->lo_flags |= LO_RECURSABLE;
if ((opts & MTX_NOWITNESS) == 0)
lock->lo_flags |= LO_WITNESS;
if (opts & MTX_DUPOK)
lock->lo_flags |= LO_DUPOK;
m->mtx_lock = MTX_UNOWNED;/*MTX_UNOWNED标志代表目前该互斥体还没有被任何线程拥有*/
LOCK_LOG_INIT(lock, opts);/*记录到日志中*/
WITNESS_INIT(lock);/*调用/sys/kern/subr_witness.c中的witness_init函数.检查锁标志和锁所属类的标志的一致性
以及把该锁插入到所有锁对列(all_locks对列)中,并置初始化标志LO_INITIALIZED,最后从
自由的witness列表中选取一个相关的witness结构.我将在讲解subr_witness.c时详细说明*/
}
/* 从all_mtx(所有互斥体对列)中删除.
*/
void
mtx_destroy(struct mtx *m)
{
/*在lock.h头文件中,我已经说明不对一些LOCK_LOG开头(调试或记录)的宏进行分析*/
LOCK_LOG_DESTROY(&m->mtx_object, 0);
if (!mtx_owned(m))/*如果该互斥体不是被当前线程拥有,也就是说,要么是别的线程拥有,要么就是没有谁拥有*/
MPASS(mtx_unowned(m));/*如果互斥体m被其他线程拥有时系统panic*/
else {/*当前线程是互斥体m的拥有者*/
MPASS((m->mtx_lock & (MTX_RECURSED|MTX_CONTESTED)) == 0);
/*当互斥体m已经被嵌套或被竞争时,系统panic*/
/* 当然还要对m解锁. */
WITNESS_UNLOCK(&m->mtx_object, LOP_EXCLUSIVE, __FILE__, __LINE__);
/*解锁的过程在subr_witness.c中.目的是先找到锁的实例lock_instance,然后在其对应的lock_list_entry列表中删除.*/
}
WITNESS_DESTROY(&m->mtx_object);
/*利用成员mtx_object结构中的witness结构指针定位该锁的witness,再查证其是否有多个线程持有.
然后把该锁指针从all_locks队列中移除.并清理掉初始化标志LO_INITIALIZED,该宏扩展后的函数
在subr_witness.c中
*/
}
/* 初始化互斥体使用环境和一些系统的互斥体.该函数在系统初始化调用时被调用(mi_startup)
* 在该函数被调用前,各CPU数据结构空间必须被设置好
*/
void
mutex_init(void)
{
/* 设置 thread0 后互斥体可以开始工作. */
LIST_INIT(&thread0.td_contested);
/*LIST_INIT宏展开后为:
thread0.td_contested->lh_first = NULL;
在syssysproc.h第268行中对线程的td_contested成员进行了结构定义:LIST_HEAD(, turnstile) td_contested;
*/
/* 设置转门锁后可睡眠互斥体可以开始工作.即对系统定义的128个十字转门链进行初始化,详见/sys/kern/subr_turnstile.c */
init_turnstiles();
/*
* 初始化系统的一些互斥体.
*/
mtx_init(&Giant, "Giant", NULL, MTX_DEF | MTX_RECURSE); /*应该是全局使用的互斥体,初始化为可睡眠互斥体(即MTX_DEF)*/
mtx_init(&sched_lock, "sched lock", NULL, MTX_SPIN | MTX_RECURSE);/*调度器用的互斥体,属于自旋互斥体*/
mtx_init(&proc0.p_mtx, "process lock", NULL, MTX_DEF | MTX_DUPOK);/*进程互斥体,MTX_DUPOK代表不记录请求副本到日志中*/
mtx_lock(&Giant);/*在使用Giant之前,还有些数据结构没初始化,所以要先锁住*/
}