Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 13 Apr 2017 17:28:04 +0800
From:      Yubin Ruan <ablacktshirt@gmail.com>
To:        Chris Torek <torek@elf.torek.net>, imp@bsdimp.com
Cc:        ed@nuxi.nl, freebsd-hackers@freebsd.org, rysto32@gmail.com, kostikbel@gmail.com
Subject:   Re: Understanding the FreeBSD locking mechanism
Message-ID:  <06a30d21-acff-efb2-ff58-9aa66793e929@gmail.com>
In-Reply-To: <201704121853.v3CIrg5d055158@elf.torek.net>
References:  <201704121853.v3CIrg5d055158@elf.torek.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2017年04月13日 02:53, Chris Torek wrote:
>>> If you obtain the locks in the other order -- i.e., if you grab
>>> the PROC_STATLOCK first, then try to lock PROC_LOCK -- you are
>>> trying to take a spin-type mutex while holding a default mutex,
>
>> Is this a typo? I guess you mean something like "you are trying
>> to take a blocking mutex while holding spin-type mutex".
>
> Yes, or rather brain-o (swapping words) -- these most often happen
> if I am interrupted while composing a message :-)
>
>> I think I get your point: if you take a spin-type mutex, you
>> already disable interrupt, which in effect means that no other
>> code can preempt you. Under this circumstance, if you continue to
>> take a blocking mutex, you may get blocked. Since you already
>> disable interrupt and nobody can interrupt/preempt you, you are blocked
>> on that CPU, not being able to do anything, which is pretty much a
>> "deadlock" (actually this is not a deadlock, but, it is similar)
>
> Right.  It *may* deadlock, and it is definitely not good -- and
> the INVARIANTS kernel will check and panic.

I discover that in the current implementation in FreeBSD, spinlock
does not disable interrupt entirely:


   607         for (;;) {
   608                 if (m->mtx_lock == MTX_UNOWNED && 
_mtx_obtain_lock(m, tid))
   609                         break;
   610                 /* Give interrupts a chance while we spin. */
   611                 spinlock_exit();
   612                 while (m->mtx_lock != MTX_UNOWNED) {
   613                         if (i++ < 10000000) {
   614                                 cpu_spinwait();
   615                                 continue;
   616                         }
   617                         if (i < 60000000 || kdb_active || 
panicstr != NULL)
   618                                 DELAY(1);
   619                         else
   620                                 _mtx_lock_spin_failed(m);
   621                         cpu_spinwait();
   622                 }
   623                 spinlock_enter();
   624         }

This is `_mtx_lock_spin_cookie(...)` in kern/kern_mutex.c, which
implements the core logic of spinning. However, as you can see, while
spinning, it would enable interrupt "occasionally" and disable it
again... What is the rationale for that?

Regards,
Yubin Ruan



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?06a30d21-acff-efb2-ff58-9aa66793e929>