Chinaunix首页 | 论坛 | 博客
  • 博客访问: 195127
  • 博文数量: 29
  • 博客积分: 1280
  • 博客等级: 中尉
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2005-02-22 16:23
文章分类

全部博文(29)

文章存档

2009年(3)

2008年(1)

2007年(1)

2006年(3)

2005年(21)

我的朋友

分类: 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之前,还有些数据结构没初始化,所以要先锁住*/
}

阅读(2479) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~