#include "KernelContext.hpp" #include "sys/sysproto.hpp" #include "thread/Process.hpp" #include "thread/Thread.hpp" #include "thread/cpuset.hpp" #include "utils/Logs.hpp" #include #include #include #include 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; } orbis::SysResult orbis::sys_cpuset(Thread *thread, ptr 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 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 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; } orbis::SysResult orbis::sys_cpuset_setaffinity(Thread *thread, cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, ptr 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; }