kern/81951: [patch] linux emulation: getpriority() returns incorrect value

Bruce Evans bde at zeta.org.au
Thu Jun 9 13:20:07 GMT 2005


The following reply was made to PR kern/81951; it has been noted by GNATS.

From: Bruce Evans <bde at zeta.org.au>
To: Andriy Gapon <avg at icyb.net.ua>
Cc: freebsd-gnats-submit at freebsd.org, freebsd-emulation at freebsd.org
Subject: Re: kern/81951: [patch] linux emulation: getpriority() returns
 incorrect value
Date: Thu, 9 Jun 2005 23:17:44 +1000 (EST)

 > on 08.06.2005 23:49 Maxim Sobolev said the following:
 > > Committed, thanks!
 > >
 > > I wonder if the setpriority(2) needs the same cure. Please clarify and
 > > let me know. I'll keep the PR open till your reply.
 
 I wonder why committers commit patches without fully understanding them.
 
 > setpriority(2) is not affected, the reason for this assymetry is in
 > Linux's convention for system calls - they return both result and errno
 > in the same register, positive values are reserved for results of
 > successful calls and negative are reserved for -errno for failed calls.
 > Thus they can not return negative priority values in getpriority(2) and
 > have to shift it to positive range. There is no problem, of course, with
 > passing negative values from userland to kernel.
 
 Returning -1 for an error is the usual convention for syscalls and is
 specified by POSIX for getpriority().  The problem is that FreeBSD's
 getpriority() is highly non-POSIX-conformant (it has an off-by 20 error and
 wrong semantics for NZERO, and an off-by 1 error), so it can't be mapped
 to an emulator's getpriority() using the identity map except in rare cases
 where the emulator's getpriority() is bug for bug compatible.  But Linux's
 getpriority() seems to be highly non-POSIX-conformant in a different, less
 fundamentally broken way.
 
 POSIX specifies that the non-error range of values returned by getpriority()
 is [0, 2*{NZERO}-1]; -1 is the error indicator.  Applications must subtract
 NZERO to get the actual priority value.
 
 High non-POSIX-conformance:
 FreeBSD:
 NZERO is 0, so this range is null, and the actual range is [PRIO_MIN,
 PRIO_MAX] = [-20, 20]; priority -1 collides with the error indicator
 (the complications to handle this are documented in getpriority(3)).
 NZERO is not mentioned in getpriority(3).
 
 Linux:
 NZERO is 20, so the POSIX range is [0, 39] which is usable, but the
 actual range is apparently [1, 40]; the error indicator works normally.
 Appalications must apparently negate the priority and add 20 to get
 the actual priority (20 - pri) instead of (pri - NZERO).
 
 I think the reason that setpriority(2) is not affected is actually that
 Linux applications know to use (20 - pri) to recover the actual priority.
 
 Fixing getpriority() in FreeBSD and all emulators should involve much the
 same code: map the range of internal priorities [PRIO_MIN, PRIO_MAX] to
 getpriority()'s range [0, 2*{SUBSYSTEM_SPECIFIC_NZERO}-1] as linearly
 as possible (something like:
 
      pri |-> (pri - PRIO_MIN) * (2 * SUBSYSTEM_SPECIFIC_NZERO - 1) /
  	    (PRIO_MAX - PRIO_MIN)
 
 but more complicated, since for if SUBSYSTEM_SPECIFIC_NZERO == 20 the
 above maps the default priority 0 to (20 * 39 / 2) = 19, but 20 is
 required; also for Linux there must be a negation.
 
 Bruce


More information about the freebsd-emulation mailing list