cvs commit: src/sys/kern sched_ule.c

Bruce Evans 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
>>  Log:
>>   - Cast the intermediate value in priority computtion back down to
>>     unsigned char.  Weirdly, casting the 1 constant to u_char still 
>> produces
>>     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
   -1.

(*) 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).

Bruce


More information about the cvs-src mailing list