diff --git a/libc/Makefile b/libc/Makefile
index 38354c9e..7cba2125 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -309,6 +309,7 @@ sys/mman/mprotect.o \
sys/mman/munmap.o \
sys/readdirents/readdirents.o \
sys/resource/getpriority.o \
+sys/resource/prlimit.o \
sys/resource/setpriority.o \
sys/select/select.o \
sys/socket/accept4.o \
diff --git a/libc/include/sys/resource.h b/libc/include/sys/resource.h
index e14dc32e..d2502187 100644
--- a/libc/include/sys/resource.h
+++ b/libc/include/sys/resource.h
@@ -31,8 +31,10 @@
__BEGIN_DECLS
@include(id_t.h)
+@include(pid_t.h)
int getpriority(int, id_t);
+int prlimit(pid_t, int, const struct rlimit*, struct rlimit*);
int setpriority(int, id_t, int);
__END_DECLS
diff --git a/libc/sys/resource/prlimit.cpp b/libc/sys/resource/prlimit.cpp
new file mode 100644
index 00000000..30ec0b2c
--- /dev/null
+++ b/libc/sys/resource/prlimit.cpp
@@ -0,0 +1,41 @@
+/*******************************************************************************
+
+ Copyright(C) Jonas 'Sortie' Termansen 2013.
+
+ This file is part of the Sortix C Library.
+
+ The Sortix C Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or (at your
+ option) any later version.
+
+ The Sortix C Library 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 Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with the Sortix C Library. If not, see .
+
+ sys/resource/prlimit.cpp
+ Access and modify the resource limits of the given process.
+
+*******************************************************************************/
+
+#include
+#include
+
+DEFN_SYSCALL4(int, sys_prlimit, SYSCALL_PRLIMIT,
+ pid_t,
+ int,
+ const struct rlimit*,
+ struct rlimit*);
+
+extern "C"
+int prlimit(pid_t pid,
+ int resource,
+ const struct rlimit* new_limit,
+ struct rlimit* old_limit)
+{
+ return sys_prlimit(pid, resource, new_limit, old_limit);
+}
diff --git a/sortix/include/sortix/kernel/process.h b/sortix/include/sortix/kernel/process.h
index e8403d41..a38536dd 100644
--- a/sortix/include/sortix/kernel/process.h
+++ b/sortix/include/sortix/kernel/process.h
@@ -26,6 +26,7 @@
#define INCLUDE_SORTIX_KERNEL_PROCESS_H
#include
+#include
#include
#include
@@ -91,6 +92,10 @@ private:
Ref mtable;
Ref dtable;
+public:
+ kthread_mutex_t resource_limits_lock;
+ struct rlimit resource_limits[RLIMIT_NUM_DECLARED];
+
public:
void BootstrapTables(Ref dtable, Ref mtable);
void BootstrapDirectories(Ref root);
diff --git a/sortix/include/sortix/resource.h b/sortix/include/sortix/resource.h
index 9adc821f..b6556077 100644
--- a/sortix/include/sortix/resource.h
+++ b/sortix/include/sortix/resource.h
@@ -26,6 +26,7 @@
#define INCLUDE_SORTIX_RESOURCE_H
#include
+#include <__/stdint.h>
__BEGIN_DECLS
@@ -33,6 +34,31 @@ __BEGIN_DECLS
#define PRIO_PGRP 1
#define PRIO_USER 2
+typedef __uintmax_t rlim_t;
+
+#define RLIM_INFINITY __UINTMAX_MAX
+#define RLIM_SAVED_CUR RLIM_INFINITY
+#define RLIM_SAVED_MAX RLIM_INFINITY
+
+struct rlimit
+{
+ rlim_t rlim_cur;
+ rlim_t rlim_max;
+};
+
+#define RLIMIT_AS 0
+#define RLIMIT_CORE 1
+#define RLIMIT_CPU 2
+#define RLIMIT_DATA 3
+#define RLIMIT_FSIZE 4
+#define RLIMIT_NOFILE 5
+#define RLIMIT_STACK 6
+#define __RLIMIT_NUM_DECLARED 7 /* index of highest constant plus 1. */
+
+#if !__STDC_HOSTED__ && defined(SORTIX_KERNEL)
+#define RLIMIT_NUM_DECLARED __RLIMIT_NUM_DECLARED
+#endif
+
__END_DECLS
#endif
diff --git a/sortix/include/sortix/syscallnum.h b/sortix/include/sortix/syscallnum.h
index 3dbc5f07..2e27189e 100644
--- a/sortix/include/sortix/syscallnum.h
+++ b/sortix/include/sortix/syscallnum.h
@@ -142,6 +142,7 @@
#define SYSCALL_MUNMAP 118
#define SYSCALL_GETPRIORITY 119
#define SYSCALL_SETPRIORITY 120
-#define SYSCALL_MAX_NUM 121 /* index of highest constant + 1 */
+#define SYSCALL_PRLIMIT 121
+#define SYSCALL_MAX_NUM 122 /* index of highest constant + 1 */
#endif
diff --git a/sortix/process.cpp b/sortix/process.cpp
index 9106aba2..7965fb37 100644
--- a/sortix/process.cpp
+++ b/sortix/process.cpp
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -105,6 +106,12 @@ Process::Process()
umask = 0022;
nicelock = KTHREAD_MUTEX_INITIALIZER;
nice = 0;
+ resource_limits_lock = KTHREAD_MUTEX_INITIALIZER;
+ for ( size_t i = 0; i < RLIMIT_NUM_DECLARED; i++ )
+ {
+ resource_limits[i].rlim_cur = RLIM_INFINITY;
+ resource_limits[i].rlim_max = RLIM_INFINITY;
+ }
Time::InitializeProcessClocks(this);
alarm_timer.Attach(Time::GetClock(CLOCK_MONOTONIC));
Put(this);
@@ -649,6 +656,11 @@ Process* Process::Fork()
kthread_mutex_unlock(&groupchildlock);
// Initialize everything that is safe and can't fail.
+ kthread_mutex_lock(&resource_limits_lock);
+ for ( size_t i = 0; i < RLIMIT_NUM_DECLARED; i++ )
+ clone->resource_limits[i] = resource_limits[i];
+ kthread_mutex_unlock(&resource_limits_lock);
+
kthread_mutex_lock(&nicelock);
clone->nice = nice;
kthread_mutex_unlock(&nicelock);
diff --git a/sortix/resource.cpp b/sortix/resource.cpp
index 3b264032..08865936 100644
--- a/sortix/resource.cpp
+++ b/sortix/resource.cpp
@@ -29,6 +29,7 @@
#include
+#include
#include
#include
#include
@@ -148,9 +149,44 @@ static int sys_setpriority(int which, id_t who, int prio)
}
}
+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;
+}
+
void Init()
{
Syscall::Register(SYSCALL_GETPRIORITY, (void*) sys_getpriority);
+ Syscall::Register(SYSCALL_PRLIMIT, (void*) sys_prlimit);
Syscall::Register(SYSCALL_SETPRIORITY, (void*) sys_setpriority);
}