Well, I've failed in my main objective (to deuglify the shutdown messages),
but an interesting debate has resulted instead, so I can't feel too bad.
I did a little research to support my position on sleep/wakeup, and here's
the best I have. This is pretty long, and unlikely to shake your world view,
so those of you with drooping eyelids can just head over to slashdot, or
Some pseudo code from "The Design of the Unix Operating System", by Maurice
Bach, page 33 shows how sleep() is used:
while (condition is true)
sleep (event: the condition becomes false);
set condition true;
and the next page shows how wakeup() is used:
set condition false;
wakeup (event: the condition is false);
In the description, it says `Thus, the "while-sleep" loop insures that at most
one process can gain access to a resource.'
Not the most convincing evidence, but on the other hand, he does not mention
the idea of *not* protecting against sudden wakeup.
>From "Writing a Unix Device Driver", by Egan and Teixeira, on page 92 we find
It is not uncommon for several processes to sleep on the same
channel. They may be competing for the same resource, or they
may be waiting for different reasons that have been associated
with the same channel value. In this situation a single wakeup
call on the common channel will cause all the sleeping processes
to become executable; ... A driver routine must not assume that
it can proceed after a return from a sleep call. It should check
to see whether the event it was waiting for has actually occurred;
if it has not it should sleep again, and repeat this cycle until
the awaited event has actually occurred.
The book is oriented rather towards I/O, so perhaps not all possible uses
of routines are covered. But again, no mention of *not* using a while loop.
Quite the opposite.
Also "Magic Garden Explained" points out that you really want to sleep on
an "event", but all you have is the address of some data. So, you often
have multiple semantically different events represented by the same integer
wakeup channel. A good reason to program defensively, I think.
But the best evidence is from kern_synch.c from 4.2 BSD, line 98, in the
header comment of the sleep() routine:
* Callers of this routine must be prepared for
* premature return, and check that the reason for
* sleeping has gone away.
That comment on sleep() is present from 4.0 BSD up to and including 4.3 tahoe,
but disappears in 4.3 reno, when the 4.4 style tsleep() was introduced. After
a bit of searching through the PUPS archive, I see it is even present in
Edition 6, character for character, in a file called slp.c.
Well, I knew I wasn't a senile old fart yet, and Kirk's BSD CD compendium
and the PUPS archive show that I remember some things correctly still. For
a considerable portion of Unix history, sleep() could return for no good reason
at all, and was documented to do so (if only in the source code).
Now, how does this relate to the current day? Nobody in the BSD world uses
plain sleep() any more. Once tsleep() appeared, the rules seem to have changed.
Perhaps some people had gotten away with ignoring the dire warnings in the
sleep() code, and decided that unexpected wakeups weren't such a useful part
of the API. I hope Kirk or other BSD veterans can be coaxed into offering
an opinion. I'd offer at least one beer for this purpose. :-)
Regardless of the history of it all, FreeBSD is full of places where
unexpected wakeups can stuff you right up. Should we regard tsleep() like
the older sleep() call, as suspect, and program defensively? Should we
be pragmatic, admit "We've gotten away with it so far", and document the
"no sudden wakeups" behaviour?
I quite like the general principle outlined in one of the earlier replies,
that a while loop can be shown to be correct through a local code reading,
but a simple conditional must be verified by reading all the rest of the
code. That's close to the same argument I use against global variables.
Their use is too hard to verify as correct. In short, I'd like to see
all cases where tsleep() is not carefully used in a loop repaired.
Practically speaking, though, I can't see that happening, especially if
we have any major players against the idea (DG for example). Given that,
I'd like as a minimum a bit more of the history of sleep() in the tsleep()
manual page, and a discussion of when a while-loop protected tsleep() is
mandatory, and when it is optional. Some sort of pronouncement against
issuing wakeup() calls against arbitrary addresses would help too.
I would do that right now, except I'm escaping computing for a few months.
Almost heresy nowadays, I suppose. And I won't be the first in line for
a brain implanted net connection either. ;-)
PS By the time you read this, I've probably unsubscribed to everything.
Please CC me in any replies. I'll read mail when I get a chance.
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message