2024-11-13 19:53:05 +01:00
|
|
|
#include "KernelContext.hpp"
|
2023-07-03 13:10:16 +02:00
|
|
|
#include "sys/sysproto.hpp"
|
2024-11-13 19:53:05 +01:00
|
|
|
#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) {
|
2024-11-13 19:53:05 +01:00
|
|
|
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) {
|
2024-11-13 19:53:05 +01:00
|
|
|
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
|
|
|
}
|