ish/kernel/resource.c
2018-01-15 19:18:38 -08:00

106 lines
2.8 KiB
C

#if __linux__
// pull in RUSAGE_THREAD
#define _GNU_SOURCE
#include <sys/resource.h>
#elif __APPLE__
// pull in thread_info and friends
#include <mach/mach.h>
#else
#error
#endif
#include "kernel/calls.h"
rlim_t_ rlimit(int resource) {
return current->limits[resource].cur;
}
dword_t sys_getrlimit(dword_t resource, addr_t rlim_addr) {
struct rlimit_ rlimit = current->limits[resource];
if (user_put(rlim_addr, rlimit))
return _EFAULT;
return 0;
}
dword_t sys_setrlimit(dword_t resource, addr_t rlim_addr) {
struct rlimit_ rlimit;
if (user_get(rlim_addr, rlimit))
return _EFAULT;
// TODO check permissions
current->limits[resource] = rlimit;
return 0;
}
dword_t sys_prlimit(pid_t_ pid, dword_t resource, addr_t new_limit_addr, addr_t old_limit_addr) {
if (pid != 0)
return _EINVAL;
int err = 0;
if (old_limit_addr != 0) {
err = sys_getrlimit(resource, old_limit_addr);
if (err < 0)
return err;
}
if (new_limit_addr != 0) {
err = sys_setrlimit(resource, new_limit_addr);
if (err < 0)
return err;
}
return 0;
}
struct rusage_ rusage_get_current() {
// only the time fields are currently implemented
struct rusage_ rusage;
#if __linux__
struct rusage usage;
int err = getrusage(RUSAGE_THREAD, &usage);
assert(err == 0);
rusage.utime.sec = usage.ru_utime.tv_sec;
rusage.utime.usec = usage.ru_utime.tv_usec;
rusage.stime.sec = usage.ru_stime.tv_sec;
rusage.stime.usec = usage.ru_stime.tv_usec;
#elif __APPLE__
thread_basic_info_data_t info;
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
int err = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t) &info, &count);
rusage.utime.sec = info.user_time.seconds;
rusage.utime.usec = info.user_time.microseconds;
rusage.stime.sec = info.system_time.seconds;
rusage.stime.usec = info.system_time.microseconds;
#endif
return rusage;
}
static void timeval_add(struct timeval_ *dst, struct timeval_ *src) {
dst->sec += src->sec;
dst->usec += src->usec;
if (dst->usec >= 1000000) {
dst->usec -= 1000000;
dst->sec++;
}
}
void rusage_add(struct rusage_ *dst, struct rusage_ *src) {
timeval_add(&dst->utime, &src->utime);
timeval_add(&dst->stime, &src->stime);
}
dword_t sys_getrusage(dword_t who, addr_t rusage_addr) {
struct rusage_ rusage;
switch (who) {
case RUSAGE_SELF_:
rusage = rusage_get_current();
break;
case RUSAGE_CHILDREN_:
lock(&current->exit_lock);
rusage = current->children_rusage;
unlock(&current->exit_lock);
break;
default:
return _EINVAL;
}
if (user_put(rusage_addr, rusage))
return _EFAULT;
return 0;
}