2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/PerProcessorScheduler.h"
4#include "pedigree/kernel/process/Scheduler.h"
5#include "pedigree/kernel/process/Thread.h"
6#include "pedigree/kernel/process/Uninterruptible.h"
7#include "pedigree/kernel/processor/Processor.h"
8#include "pedigree/kernel/processor/ProcessorInformation.h"
9#include "pedigree/kernel/syscallError.h"
11#include "PosixProcess.h"
12#include "PosixSubsystem.h"
14#include "scheduling-syscalls.h"
17constexpr int Other = 0, Fifo = 1,
RoundRobin = 2, Batch = 3, Idle = 5, Deadline = 6;
18constexpr int ResetOnFork = 0x40000000;
20class SchedulingResult {
22 SchedulingResult() : m_Thread(*
Processor::information().getCurrentThread()) {}
24 m_Thread.setErrno(m_Error);
26 int finish(
int value) {
27 m_Error = value < 0 ? m_Thread.getErrno() : 0;
38 const bool found = pid == 0
41 if (found && target->
getParent()->getType() == Process::Posix &&
44 target->snapshotPlacement(placement);
45 if (placement.migratable)
48 SYSCALL_ERROR(NoSuchProcess);
52bool authorized(
Thread& target) {
54 if (caller->getType() == Process::Posix) {
55 const auto source =
static_cast<PosixProcess*
>(caller)->snapshotCredentials();
57 if (!source.euid || source.euid == destination.ruid || source.euid == destination.euid)
60 SYSCALL_ERROR(NotEnoughPermissions);
64int priorityBound(
int policy,
bool maximum) {
68 return maximum ? 99 : 1;
75 SYSCALL_ERROR(InvalidArgument);
80int setPolicy(
int pid,
int policy,
const void* user) {
81 SchedulingResult result;
83 if (pid < 0 || !user) {
84 SYSCALL_ERROR(InvalidArgument);
85 return result.finish(-1);
90 SYSCALL_ERROR(BadAddress);
91 return result.finish(-1);
94 if (!acquireTarget(pid, target))
95 return result.finish(-1);
96 const int basePolicy = policy & ~ResetOnFork;
97 const int minimum = priorityBound(basePolicy,
false);
98 const int maximum = minimum < 0 ? -1 : priorityBound(basePolicy,
true);
99 if (minimum < 0 || priority < minimum || priority > maximum) {
100 SYSCALL_ERROR(InvalidArgument);
101 return result.finish(-1);
104 if (!authorized(*target.get()))
105 return result.finish(-1);
106 if (policy != Other) {
107 SYSCALL_ERROR(OperationNotSupported);
108 return result.finish(-1);
111 return result.finish(0);
115int posix_sched_setparam(
int pid,
const void* parameter) {
116 return setPolicy(pid, Other, parameter);
119int posix_sched_setscheduler(
int pid,
int policy,
const void* parameter) {
121 SYSCALL_ERROR(InvalidArgument);
124 return setPolicy(pid, policy, parameter);
127int posix_sched_getparam(
int pid,
void* parameter) {
128 SchedulingResult result;
130 if (pid < 0 || !parameter) {
131 SYSCALL_ERROR(InvalidArgument);
132 return result.finish(-1);
135 if (!acquireTarget(pid, target))
136 return result.finish(-1);
137 const int priority = 0;
140 SYSCALL_ERROR(BadAddress);
141 return result.finish(-1);
143 return result.finish(0);
146int posix_sched_getscheduler(
int pid) {
147 SchedulingResult result;
150 SYSCALL_ERROR(InvalidArgument);
151 return result.finish(-1);
154 return result.finish(acquireTarget(pid, target) ? Other : -1);
157int posix_sched_get_priority_max(
int policy) {
158 return priorityBound(policy,
true);
161int posix_sched_get_priority_min(
int policy) {
162 return priorityBound(policy,
false);
165int posix_sched_rr_get_interval(
int pid,
void* interval) {
166 SchedulingResult result;
169 SYSCALL_ERROR(InvalidArgument);
170 return result.finish(-1);
173 if (!acquireTarget(pid, target))
174 return result.finish(-1);
182 SYSCALL_ERROR(OperationNotSupported);
183 return result.finish(-1);
185 const int64_t timespec[2] = {
static_cast<int64_t
>(quantum / 1000000000),
186 static_cast<int64_t
>(quantum % 1000000000)};
188 SYSCALL_ERROR(BadAddress);
189 return result.finish(-1);
191 return result.finish(0);
194int posix_sched_setaffinity(
int pid,
unsigned int length,
const void* user) {
195 SchedulingResult result;
198 size_t copied = length;
199 const size_t bytes = Scheduler::affinityBytes();
203 SYSCALL_ERROR(BadAddress);
204 return result.finish(-1);
206 mask.intersect(Scheduler::onlineAffinity());
208 if (!acquireTarget(pid, target))
209 return result.finish(-1);
211 uint64_t generation = 0;
212 AffinityResult admitted;
215 if (!authorized(*target.get()))
216 return result.finish(-1);
218 if (!subsystem->affinityPolicyAllowed()) {
219 SYSCALL_ERROR(OperationNotSupported);
220 return result.finish(-1);
223 if (admitted == AffinityResult::Success || admitted == AffinityResult::Busy)
224 subsystem->recordAffinityPolicyUse();
226 if (admitted == AffinityResult::Invalid || admitted == AffinityResult::Pinned) {
227 SYSCALL_ERROR(InvalidArgument);
228 return result.finish(-1);
230 if (admitted == AffinityResult::Unsupported) {
231 SYSCALL_ERROR(OperationNotSupported);
232 return result.finish(-1);
234 if (admitted == AffinityResult::Terminal) {
235 SYSCALL_ERROR(NoSuchProcess);
236 return result.finish(-1);
240 if (target->
waitAffinity(generation) != AffinityResult::Success) {
241 SYSCALL_ERROR(NoSuchProcess);
242 return result.finish(-1);
244 if (admitted != AffinityResult::Busy)
245 return result.finish(0);
249int posix_sched_getaffinity(
int pid,
unsigned int length,
void* user) {
250 SchedulingResult result;
252 const size_t bytes = Scheduler::affinityBytes();
253 if (length < bytes || length %
sizeof(
unsigned long)) {
254 SYSCALL_ERROR(InvalidArgument);
255 return result.finish(-1);
258 if (!acquireTarget(pid, target))
259 return result.finish(-1);
261 target->snapshotPlacement(placement);
264 SYSCALL_ERROR(BadAddress);
265 return result.finish(-1);
267 return result.finish(
static_cast<int>(bytes));
270int posix_getcpu(
unsigned int* cpu,
unsigned int* node) {
271 SchedulingResult result;
280 SYSCALL_ERROR(BadAddress);
281 return result.finish(-1);
283 return result.finish(0);
Memory-mapped file interface.
static MemoryMapManager & instance()
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
MUST_USE_RESULT bool acquireThread(ThreadLease &lease, size_t n)
static ProcessorInformation & information()
static Scheduler & instance()
@ TerminateThread
Exit only this thread during Process exit.
AffinityResult waitAffinity(uint64_t generation)
UnwindType getUnwindState()
Process * getParent() const
class PerProcessorScheduler * getScheduler() const
AffinityResult requestAffinity(const CpuAffinityMask &mask, uint64_t &generation)