cvs commit: src/sys/kern sched_ule.c
bde at zeta.org.au
Sat Mar 17 20:44:30 UTC 2007
On Sat, 17 Mar 2007, Jeff Roberson wrote:
> Any language lawyers care to comment on this?
Don't all C programmers know this? :)
> On Sat, 17 Mar 2007, Jeff Roberson wrote:
>> jeff 2007-03-17 18:13:33 UTC
>> FreeBSD src repository
>> Modified files:
>> sys/kern sched_ule.c
>> - Cast the intermediate value in priority computtion back down to
>> unsigned char. Weirdly, casting the 1 constant to u_char still
>> a signed integer result that is then used in the % computation. This
>> avoids that mess all together and causes a 0 pri to turn into 255 % 64
>> as we expect.
- tdq_ridx has the dubious type u_char. This may be good for saving space,
but using unsigned types tends to give sign extension problems, and using
types smaller than ints tends to waste time.
- pri = tdq->tdq_ridx also has type u_char. Good -- otherwise you have to
be concerned about conversions.
- the expression (pri - 1) has the int thanks to C90's broken value-preserving
unsign extensions. In any binary expression, both types get promoted to
a common type that is at least as wide as int for integer expressions.
(Surely C programmers know this?) Broken value-preserving extension gives
a common type of int. Value pri = 0 is preserved. Then subtraction gives
the unwanted value of -1. Sign-preserving extension would give a common
type of u_int; value pri = 0 would be preserved, and subtraction of 1 would
give a value of UINT_MAX.
- there should still have been no problem in the (previous) semi-final
expression `(pri - 1) % RQ_NQS' since RQ_NQS is power of 2. -1
should equal UINT_MAX mod any power of 2 (> 2). It actually gives
-1 due to older C brokenness. Before C99, the value of integer
division and remainder on a negative numerator (assume a positive
denominator for simplicity) was implementation defined. Division
may be rounded either towards zero or towards minus infinity. The
correct rounding is towards minus infinity so that the remainder is
always between 0 and the numerator (>= 0, < numerator). Most
implementations follow the hardware and most hardware of course gets
this wrong (*). Thus -1 % 64 normally gives -1. C99 "fixed" this by
requiring incorrect rounding in all cases. This -1 % 64 always gives
(*) Rounding towards -infinity may be simplest for the hardware. However,
it is more complicated for software implementations of remainder by a
power of 2. gcc has to generate extra code to give the unwanted result
for `(pri - 1) % RQ_NQS'. It can't just AND (pri -1) with 0x3F, but has
to do a sign test and adjust the result if (pri - 1 < 0).
More information about the cvs-src