svn commit: r227749 - head/sys/kern
Bruce Evans
brde at optusnet.com.au
Mon Nov 21 03:37:13 UTC 2011
On Sun, 20 Nov 2011, Warner Losh wrote:
> Is this right? Passing 0 to timo causes a panic? That can't be good.
Because it reverses the natural order of conversations.
> On Nov 20, 2011, at 1:36 AM, Hans Petter Selasky wrote:
>> Log:
>> Given that the typical usage of pause() is pause("zzz", hz / N), where N can
>> be greater than hz in some cases, simply ignore a timeout value of zero.
>>
>> Suggested by: Bruce Evans
>> MFC after: 1 week
>>
>> Modified:
>> head/sys/kern/kern_synch.c
>>
>> Modified: head/sys/kern/kern_synch.c
>> ==============================================================================
>> --- head/sys/kern/kern_synch.c Sun Nov 20 08:29:23 2011 (r227748)
>> +++ head/sys/kern/kern_synch.c Sun Nov 20 08:36:18 2011 (r227749)
>> @@ -333,7 +333,7 @@ msleep_spin(void *ident, struct mtx *mtx
>> int
>> pause(const char *wmesg, int timo)
>> {
>> - KASSERT(timo > 0, ("pause: timo must be > 0"));
>> + KASSERT(timo >= 0, ("pause: timo must be >= 0"));
>>
>> /* silently convert invalid timeouts */
>> if (timo < 1)
I tried to get Hans to remove the KASSERT() and its panic in one of my
many reviews of changes to usb_pause() and pause(), but got confused in
my review of this commit. I said that this commit restores the old
KASSERT() which gives panics for a timeout of 0, but it actually
completes changing the KASSERT() so that it doesn't give panics in this
case. I got confused because the comments and the code are inconsistent
in different ways than before (and KASSERT() has its usual negative
logic complications):
- a previous comment says, verbosely, that "the timeout must be greater
than zero"
- the previous KASSERT() requires, consisely, that "timo must be > 0".
This was consistent with the comment. The new KASSERT() is inconsistent
with the comment.
- the "silently convert invalid timeouts" code, which was added on my
request in the previous commit, was unreachable in all cases that it
handles when INVARIANTS is configured. Now it is reachable for timeouts
of 0. It remains unreachable for timeouts of < 0. The verbose previous
comment is not as verbose as this mail, so it doesn't describe all the
cases.
timo isn't a function, so 0 can't be passed to it. Passing a timeout of
0 to various functions has various behaviours:
- passing a timeout of 0 to msleep() is supported and means no timeout
(= a timeout of infinity). (Negative timeouts don't seem to be
properly handled by msleep(). They are neither rejected not silently
fixed up, but are passed on.)
- passing a timeout of 0 (or < 0) to callout_reset() makes no sense,
but is not considered harmful enough the panic on. It was silently
fixed up to be a timeout of 1.
- passing a timeout of 0 (or < 0) to pause() makes no sense, but was
considered to be harmful enough to panic on for a timeout of 0, while
negative timeouts were just passed on.
(pause()'s main comment says that it is like tsleep(), but it is
really like DELAY(). Thus its timeout isn't really a (maximum)
timeout, but is a (minimum) DELAY(). Another minor problem with
the API or documentation is that it isn't clear if the caller is
responsible for handling the implementation detail that pause(msg,
1) only delays for a fractional tick iff it is implemented using
tsleep(); the caller must ask for a "timeout" of of 2 if it wants
a delay of strictly >= 1 tick. Returning early is OK for a
maximum timeout but not for a minimum delay. Non-hardware callers
probably don't care about getting a minimum, but usb callers do.
usb_pause() has always adds 1 tick to handle this and rounding
errors.)
After Hans' first change, negative timeouts were considered harmful
enough to panic on too. I thought that this was silly, since pause()
is unimportant compared with callout_reset() -- who cares if it is
passed an invalid timeout? -- and asked him to change to the silent
fixup used by callout_reset(). This is now done for timeouts of 0,
but not for timeouts of < 0 in the INVARIANTS case (since the KASSERT()
is still there for them). Checking for timeouts of < 0 in pause() is
getting close to checking for parity errors in the CPU in pause().
msleep() is much more important, but never did either.
pause() grew some additional complications that I don't like. Hans
noticed that DELAY(n) overflows for large n on arm. So pause() now
avoids passing large n to DELAY(). Probably no other callers of
DELAY() do this, and no callers of pause() need large n for DELAY().
Why is top posting considered harmful?
Bruce
More information about the svn-src-all
mailing list