#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
#include "pthread_private.h"
#include <errno.h>
#include <sys/resource.h>
#include <OS.h>
#include <sys/param.h>
#include <syscall_utils.h>
#ifdef CLIP
#undef CLIP
#endif
#define CLIP(n, max, min) MAX(MIN((n), (max)), (min))
#define NMAX 0
#define NMIN (NZERO * 2 - 1)
#define CLIP_TO_UNIX(n) CLIP(n, NMIN, NMAX)
#define BZERO B_NORMAL_PRIORITY
#define BMAX (B_REAL_TIME_DISPLAY_PRIORITY - 1)
#define BMIN 1
#define CLIP_TO_BEOS(n) CLIP(n, BMAX, BMIN)
static int32
prio_be_to_unix(int32 prio)
{
int out;
if (prio >= BZERO)
out = NZERO
- ((prio - BZERO) * NZERO + (BMAX - BZERO) / 2) / (BMAX - BZERO);
else
out = NZERO
+ ((BZERO - prio) * (NZERO - 1)) / (BZERO - BMIN)
+ 1;
return CLIP_TO_UNIX(out);
}
static int32
prio_unix_to_be(int32 prio)
{
int out;
if (prio >= NZERO)
out = BZERO - ((prio - NZERO) * (BZERO - BMIN)) / (NZERO - 1);
else
out = BZERO + ((NZERO - prio) * (BMAX - BZERO)) / (NZERO);
return CLIP_TO_BEOS(out);
}
int
getpriority(int which, id_t who)
{
bool found = false;
int out = -100;
if (who < 0)
RETURN_AND_SET_ERRNO(EINVAL);
switch (which) {
case PRIO_PROCESS:
{
int32 th_cookie = 0;
thread_info thread;
while (get_next_thread_info(who, &th_cookie, &thread) == B_OK) {
if (thread.priority > out) {
found = true;
out = thread.priority;
}
}
break;
}
case PRIO_PGRP:
{
int32 team_cookie = 0, th_cookie = 0;
team_info team;
thread_info thread;
who = who == 0 ? getpgrp() : who;
while (get_next_team_info(&team_cookie, &team) == B_OK) {
if (getpgid(team.team) != who)
continue;
th_cookie = 0;
while (get_next_thread_info(team.team, &th_cookie, &thread)
== B_OK) {
if (thread.priority > out) {
found = true;
out = thread.priority;
}
}
}
break;
}
case PRIO_USER:
{
uid_t euid = who == 0 ? geteuid() : (uid_t)who;
int32 team_cookie = 0, th_cookie = 0;
team_info team;
thread_info thread;
while (get_next_team_info(&team_cookie, &team) == B_OK) {
if (team.uid != euid)
continue;
th_cookie = 0;
while (get_next_thread_info(team.team, &th_cookie, &thread)
== B_OK) {
if (thread.priority > out) {
found = true;
out = thread.priority;
}
}
}
break;
}
default:
RETURN_AND_SET_ERRNO(EINVAL);
}
if (!found)
RETURN_AND_SET_ERRNO(ESRCH);
return prio_be_to_unix(out) - NZERO;
}
int
setpriority(int which, id_t who, int value)
{
int32 th_cookie = 0;
thread_info thread;
if (who != 0 && which != PRIO_PROCESS)
RETURN_AND_SET_ERRNO(EINVAL);
value = value > NMIN ? NMIN : CLIP_TO_UNIX(value + NZERO);
value = prio_unix_to_be(value);
__pthread_set_default_priority(value);
while (get_next_thread_info(B_CURRENT_TEAM, &th_cookie, &thread) == B_OK)
set_thread_priority(thread.thread, value);
return 0;
}