Ticket #2817: 0001-libroot-add-gs-etpriority-implementation.patch

File 0001-libroot-add-gs-etpriority-implementation.patch, 8.6 KB (added by Timothy_Gu, 9 years ago)

Patch from #11755.

  • headers/posix/sys/resource.h

    From 8413d0231e71be66b28984e1052a68de3d067fa1 Mon Sep 17 00:00:00 2001
    From: Timothy Gu <timothygu99@gmail.com>
    Date: Sat, 10 Jan 2015 20:17:09 -0800
    Subject: [PATCH] libroot: add [gs]etpriority implementation
    
    Implemented against POSIX-1.2013.
    
    It is possible to have small precision errors when converting from Unix-
    style thread priority to Be-style. For example, the following program
    outputs "17" instead of the expected "18":
    
    	#include <stdio.h>
    	#include <sys/resource.h>
    
    	int
    	main()
    	{
    		setpriority(PRIO_PROCESS, 0, 18);
    		printf("%d\n", getpriority(PRIO_PROCESS, 0));
    		return 0;
    	}
    
    The underlying reason is because when you setpriority() both 18 and 19
    are converted to the Be-style "2". This problem should not happen with
    priority levels lower than or equal to 20, when the Be notation is more
    precise than the Unix-style.
    
    Done as a part of GCI 2014. Fixes #2817.
    
    Signed-off-by: Timothy Gu <timothygu99@gmail.com>
    ---
     headers/posix/sys/resource.h            |   5 +-
     src/apps/aboutsystem/Credits.h          |   1 +
     src/system/libroot/posix/sys/Jamfile    |   1 +
     src/system/libroot/posix/sys/priority.c | 228 ++++++++++++++++++++++++++++++++
     4 files changed, 232 insertions(+), 3 deletions(-)
     create mode 100644 src/system/libroot/posix/sys/priority.c
    
    diff --git a/headers/posix/sys/resource.h b/headers/posix/sys/resource.h
    index 96ac924..c27cfda 100644
    a b extern int getrusage(int who, struct rusage *rusage);  
    6464extern int getrlimit(int resource, struct rlimit * rlp);
    6565extern int setrlimit(int resource, const struct rlimit * rlp);
    6666
    67 /* ToDo: The following POSIX calls are missing (in BeOS as well):
    68  * int getpriority(int which, id_t who);
    69  * int setpriority(int which, id_t who, int priority); */
     67extern int getpriority(int which, id_t who);
     68extern int setpriority(int which, id_t who, int priority);
    7069
    7170__END_DECLS
    7271
  • src/apps/aboutsystem/Credits.h

    diff --git a/src/apps/aboutsystem/Credits.h b/src/apps/aboutsystem/Credits.h
    index 2ee165c..ed1eed5 100644
    a b static const Translation kTranslations[] = {  
    416416    "Deyan Genovski\n" \
    417417    "Pete Goodeve\n" \
    418418    "Lucian Adrian Grijincu\n" \
     419    "Tiancheng \"Timothy\" Gu\n" \
    419420    "Sean Healy\n" \
    420421    "Andreas Henriksson\n" \
    421422    "Matthijs Hollemans\n" \
  • src/system/libroot/posix/sys/Jamfile

    diff --git a/src/system/libroot/posix/sys/Jamfile b/src/system/libroot/posix/sys/Jamfile
    index c4f9a29..d7f4bea 100644
    a b for architectureObject in [ MultiArchSubDirSetup ] {  
    2121            mkfifo.c
    2222            mknod.c
    2323            mman.cpp
     24            priority.c
    2425            rlimit.c
    2526            select.c
    2627            stat.c
  • new file src/system/libroot/posix/sys/priority.c

    diff --git a/src/system/libroot/posix/sys/priority.c b/src/system/libroot/posix/sys/priority.c
    new file mode 100644
    index 0000000..faa019d
    - +  
     1/*
     2 * Copyright 2015 Tiancheng "Timothy" Gu, timothygu99@gmail.com
     3 * Copyright 2001-2002 François Revol (mmu_man)
     4 * All rights reserved. Distributed under the terms of the MIT License.
     5 */
     6
     7#include <errno.h>
     8#include <sys/resource.h>
     9
     10#include <OS.h>
     11#include <sys/param.h> // for MAX() and MIN() macros
     12
     13// Part of this file is adapted from src/bin/renice.c, by François Revol.
     14
     15// Some notes on different priority notations:
     16//
     17// Notation system          | Real-time | High Prio | Default | Low Prio |
     18// -------------------------|----------:|----------:|--------:|---------:|
     19// BeOS/Haiku               |      120* |        99 |      10 |      1** |
     20// UNIX [gs]etpriority()*** |      N.A. |       -20 |       0 |       19 |
     21// UNIX internal            |      N.A. |         0 |      20 |       39 |
     22//
     23// *    Note that BeOS/Haiku does not have an absolute highest priority value
     24//      (else than the maximum of int32), and (B_REAL_TIME_PRIORITY - 1) is
     25//      the highest non-real-time priority and usually used as the priority
     26//      limit. On UNIX systems there is no such concept as "real-time."
     27// **   0 only for idle_thread
     28// ***  Also used for UNIX nice(1) and nice(3)
     29
     30#ifdef CLIP
     31#undef CLIP
     32#endif
     33#define CLIP(n, max, min) MAX(MIN((n), (max)), (min))
     34
     35// In these contexts, "min" does not mean "lowest value," but "lowest
     36// priority," which is the maximum value in UNIX priority notation.
     37// "Zero" means normal priority, which in UNIX function notation is 0.
     38// POSIX specification also refers to it as "NZERO."
     39#ifndef NZERO
     40#define NZERO 20
     41#endif
     42#define NMAX 0
     43#define NMIN (NZERO * 2 - 1)
     44#define CLIP_TO_UNIX(n) CLIP(n, NMIN, NMAX)
     45
     46#define BZERO B_NORMAL_PRIORITY
     47#define BMAX (B_REAL_TIME_DISPLAY_PRIORITY - 1)
     48#define BMIN 1
     49#define CLIP_TO_BEOS(n) CLIP(n, BMAX, BMIN)
     50
     51// To accurately convert the notation values, we need to use an exponential
     52// function:
     53//
     54//  f(x) = 99e^(-0.116x)
     55//
     56// where f() represents the BeOS priority value, and x represents the Unix
     57// priority value.
     58//
     59// But that's too complicated. And slow. So we use a simple piecewise linear
     60// approach here, by a simple rescaling of the values.
     61
     62// returns an equivalent UNIX priority for a given BeOS priority.
     63static int32
     64prio_be_to_unix(int32 prio)
     65{
     66    int out;
     67    if (prio >= BZERO)
     68        out = NZERO
     69            - ((prio - BZERO) * NZERO + (BMAX - BZERO) / 2) / (BMAX - BZERO);
     70            // `(BMAX - BZERO) / 2` for rounding
     71    else
     72        out = NZERO
     73            + ((BZERO - prio) * (NZERO - 1)) / (BZERO - BMIN)
     74            + 1;
     75            // `+1` for rounding
     76    return CLIP_TO_UNIX(out);
     77}
     78
     79
     80// returns an equivalent BeOS priority for a given UNIX priority.
     81static int32
     82prio_unix_to_be(int32 prio)
     83{
     84    int out;
     85    // Do not need to care about rounding
     86    if (prio >= NZERO)
     87        out = BZERO - ((prio - NZERO) * (BZERO - BMIN)) / (NZERO - 1);
     88    else
     89        out = BZERO + ((NZERO - prio) * (BMAX - BZERO)) / (NZERO);
     90    return CLIP_TO_BEOS(out);
     91}
     92
     93
     94int
     95getpriority(int which, id_t who) {
     96    team_info team;
     97    thread_info thread;
     98    int32 team_cookie = 0, th_cookie = 0;
     99    int out = -100;
     100    bool found = false;
     101
     102    if (who < 0) {
     103        errno = EINVAL;
     104        return -1;
     105    }
     106    switch (which) {
     107        // In Haiku process and process group are the same -- teams.
     108        case PRIO_PROCESS:
     109        case PRIO_PGRP:
     110        {
     111            status_t status;
     112            if (!who)
     113                who = getpid();
     114            status = get_team_info(who, &team);
     115            if (status == B_BAD_TEAM_ID) {
     116                errno = ESRCH;
     117                return -1;
     118            }
     119            while (get_next_thread_info(team.team, &th_cookie, &thread)
     120                == B_OK) {
     121                if (thread.priority > out) {
     122                    found = true;
     123                    out = thread.priority;
     124                }
     125            }
     126            break;
     127        }
     128        case PRIO_USER:
     129        {
     130            uid_t uid;
     131            // `who` (id_t) is int32, but uid_t is uint32, so using this
     132            // indirection to get rid of compiler warnings
     133            // `who` can never be negative because of the `who < 0` check
     134            // above.
     135            if (who)
     136                uid = who;
     137            else
     138                uid = geteuid();
     139            while (get_next_team_info(&team_cookie, &team) == B_OK) {
     140                if (team.uid != uid)
     141                    continue;
     142                th_cookie = 0;
     143                while (get_next_thread_info(team.team, &th_cookie, &thread)
     144                    == B_OK)
     145                    if (thread.priority > out) {
     146                        found = true;
     147                        out = thread.priority;
     148                    }
     149            }
     150            break;
     151        }
     152        default:
     153            errno = EINVAL;
     154            return -1;
     155    }
     156    if (!found) {
     157        errno = ESRCH;
     158        return -1;
     159    }
     160    return prio_be_to_unix(out) - NZERO;
     161}
     162
     163
     164int
     165setpriority(int which, id_t who, int value) {
     166    team_info team;
     167    thread_info thread;
     168    int32 team_cookie = 0, th_cookie = 0;
     169    bool found = false;
     170
     171    if (who < 0) {
     172        errno = EINVAL;
     173        return -1;
     174    }
     175    value = CLIP_TO_UNIX(value + NZERO);
     176    value = prio_unix_to_be(value);
     177
     178    switch (which) {
     179        // In Haiku process and process group are the same -- teams.
     180        case PRIO_PROCESS:
     181        case PRIO_PGRP:
     182        {
     183            status_t status;
     184            if (!who)
     185                who = getpid();
     186            status = get_team_info(who, &team);
     187            if (status == B_BAD_TEAM_ID) {
     188                errno = ESRCH;
     189                return -1;
     190            }
     191            while (get_next_thread_info(team.team, &th_cookie, &thread)
     192                == B_OK) {
     193                found = true;
     194                set_thread_priority(thread.thread, value);
     195            }
     196            break;
     197        }
     198        case PRIO_USER:
     199        {
     200            uid_t uid;
     201            // who (id_t) is signed, but uid_t is not, so have to use an
     202            // indirection like this
     203            if (who)
     204                uid = who;
     205            else
     206                uid = geteuid();
     207            while (get_next_team_info(&team_cookie, &team) == B_OK) {
     208                if (team.uid != uid)
     209                    continue;
     210                th_cookie = 0;
     211                while (get_next_thread_info(team.team, &th_cookie, &thread)
     212                    == B_OK) {
     213                    found = true;
     214                    set_thread_priority(thread.thread, value);
     215                }
     216            }
     217            break;
     218        }
     219        default:
     220            errno = EINVAL;
     221            return -1;
     222    }
     223    if (!found) {
     224        errno = ESRCH;
     225        return -1;
     226    }
     227    return 0;
     228}