Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 Sep 2000 02:49:58 +0000 (GMT)
From:      Terry Lambert <tlambert@primenet.com>
To:        arch@freebsd.org
Cc:        tlambert@primenet.com
Subject:   Re: Mutexes and semaphores (was: cvs commit: src/sys/conf files
Message-ID:  <200009260249.TAA08391@usr05.primenet.com>
In-Reply-To: <200009260209.TAA03815@vashon.polstra.com> from "John Polstra" at Sep 25, 2000 07:09:28 PM

next in thread | previous in thread | raw e-mail | index | archive | help
> > Fine.  Then we're agreed: non-recursive mutexes are the base unit,
> > and recursion will be implemented on a case by case basis using
> > an additional structure, which contains a non-recursive mutex, a
> > recursion counter, and an owner field.
> 
> That's simply a less efficient implementation of a recursive mutex.
> Why not use the real thing?

No we're back to my original question: where in the code is
there a perceived need for mutex recursion, or is this just
a case of the mutex code being bloated for no good reason?


> > Glad that's settled, until the first time a thread migrates between
> > processors, and we decide we need a semaphore instead of a mutex as
> > a primitive in order to handle sleeps and wakeups that occur with
> > a mutex with a recursion count greater than 0, for some ungodly
> > reason.
> 
> Now we're back practically to my original question.  Explain how a
> semaphore is going to solve anything here.  I don't think it will
> help one bit.  In virtually all cases which require sleeping and
> being woken up (whether via a condition variable or a semaphore), the
> basic scenario is the same.  Thread A is examining and/or modifying a
> shared data structure.  Now he wants to wait until thread B modifies
> the data structure and puts it into some desired state.  While A
> was examining/modifying the data structure, he necessarily held a
> mutex on it in order to get a consistent view.  Before he waits, he
> must release that mutex -- otherwise B won't be able to make the
> desired modifications.  This is true whether the waiting is done with
> a condition variable or with a semaphore.  It really doesn't make much
> difference which one you use.  The only difference is that when using
> a condition variable the "release mutex and wait" sequence must be
> atomic, because a condition variable doesn't "remember" a wakeup that
> happened when nobody was waiting yet.  A semaphore does remember it,
> so there is no need for atomicity with respect to releasing the mutex.
> That's a pretty minor difference, and it doesn't have anything to do
> with whether the mutexes are recursive or not.

No, it has to do with how long they are held.  If they are never
permitted to be held across recursive function calls -- or better,
across _ANY_ function calls -- then you can spin on the mutex,
instead of hoing to sleep.  So a mutex operation becomes:

	1)	Acquire mutex
	2)	Frob data protected by mutex
	3)	Release mutex

If someone else needs the same data, they do the same thing.

If you want to wait until a condition is true, then use a
condition variable, a semaphore, or something else you can wait
on in order to be signalled.

The idea that you should ever go to sleep waitind for a mutex
is antithetical to the very idea.

There are likewise, few real situation in which you require to
be able to hold two mutexes; these are degenerate cases, which
are badly coded.

Consider that I may have a vnode freelist protected by a mutex,
and a vnode protected by a mutex.  The perceived need to hold both
of these simultaneously to put something on the freelist is an
artifact of wrong-thinking: the pointer use to place a vnode on
a freelist are the property of the freelist mutex, not the vnode
mutex.

Even if you can make a case for this not being true (e.g. moving
a vnode from one list to another, using the same pointers in the
vnode to track state on both lists, which is really just an
acquire/remove/release/aquire/insert/release operation, where
you have a window between the removal and the reinsertion), it
can be handled by strictly controlling the order of operation on
mutex acquisition, and inverting the release order, and backing
off in case of conflict.


> If the mutex is recursively held, there is a problem in that some
> other code grabbed the mutex and expected it to protect the data
> structure from being changed underfoot.

Worst case, set an "IN_USE" flag on the data in a flags field to
bar reentry on a given data item.  Best case, fix the broken code.
The vnode locking code does this today (I'd argue that it's broken
code).


> Using a semaphore to do the
> waiting doesn't solve that problem, or even address it.

It does.  Semaphores can be held across a sleep (a wait).


					Terry Lambert
					terry@lambert.org
---
Any opinions in this posting are my own and not those of my present
or previous employers.


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200009260249.TAA08391>