Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 9 Apr 2017 18:13:40 +0800
From:      Yubin Ruan <ablacktshirt@gmail.com>
To:        Ed Schouten <ed@nuxi.nl>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Understanding the FreeBSD locking mechanism
Message-ID:  <c72c0ee3-328d-3efc-e8a0-4d6c0d5c8cee@gmail.com>
In-Reply-To: <CABh_MKkbVVi%2BgTkaBVDvVfRggS6pbHKJE_VbYBZpAaTCZ81b7Q@mail.gmail.com>
References:  <e99b6366-7d30-a889-b7db-4a3b3133ff5e@gmail.com> <CABh_MKkbVVi%2BgTkaBVDvVfRggS6pbHKJE_VbYBZpAaTCZ81b7Q@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2017/4/6 17:31, Ed Schouten wrote:
> Hi Yubin,
>
> 2017-04-06 11:16 GMT+02:00 Yubin Ruan <ablacktshirt@gmail.com>:
>> Does this function provides the ordinary "spinlock" functionality? There
>> is no special "test-and-set" instruction, and neither any extra locking
>> to protect internal data structure manipulation. Isn't this subjected to
>> race condition?
>
> Locking a spinlock is done through macro mtx_lock_spin(), which
> expands to __mtx_lock_spin() in sys/sys/mutex.h. That macro first
> calls into the function you looked at, spinlock_enter(), to disable
> interrupts. It then calls into the _mtx_obtain_lock_fetch() to do the
> test-and-set operation you were looking for.

Thanks for replying. I have read some of those codes.

Just a few more questions, if you don't mind:

(1) why are spinlocks forced to disable interrupt in FreeBSD?

 From the book "The design and implementation of the FreeBSD Operating
System", the authors say "spinning can result in deadlock if a thread 
interrupted the thread that held a mutex and then tried to acquire the 
mutex"...(section 4.3, Mutex Synchronization, paragraph 4)

I don't get the point why a spinlock(or *spin mutex* in the FreeBSD
world) has to disable interrupt. Being interrupted does not necessarily
mean a deadlock. Assume that thread A holding a lock T gets interrupted
by another thread B(context switch here) and thread B try to acquire
the lock T. After finding out that lock T has already been acquired,
thread B will just spin until it gets preempted, after which thread A
gets waken up and run and release the lock T. So, you see there is not
necessarily any deadlock even if thread A get interrupted.

I can only remember two conditions where using spinlock without
disabling interrupts will cause deadlock:

#######1, spinlock used in an interrupt handler
If a thread A holding a spinlock T get interrupted and the interrupt
handler responsible for this interrupt try to acquire T, then we have
deadlock, because A would never have a chance to run before the
interrupt handler return, and the interrupt handler, unfortunately,
will continue to spin ... so in this situation, one has to disable
interrupt before spinning.

As far as I know, in Linux, they provide two kinds of spinlocks:

   spin_lock(..);   /* spinlock that does not disable interrupts */
   spin_lock_irqsave(...); /* spinlock that disable local interrupt */


#######2, priority inversion problem
If thread B with a higher priority get in and try to acquire the lock
that thread A currently holds, then thread B would spin, while at the
same time thread A has no chance to run because it has lower priority,
thus not being able to release the lock.
(I haven't investigate enough into the source code, so I don't know
how FreeBSD and Linux handle this priority inversion problem. Maybe
they use priority inheritance or random boosting?)

thanks,
Yubin Ruan



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?c72c0ee3-328d-3efc-e8a0-4d6c0d5c8cee>