cvs commit: src/share/man/man9 sleep.9

Robert Watson rwatson at FreeBSD.org
Wed Feb 28 08:41:14 UTC 2007


On Wed, 28 Feb 2007, Greg 'groggy' Lehey wrote:

>> If there are parts of the FreeBSD kernel that are abusing a sleep channel 
>> to create this situation, we should fix them.
>
> See the rest of the thread.  A "sleep channel" is a memory address. It's 
> usually in the kernel, so you're talking about a 30 bit address space on 
> ia32.  That's really not very many.

Again, this is like saying "You can't expect to find the right data at a 
pointer, as there are only 2^30 possible values and anyone could write to it". 
Anyone could, but when they do, it's considered a bug if it leads the program 
to behave incorrectly -- the pointer mechanism itself is working just fine 
when you write to the wrong pointer, though, as does the sleep/wakeup 
mechanism when you wakeup the wrong pointer.  The sleep/wakeup mechanism 
relies on memory ownership, just like reading from and writing to pointers, in 
order to prevent collisions during use.  Whether you allocate it on the stack, 
allocate it with malloc(9), or are delegated use of an address as part of a 
complex data structure, memory ownership is how you prevent unexpected 
simultaneous use of an address.  If there is unexpected simultaneous use of an 
address by the same or a different consumer, then that is a bug in the 
consumer, and not the producer of the API.

>> If not, the most that should be done in the FreeBSD manpage is to clearly 
>> explain how not to introduce such a bug in a programmer's own code.
>
> Until the advent of wakeup_one, this wasn't a bug.  wakeup works fine under 
> these circumstances.

wakeup_one works fine, as far as we know, under all circumstances.  The 
mistake is in re-using a memory address for more than one type of wakeup event 
at a time.  Per previous requests for correction, we can and should document 
the semantics that are provided and the pitfalls programmers fall into when 
not aware of those semantics, but let's not document those semantics as 
incorrect.

>> As far as I'm aware, nowhere else in our manpages do we provide advice for 
>> the lazy programmer who cannot be bothered figuring out whether his code is 
>> correct and who just wants an expedient hack in case it's not.
>
> Maybe you should be a little less combative and consider that the paradigms 
> have changed.  The whole idea of sleeping on memory addresses is an 
> expedient hack.  The fact that people usually choose different addresses 
> means that even wakeup_one seldom has problems. But most people aren't even 
> aware of the issue.  As I say, how would you address the status quo?

It's not an accident that people don't choose the same address arbitrarily, 
it's a design feature.  We don't just randomly start using random memory 
addresses for storage, and we also don't just start using random memory 
addreses for wakeup channels.  When a programmer creates a new wakeup event 
class, it is their responsibility to decide whether it is appropriate to reuse 
an exist memory address or structure field for it.  They do this by looking at 
whether the existing address/field semantics with respect to wakeup are 
identical or not.  If not, they add a new address.  This is why some data 
structures, such as sockets, have several variables used for wakeups: the 
semantics of the wakeups differ, and so the same one cannot be used. 
Likewise, changing arbitrary instances of wakeup() to wakeup_one(), or vice 
versa, should be done only after analyzing other users of the same channel to 
make sure that the behavior is compatible.

You'll notice that a few years ago, we added cv(9) to the repertoire of kernel 
synchronization primitives.  This primitive represents a semantic improvement 
on the sleep(9) primitives for several reasons:

(1) It ties the notion of of a sleep/wakeup channel to a specific initialized
     memory type in order to encourage correct use as part of an init / sleep /
     wakeup / destroy life cycle.

(2) It enforces use of a mutex with the condition variable, which in turn
     discourages incorrect use without a mutex.  I can't remember if we KASSERT
     that it's the same mutex every time, but we should. :-)

The main downside I'm aware of is that this involves allocating slightly more 
memory explicitly, but as you point out, this may well discourage bugs in 
consumers.  What you could do is replace the text you've added with a coherent 
description of the memory ownership model (per previous e-mails), and add a 
comment that the cv(9) interface is now preferred.  Mind you, exactly the same 
consumer bugs can occur, as it supports both cv_signal (wakeup_one) and 
cv_broadcast (wakeup) semantics, so as with the sleep(9) API, has to be done 
with the awareness that naive use can lead to unexpected results.

Robert N M Watson
Computer Laboratory
University of Cambridge


More information about the cvs-all mailing list