sortix-mirror/kernel/resource.cpp

195 lines
5.7 KiB
C++
Raw Normal View History

2013-08-30 15:35:30 +00:00
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Sortix. If not, see <http://www.gnu.org/licenses/>.
resource.cpp
Resource limits and operations.
*******************************************************************************/
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <sortix/resource.h>
2013-08-30 21:55:09 +00:00
#include <sortix/kernel/copy.h>
2013-08-30 15:35:30 +00:00
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/syscall.h>
#include "resource.h"
namespace Sortix {
namespace Resource {
static int GetProcessPriority(pid_t who)
{
if ( who < 0 )
return errno = EINVAL, -1;
// TODO: If who isn't the current process, then it could self-destruct at
// any time while we use it; there is no safe way to do this yet.
Process* process = who ? Process::Get(who) : CurrentProcess();
if ( !process )
return errno = ESRCH, -1;
ScopedLock lock(&process->nicelock);
return process->nice;
}
static int SetProcessPriority(pid_t who, int prio)
{
if ( who < 0 )
return errno = EINVAL, -1;
// TODO: If who isn't the current process, then it could self-destruct at
// any time while we use it; there is no safe way to do this yet.
Process* process = who ? Process::Get(who) : CurrentProcess();
if ( !process )
return errno = ESRCH, -1;
ScopedLock lock(&process->nicelock);
process->nice = prio;
return 0;
}
static Process* CurrentProcessGroup()
{
Process* process = CurrentProcess();
ScopedLock lock(&process->groupchildlock);
// TODO: The process group can change when this call returns, additionally
// the current process leader could self-destruct.
return process->group;
}
static int GetProcessGroupPriority(pid_t who)
{
if ( who < 0 )
return errno = EINVAL, -1;
// TODO: If who isn't the current process, then it could self-destruct at
// any time while we use it; there is no safe way to do this yet.
Process* group = who ? Process::Get(who) : CurrentProcessGroup();
if ( !group )
return errno = ESRCH, -1;
int lowest = INT_MAX;
ScopedLock group_parent_lock(&group->groupparentlock);
for ( Process* process = group->groupfirst; process; process = process->groupnext )
{
ScopedLock lock(&process->nicelock);
if ( process->nice < lowest )
lowest = process->nice;
}
return lowest;
}
static int SetProcessGroupPriority(pid_t who, int prio)
{
if ( who < 0 )
return errno = EINVAL, -1;
// TODO: If who isn't the current process, then it could self-destruct at
// any time while we use it; there is no safe way to do this yet.
Process* group = who ? Process::Get(who) : CurrentProcessGroup();
if ( !group )
return errno = ESRCH, -1;
ScopedLock group_parent_lock(&group->groupparentlock);
for ( Process* process = group->groupfirst; process; process = process->groupnext )
{
ScopedLock lock(&process->nicelock);
process->nice = prio;
}
return 0;
}
static int GetUserPriority(uid_t /*who*/)
{
// TODO: There is currently no easy way to iterate all processes without
// dire race conditions being possible.
return errno = ENOSYS, -1;
}
static int SetUserPriority(uid_t /*who*/, int /*prio*/)
{
// TODO: There is currently no easy way to iterate all processes without
// dire race conditions being possible.
return errno = ENOSYS, -1;
}
static int sys_getpriority(int which, id_t who)
{
switch ( which )
{
case PRIO_PROCESS: return GetProcessPriority(who);
case PRIO_PGRP: return GetProcessGroupPriority(who);
case PRIO_USER: return GetUserPriority(who);
default: return errno = EINVAL, -1;
}
}
static int sys_setpriority(int which, id_t who, int prio)
{
switch ( which )
{
case PRIO_PROCESS: return SetProcessPriority(who, prio);
case PRIO_PGRP: return SetProcessGroupPriority(who, prio);
case PRIO_USER: return SetUserPriority(who, prio);
default: return errno = EINVAL, -1;
}
}
2013-08-30 21:55:09 +00:00
static
int sys_prlimit(pid_t pid,
int resource,
const struct rlimit* user_new_limit,
struct rlimit* user_old_limit)
{
if ( pid < 0 )
return errno = EINVAL, -1;
if ( resource < 0 || RLIMIT_NUM_DECLARED <= resource )
return errno = EINVAL, -1;
// TODO: If pid isn't the current process, then it could self-destruct at
// any time while we use it; there is no safe way to do this yet.
Process* process = pid ? Process::Get(pid) : CurrentProcess();
if ( !process )
return errno = ESRCH, -1;
ScopedLock lock(&process->resource_limits_lock);
struct rlimit* limit = &process->resource_limits[resource];
if ( user_old_limit )
{
if ( !CopyToUser(user_old_limit, limit, sizeof(struct rlimit)) )
return -1;
}
if ( user_new_limit )
{
struct rlimit new_limit;
if ( !CopyFromUser(&new_limit, user_new_limit, sizeof(struct rlimit)) )
return -1;
if ( new_limit.rlim_max < new_limit.rlim_cur )
return errno = EINVAL, -1;
*limit = new_limit;
}
return 0;
}
2013-08-30 15:35:30 +00:00
void Init()
{
Syscall::Register(SYSCALL_GETPRIORITY, (void*) sys_getpriority);
2013-08-30 21:55:09 +00:00
Syscall::Register(SYSCALL_PRLIMIT, (void*) sys_prlimit);
2013-08-30 15:35:30 +00:00
Syscall::Register(SYSCALL_SETPRIORITY, (void*) sys_setpriority);
}
} // namespace Resource
} // namespace Sortix