Date: Thu, 9 Jun 2005 13:20:06 GMT From: Bruce Evans <bde@zeta.org.au> To: freebsd-emulation@FreeBSD.org Subject: Re: kern/81951: [patch] linux emulation: getpriority() returns incorrect value Message-ID: <200506091320.j59DK6s5095303@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/81951; it has been noted by GNATS. From: Bruce Evans <bde@zeta.org.au> To: Andriy Gapon <avg@icyb.net.ua> Cc: freebsd-gnats-submit@freebsd.org, freebsd-emulation@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200506091320.j59DK6s5095303>