rpcsx/orbis-kernel/src/sys/sys_cpuset.cpp

195 lines
5.9 KiB
C++
Raw Normal View History

#include "KernelContext.hpp"
2023-07-03 13:10:16 +02:00
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "thread/cpuset.hpp"
#include "utils/Logs.hpp"
#include <bit>
#include <pthread.h>
#include <sched.h>
#include <sys/sysinfo.h>
enum class CpuLevel {
Root = 1,
CpuSet = 2,
Which = 3,
};
enum class CpuWhich {
Tid = 1,
Pid = 2,
CpuSet = 3,
Irq = 4,
Jail = 5,
};
static cpu_set_t toHostCpuSet(orbis::cpuset cpuSet) {
const int procCount = get_nprocs();
cpu_set_t result{};
for (unsigned cpu = std::countr_zero(cpuSet.bits);
cpu < sizeof(cpuSet.bits) * 8;
cpu = std::countr_zero(cpuSet.bits >> (cpu + 1)) + cpu + 1) {
unsigned hostCpu = cpu;
if (procCount < 8) {
hostCpu = cpu % procCount;
} else if (procCount >= 8 * 2) {
hostCpu = cpu * 2;
}
ORBIS_LOG_ERROR(__FUNCTION__, cpu, hostCpu);
CPU_SET(hostCpu, &result);
}
ORBIS_LOG_ERROR(__FUNCTION__, procCount, result.__bits[0], cpuSet.bits);
return result;
}
2023-07-03 13:10:16 +02:00
2023-07-06 18:16:25 +02:00
orbis::SysResult orbis::sys_cpuset(Thread *thread, ptr<cpusetid_t> setid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cpuset_setid(Thread *thread, cpuwhich_t which,
id_t id, cpusetid_t setid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cpuset_getid(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
ptr<cpusetid_t> setid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cpuset_getaffinity(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
size_t cpusetsize,
ptr<cpuset> mask) {
if (cpusetsize != sizeof(cpuset)) {
return ErrorCode::INVAL;
}
std::lock_guard lock(thread->mtx);
std::lock_guard lockProc(thread->tproc->mtx);
switch (CpuLevel{level}) {
case CpuLevel::Root:
case CpuLevel::CpuSet:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
case CpuLevel::Which:
switch (CpuWhich(which)) {
case CpuWhich::Tid: {
Thread *whichThread = nullptr;
if (id == ~id_t(0) || thread->tid == id) {
whichThread = thread;
} else {
whichThread = thread->tproc->threadsMap.get(id - thread->tproc->pid);
if (whichThread == nullptr) {
ORBIS_LOG_ERROR(__FUNCTION__, "thread not found", level, which, id,
cpusetsize);
return ErrorCode::SRCH;
}
}
return uwrite(mask, whichThread->affinity);
}
case CpuWhich::Pid: {
Process *whichProcess = nullptr;
if (id == ~id_t(0) || id == thread->tproc->pid) {
whichProcess = thread->tproc;
} else {
whichProcess = g_context.findProcessById(id);
if (whichProcess == nullptr) {
return ErrorCode::SRCH;
}
}
return uwrite(mask, whichProcess->affinity);
}
case CpuWhich::CpuSet:
case CpuWhich::Irq:
case CpuWhich::Jail:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
}
break;
}
return ErrorCode::INVAL;
2023-07-06 18:16:25 +02:00
}
orbis::SysResult orbis::sys_cpuset_setaffinity(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
size_t cpusetsize,
ptr<const cpuset> mask) {
std::lock_guard lock(thread->mtx);
std::lock_guard lockProc(thread->tproc->mtx);
switch (CpuLevel{level}) {
case CpuLevel::Root:
case CpuLevel::CpuSet:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
case CpuLevel::Which:
switch (CpuWhich(which)) {
case CpuWhich::Tid: {
Thread *whichThread = nullptr;
if (id == ~id_t(0) || thread->tid == id) {
whichThread = thread;
} else {
whichThread = thread->tproc->threadsMap.get(id - thread->tproc->pid);
if (whichThread == nullptr) {
ORBIS_LOG_ERROR(__FUNCTION__, "thread not found", level, which, id,
cpusetsize);
return ErrorCode::SRCH;
}
}
ORBIS_RET_ON_ERROR(uread(whichThread->affinity, mask));
auto threadHandle = whichThread->getNativeHandle();
auto hostCpuSet = toHostCpuSet(whichThread->affinity);
ORBIS_LOG_ERROR(__FUNCTION__, threadHandle, thread->tid, id);
if (pthread_setaffinity_np(threadHandle, sizeof(hostCpuSet), &hostCpuSet)) {
ORBIS_LOG_ERROR(__FUNCTION__,
"failed to set affinity mask for host thread",
whichThread->hostTid, whichThread->affinity.bits);
}
return {};
}
case CpuWhich::Pid: {
Process *whichProcess = nullptr;
if (id == ~id_t(0) || id == thread->tproc->pid) {
whichProcess = thread->tproc;
} else {
ORBIS_LOG_ERROR(__FUNCTION__, "process not found", level, which, id,
cpusetsize);
whichProcess = g_context.findProcessById(id);
if (whichProcess == nullptr) {
return ErrorCode::SRCH;
}
}
ORBIS_RET_ON_ERROR(uread(whichProcess->affinity, mask));
auto hostCpuSet = toHostCpuSet(whichProcess->affinity);
if (sched_setaffinity(whichProcess->hostPid, sizeof(hostCpuSet),
&hostCpuSet)) {
ORBIS_LOG_ERROR(__FUNCTION__,
"failed to set affinity mask for host process",
whichProcess->hostPid, whichProcess->affinity.bits);
}
return {};
}
case CpuWhich::CpuSet:
case CpuWhich::Irq:
case CpuWhich::Jail:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
}
break;
}
return ErrorCode::INVAL;
2023-07-06 18:16:25 +02:00
}