From owner-freebsd-arch Mon Sep 25 19:50:21 2000 Delivered-To: freebsd-arch@freebsd.org Received: from smtp04.primenet.com (smtp04.primenet.com [206.165.6.134]) by hub.freebsd.org (Postfix) with ESMTP id 48E2C37B424 for ; Mon, 25 Sep 2000 19:50:12 -0700 (PDT) Received: (from daemon@localhost) by smtp04.primenet.com (8.9.3/8.9.3) id TAA15991; Mon, 25 Sep 2000 19:47:40 -0700 (MST) Received: from usr05.primenet.com(206.165.6.205) via SMTP by smtp04.primenet.com, id smtpdAAA3daybF; Mon Sep 25 19:47:29 2000 Received: (from tlambert@localhost) by usr05.primenet.com (8.8.5/8.8.5) id TAA08391; Mon, 25 Sep 2000 19:49:58 -0700 (MST) From: Terry Lambert Message-Id: <200009260249.TAA08391@usr05.primenet.com> Subject: Re: Mutexes and semaphores (was: cvs commit: src/sys/conf files To: arch@freebsd.org Date: Tue, 26 Sep 2000 02:49:58 +0000 (GMT) Cc: tlambert@primenet.com In-Reply-To: <200009260209.TAA03815@vashon.polstra.com> from "John Polstra" at Sep 25, 2000 07:09:28 PM X-Mailer: ELM [version 2.5 PL2] MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG > > 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