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

Bruce Evans bde at zeta.org.au
Thu Jun 9 13:17:47 GMT 2005


> 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