orbis-kernel: unblock signals only on wait operations

implement sys_cpuset_getaffinity, sys_cpuset_setaffinity, sys_rtprio_thread
fix hang on sys_select
simplify sys_thr_*_ucontext
This commit is contained in:
DH 2024-11-13 21:53:05 +03:00
parent c19c70eb77
commit 9fbe1846c0
21 changed files with 675 additions and 236 deletions

View file

@ -8,6 +8,7 @@
#include "../thread/Thread.hpp"
#include "../thread/types.hpp"
#include "ProcessState.hpp"
#include "cpuset.hpp"
#include "orbis/AppInfo.hpp"
#include "orbis/AuthInfo.hpp"
#include "orbis/file.hpp"
@ -64,6 +65,7 @@ struct Process final {
AuthInfo authInfo{};
kstring cwd;
kstring root = "/";
cpuset affinity{(1 << 7) - 1};
sint memoryContainer{1};
sint budgetId{1};
bool isInSandbox = false;

View file

@ -87,5 +87,8 @@ struct ProcessOps {
SysResult (*registerEhFrames)(Thread *thread);
void (*where)(Thread *);
void (*unblock)(Thread *);
void (*block)(Thread *);
};
} // namespace orbis

View file

@ -1,53 +1,76 @@
#pragma once
#include "ThreadState.hpp"
#include "cpuset.hpp"
#include "orbis-config.hpp"
#include "types.hpp"
#include "../KernelAllocator.hpp"
#include "../ucontext.hpp"
#include "../utils/SharedAtomic.hpp"
#include "../utils/SharedCV.hpp"
#include "../utils/SharedMutex.hpp"
#include <atomic>
#include <thread>
namespace orbis {
struct Process;
static constexpr std::uint32_t kThreadSuspendFlag = 1 << 31;
struct Thread {
utils::shared_mutex mtx;
Process *tproc = nullptr;
uint64_t retval[2]{};
void *context{};
kvector<void *> altStack;
ptr<void> stackStart;
ptr<void> stackEnd;
uint64_t fsBase{};
uint64_t gsBase{};
char name[32]{};
cpuset affinity{~0u};
SigSet sigMask = {0x7fff'ffff, ~0u, ~0u, ~0u};
rtprio prio{
.type = 2,
.prio = 10,
};
utils::shared_mutex suspend_mtx;
utils::shared_cv suspend_cv;
kdeque<int> signalQueue;
kvector<UContext> sigReturns;
std::atomic<unsigned> suspended{0};
kvector<SigInfo> blockedSignals;
kvector<SigInfo> queuedSignals;
shared_atomic32 suspendFlags{0};
std::int64_t hostTid = -1;
lwpid_t tid = -1;
unsigned unblocked = 0;
ThreadState state = ThreadState::INACTIVE;
std::thread handle;
std::thread::native_handle_type nativeHandle;
// Used to wake up thread in sleep queue
utils::shared_cv sync_cv;
uint64_t evfResultPattern;
uint64_t evfIsCancelled;
[[nodiscard]] std::thread::native_handle_type getNativeHandle() {
if (handle.joinable()) {
return handle.native_handle();
}
return nativeHandle;
}
// Print backtrace
void where();
void unblock();
void block();
void suspend();
void resume();
void sendSignal(int signo);
void notifyUnblockedSignal(int signo);
// FIXME: implement thread destruction
void incRef() {}
@ -55,4 +78,31 @@ struct Thread {
};
extern thread_local Thread *g_currentThread;
struct scoped_unblock {
scoped_unblock();
~scoped_unblock();
scoped_unblock(const scoped_unblock &) = delete;
};
class scoped_unblock_now {
bool unblocked = false;
public:
scoped_unblock_now() {
if (g_currentThread && g_currentThread->context) {
g_currentThread->unblock();
unblocked = true;
}
}
~scoped_unblock_now() {
if (unblocked) {
g_currentThread->block();
}
}
scoped_unblock_now(const scoped_unblock_now &) = delete;
};
} // namespace orbis

View file

@ -3,10 +3,7 @@
#include "orbis-config.hpp"
namespace orbis {
static constexpr auto NCPUBITS = sizeof(slong) * 8;
static constexpr auto NCPUWORDS = 128 / NCPUBITS;
struct cpuset {
slong bits[NCPUWORDS];
uint bits;
};
} // namespace orbis

View file

@ -23,6 +23,8 @@ static constexpr auto kRelaxSpinCount = 12;
static constexpr auto kSpinCount = 16;
inline namespace utils {
inline thread_local void (*g_scopedUnblock)(bool) = nullptr;
bool try_spin_wait(auto &&pred) {
for (std::size_t i = 0; i < kSpinCount; ++i) {
if (pred()) {
@ -58,8 +60,8 @@ struct shared_atomic32 : std::atomic<std::uint32_t> {
using atomic::operator=;
template <typename Clock, typename Dur>
[[nodiscard]] std::errc wait(std::uint32_t oldValue,
std::chrono::time_point<Clock, Dur> timeout) {
std::errc wait(std::uint32_t oldValue,
std::chrono::time_point<Clock, Dur> timeout) {
if (try_spin_wait(
[&] { return load(std::memory_order::acquire) != oldValue; })) {
return {};
@ -76,12 +78,12 @@ struct shared_atomic32 : std::atomic<std::uint32_t> {
std::chrono::duration_cast<std::chrono::microseconds>(timeout - now));
}
[[nodiscard]] std::errc wait(std::uint32_t oldValue,
std::chrono::microseconds usec_timeout) {
std::errc wait(std::uint32_t oldValue,
std::chrono::microseconds usec_timeout) {
return wait_impl(oldValue, usec_timeout);
}
[[nodiscard]] std::errc wait(std::uint32_t oldValue) {
std::errc wait(std::uint32_t oldValue) {
if (try_spin_wait(
[&] { return load(std::memory_order::acquire) != oldValue; })) {
return {};

View file

@ -2,6 +2,7 @@
#include "orbis/thread/Process.hpp"
#include "orbis/thread/ProcessOps.hpp"
#include "orbis/utils/Logs.hpp"
#include "utils/SharedAtomic.hpp"
#include <bit>
#include <chrono>
#include <csignal>
@ -314,16 +315,42 @@ void log_class_string<kstring>::format(std::string &out, const void *arg) {
} // namespace logs
void Thread::suspend() { sendSignal(-1); }
void Thread::resume() { sendSignal(-2); }
void Thread::sendSignal(int signo) {
std::lock_guard lock(mtx);
signalQueue.push_back(signo);
if (::tgkill(tproc->hostPid, hostTid, SIGUSR1) < 0) {
perror("tgkill");
if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) {
perror("pthread_sigqueue");
}
}
void Thread::notifyUnblockedSignal(int signo) {
for (std::size_t i = 0; i < blockedSignals.size();) {
if (blockedSignals[i].signo != signo) {
++i;
continue;
}
queuedSignals.push_back(blockedSignals[i]);
blockedSignals.erase(blockedSignals.begin() + i);
}
}
void Thread::where() { tproc->ops->where(this); }
void Thread::unblock() { tproc->ops->unblock(this); }
void Thread::block() { tproc->ops->block(this); }
scoped_unblock::scoped_unblock() {
if (g_currentThread && g_currentThread->context) {
g_scopedUnblock = [](bool unblock) {
if (unblock) {
g_currentThread->unblock();
} else {
g_currentThread->block();
}
};
}
}
scoped_unblock::~scoped_unblock() { g_scopedUnblock = nullptr; }
} // namespace orbis

View file

@ -77,11 +77,14 @@ orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode,
waitingThreads.emplace_back(waitingThread);
if (timeout) {
result = toErrorCode(thread->sync_cv.wait(queueMtx, *timeout));
update_timeout();
} else {
result = toErrorCode(thread->sync_cv.wait(queueMtx));
{
orbis::scoped_unblock unblock;
if (timeout) {
result = toErrorCode(thread->sync_cv.wait(queueMtx, *timeout));
update_timeout();
} else {
result = toErrorCode(thread->sync_cv.wait(queueMtx));
}
}
if (thread->evfIsCancelled == UINT64_MAX) {

View file

@ -1,6 +1,7 @@
#include "ipmi.hpp"
#include "KernelContext.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include <chrono>
#include <span>
@ -243,6 +244,7 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread,
{
std::lock_guard lock(server->mutex);
while (server->packets.empty()) {
orbis::scoped_unblock unblock;
server->receiveCv.wait(server->mutex);
}
@ -621,6 +623,7 @@ orbis::SysResult orbis::sysIpmiClientTryGetResult(Thread *thread,
return uwrite(result, 0u);
}
orbis::scoped_unblock unblock;
client->asyncResponseCv.wait(client->mutex);
}
@ -684,7 +687,11 @@ orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread,
auto waitTime = std::chrono::duration_cast<std::chrono::microseconds>(
timeoutPoint - now);
queue.messageCv.wait(client->mutex, waitTime.count());
{
orbis::scoped_unblock unblock;
queue.messageCv.wait(client->mutex, waitTime.count());
}
if (!queue.messages.empty()) {
now = clock::now();
@ -704,6 +711,7 @@ orbis::SysResult orbis::sysIpmiClientGetMessage(Thread *thread,
}
} else {
while (queue.messages.empty()) {
orbis::scoped_unblock unblock;
queue.messageCv.wait(client->mutex);
}
}
@ -966,7 +974,10 @@ orbis::sysIpmiClientInvokeSyncMethod(Thread *thread, ptr<uint> result, uint kid,
IpmiSession::SyncResponse response;
while (true) {
session->responseCv.wait(session->mutex);
{
orbis::scoped_unblock unblock;
session->responseCv.wait(session->mutex);
}
bool found = false;
for (auto it = session->syncResponses.begin();
@ -1131,10 +1142,12 @@ orbis::SysResult orbis::sysIpmiClientConnect(Thread *thread, ptr<uint> result,
}
while (client->session == nullptr && !client->connectionStatus) {
orbis::scoped_unblock unblock;
client->sessionCv.wait(client->mutex);
}
while (!client->connectionStatus) {
orbis::scoped_unblock unblock;
client->connectCv.wait(client->mutex);
}
@ -1287,8 +1300,13 @@ orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread,
}
auto &evf = client->eventFlags[_params.index];
auto waitResult = evf.wait(thread, _params.mode, _params.patternSet,
_params.pTimeout != 0 ? &resultTimeout : nullptr);
ErrorCode waitResult;
{
orbis::scoped_unblock unblock;
waitResult = evf.wait(thread, _params.mode, _params.patternSet,
_params.pTimeout != 0 ? &resultTimeout : nullptr);
}
if (_params.pPatternSet != nullptr) {
ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, thread->evfResultPattern));

View file

@ -1,4 +1,50 @@
#include "KernelContext.hpp"
#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;
}
orbis::SysResult orbis::sys_cpuset(Thread *thread, ptr<cpusetid_t> setid) {
return ErrorCode::NOSYS;
@ -16,11 +62,133 @@ orbis::SysResult orbis::sys_cpuset_getaffinity(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
size_t cpusetsize,
ptr<cpuset> mask) {
return {};
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<const cpuset> mask) {
return {};
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;
}

View file

@ -450,7 +450,15 @@ orbis::SysResult orbis::sys_select(Thread *thread, sint nd,
ptr<struct fd_set_t> out,
ptr<struct fd_set_t> ex,
ptr<struct timeval> tv) {
return ErrorCode::NOSYS;
if (tv == nullptr) {
orbis::scoped_unblock_now unblock;
std::this_thread::sleep_for(std::chrono::days(1));
} else {
std::this_thread::sleep_for(std::chrono::seconds(tv->tv_sec));
return orbis::ErrorCode::TIMEDOUT;
}
return {};
}
orbis::SysResult orbis::sys_poll(Thread *thread, ptr<struct pollfd> fds,
uint nfds, sint timeout) {

View file

@ -1,6 +1,8 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include <sched.h>
namespace orbis {
struct rlimit {
@ -21,9 +23,54 @@ orbis::SysResult orbis::sys_rtprio_thread(Thread *thread, sint function,
ptr<struct rtprio> rtp) {
ORBIS_LOG_ERROR(__FUNCTION__, function, lwpid, rtp->prio, rtp->type);
thread->where();
Thread *targetThread;
if (lwpid == thread->tid || lwpid == -1) {
targetThread = thread;
} else {
targetThread = thread->tproc->threadsMap.get(lwpid - thread->tproc->pid);
if (targetThread == nullptr) {
return ErrorCode::SRCH;
}
}
if (function == 0) {
rtp->type = 2;
rtp->prio = 10;
return orbis::uwrite(rtp, targetThread->prio);
} else if (function == 1) {
ORBIS_RET_ON_ERROR(orbis::uread(targetThread->prio, rtp));
int hostPolicy = SCHED_RR;
auto prioMin = sched_get_priority_min(hostPolicy);
auto prioMax = sched_get_priority_max(hostPolicy);
auto hostPriority =
(targetThread->prio.prio * (prioMax - prioMin + 1)) / 1000 - prioMin;
::sched_param hostParam{};
hostParam.sched_priority = hostPriority;
if (pthread_setschedparam(targetThread->getNativeHandle(), hostPolicy,
&hostParam)) {
auto normPrio = targetThread->prio.prio / 1000.f;
hostParam.sched_priority = 0;
if (normPrio < 0.3f) {
hostPolicy = SCHED_BATCH;
} else if (normPrio < 0.7f) {
hostPolicy = SCHED_OTHER;
} else {
hostPolicy = SCHED_IDLE;
}
if (pthread_setschedparam(targetThread->getNativeHandle(),
hostPolicy, &hostParam)) {
ORBIS_LOG_ERROR(__FUNCTION__, "failed to set host priority",
hostPriority, targetThread->prio.prio,
targetThread->prio.type, errno,
targetThread->getNativeHandle(), prioMin, prioMax, errno);
}
} else {
ORBIS_LOG_ERROR(__FUNCTION__, "set host priority", hostPriority,
targetThread->tid, targetThread->prio.prio,
targetThread->prio.type, prioMin, prioMax);
}
}
return {};
}

View file

@ -15,9 +15,9 @@
#include "uio.hpp"
#include "utils/Logs.hpp"
#include <fcntl.h>
#include <ranges>
#include <sys/mman.h>
#include <sys/stat.h>
#include <thread>
orbis::SysResult orbis::sys_netcontrol(Thread *thread, sint fd, uint op,
ptr<void> buf, uint nbuf) {
@ -576,6 +576,8 @@ orbis::SysResult orbis::sys_osem_wait(Thread *thread, sint id, sint need,
break;
}
}
orbis::scoped_unblock unblock;
sem->cond.wait(sem->mtx, ut);
}
@ -1158,10 +1160,17 @@ orbis::SysResult orbis::sys_get_resident_fmem_count(Thread *thread, pid_t pid) {
orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid,
char *buf, size_t buflen) {
Thread *searchThread;
if (thread->tid == lwpid) {
if (thread->tid == lwpid || lwpid == -1) {
searchThread = thread;
} else {
searchThread = thread->tproc->threadsMap.get(lwpid);
searchThread = thread->tproc->threadsMap.get(lwpid - thread->tproc->pid);
if (searchThread == nullptr) {
if (auto process = g_context.findProcessById(lwpid)) {
searchThread = process->threadsMap.get(lwpid - process->pid);
}
}
if (searchThread == nullptr) {
return ErrorCode::SRCH;
}
@ -1169,11 +1178,13 @@ orbis::SysResult orbis::sys_thr_get_name(Thread *thread, lwpid_t lwpid,
auto namelen = std::strlen(searchThread->name);
if (namelen >= buflen) {
return ErrorCode::INVAL;
auto writeLen = std::min(namelen + 1, buflen);
if (writeLen > 0) {
ORBIS_RET_ON_ERROR(uwriteRaw(buf, searchThread->name, writeLen - 1));
buf[writeLen] = 0;
}
ORBIS_RET_ON_ERROR(uwriteRaw(buf, searchThread->name, namelen));
thread->retval[0] = writeLen > 0 ? writeLen : namelen + 1;
return {};
}
orbis::SysResult orbis::sys_set_gpo(Thread *thread /* TODO */) {
@ -1318,78 +1329,77 @@ orbis::SysResult orbis::sys_resume_internal_hdd(Thread *thread /* TODO */) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_suspend_ucontext(Thread *thread, lwpid_t tid) {
auto t = tid == thread->tid ? thread
: thread->tproc->threadsMap.get(tid % 10000 - 1);
auto t = tid == thread->tid
? thread
: thread->tproc->threadsMap.get(tid - thread->tproc->pid);
if (t == nullptr) {
return ErrorCode::SRCH;
}
while (true) {
unsigned prevSuspend = 0;
if (t->suspended.compare_exchange_strong(prevSuspend, 1)) {
t->suspended.fetch_sub(1);
t->suspend();
ORBIS_LOG_NOTICE(__FUNCTION__, tid);
while (t->suspended == 0) {
std::this_thread::yield();
}
auto prevValue = t->suspendFlags.fetch_add(1, std::memory_order::relaxed);
break;
}
if (t->suspended.compare_exchange_strong(prevSuspend, prevSuspend + 1)) {
break;
}
while ((prevValue & kThreadSuspendFlag) == 0) {
t->suspend();
t->suspendFlags.wait(prevValue);
prevValue = t->suspendFlags.load(std::memory_order::relaxed);
}
return {};
}
orbis::SysResult orbis::sys_thr_resume_ucontext(Thread *thread, lwpid_t tid) {
auto t = tid == thread->tid ? thread
: thread->tproc->threadsMap.get(tid % 10000 - 1);
auto t = tid == thread->tid
? thread
: thread->tproc->threadsMap.get(tid - thread->tproc->pid);
if (t == nullptr) {
return ErrorCode::SRCH;
}
while (true) {
unsigned prevSuspend = t->suspended.load();
if (t->suspended == prevSuspend) {
t->resume();
break;
}
ORBIS_LOG_NOTICE(__FUNCTION__, tid);
if (prevSuspend == 0) {
auto result = t->suspendFlags.op([](unsigned &value) -> ErrorCode {
if ((value & kThreadSuspendFlag) == 0) {
return ErrorCode::INVAL;
}
if (t->suspended.compare_exchange_strong(prevSuspend, prevSuspend - 1)) {
break;
if ((value & ~kThreadSuspendFlag) == 0) {
return ErrorCode::INVAL;
}
--value;
return {};
});
if (result == ErrorCode{}) {
t->suspendFlags.notify_all();
}
return {};
return result;
}
orbis::SysResult orbis::sys_thr_get_ucontext(Thread *thread, lwpid_t tid,
ptr<UContext> context) {
auto t = tid == thread->tid ? thread
: thread->tproc->threadsMap.get(tid % 10000 - 1);
auto t = tid == thread->tid
? thread
: thread->tproc->threadsMap.get(tid - thread->tproc->pid);
if (t == nullptr) {
return ErrorCode::SRCH;
}
std::lock_guard lock(t->mtx);
if (t->suspended == 0) {
if ((t->suspendFlags.load() & kThreadSuspendFlag) == 0) {
return ErrorCode::INVAL;
}
for (auto it = t->sigReturns.rbegin(); it != t->sigReturns.rend(); ++it) {
auto &savedContext = *it;
if (savedContext.mcontext.rip < 0x100'0000'0000) {
for (auto &savedContext : std::ranges::reverse_view(t->sigReturns)) {
if (savedContext.mcontext.rip < orbis::kMaxAddress) {
return uwrite(context, savedContext);
}
}
ORBIS_LOG_FATAL(__FUNCTION__, tid, "not found guest context");
std::abort();
*context = {};
return {};
}

View file

@ -32,6 +32,8 @@ orbis::SysResult orbis::sys_sigaction(Thread *thread, sint sig,
orbis::SysResult orbis::sys_sigprocmask(Thread *thread, sint how,
ptr<SigSet> set, ptr<SigSet> oset) {
std::lock_guard lock(thread->mtx);
if (oset) {
ORBIS_RET_ON_ERROR(uwrite(oset, thread->sigMask));
}
@ -40,20 +42,23 @@ orbis::SysResult orbis::sys_sigprocmask(Thread *thread, sint how,
SigSet _set;
ORBIS_RET_ON_ERROR(uread(_set, set));
auto newSigMask = thread->sigMask;
auto oldSigMask = newSigMask;
switch (how) {
case 1: // block
for (std::size_t i = 0; i < 4; ++i) {
thread->sigMask.bits[i] |= _set.bits[i];
newSigMask.bits[i] |= _set.bits[i];
}
break;
case 2: // unblock
for (std::size_t i = 0; i < 4; ++i) {
thread->sigMask.bits[i] &= ~_set.bits[i];
newSigMask.bits[i] &= ~_set.bits[i];
}
break;
case 3: // set
thread->sigMask = _set;
newSigMask = _set;
break;
default:
@ -62,8 +67,20 @@ orbis::SysResult orbis::sys_sigprocmask(Thread *thread, sint how,
return ErrorCode::INVAL;
}
thread->sigMask.clear(kSigKill);
thread->sigMask.clear(kSigStop);
newSigMask.clear(kSigKill);
newSigMask.clear(kSigStop);
thread->sigMask = newSigMask;
for (std::size_t word = 0; word < std::size(newSigMask.bits); ++word) {
auto unblockedBits = ~oldSigMask.bits[word] & newSigMask.bits[word];
std::uint32_t offset = word * 32 + 1;
for (std::uint32_t i = std::countr_zero(unblockedBits); i < 32;
i += std::countr_zero(unblockedBits >> (i + 1)) + 1) {
thread->notifyUnblockedSignal(offset + i);
}
}
}
return {};

View file

@ -91,6 +91,7 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
if (val == id) {
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx));
if (result != ErrorCode{} || node->second.thr != thread)
break;
@ -99,6 +100,7 @@ orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
@ -191,6 +193,7 @@ static ErrorCode do_lock_normal(Thread *thread, ptr<umutex> m, uint flags,
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m);
auto node = chain.enqueue(key, thread);
if (m->owner.compare_exchange_strong(owner, owner | kUmutexContested)) {
orbis::scoped_unblock unblock;
error = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (error == ErrorCode{} && node->second.thr == thread) {
error = ErrorCode::TIMEDOUT;
@ -350,6 +353,7 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
if (result == ErrorCode{}) {
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (result != ErrorCode{} || node->second.thr != thread) {
break;
@ -359,6 +363,7 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread) {
@ -455,6 +460,7 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<urwlock> rwlock,
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (result != ErrorCode{} || node->second.thr != thread) {
break;
@ -464,6 +470,7 @@ orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<urwlock> rwlock,
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
@ -556,6 +563,7 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<urwlock> rwlock,
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
error = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (error != ErrorCode{} || node->second.thr != thread) {
break;
@ -565,6 +573,7 @@ orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<urwlock> rwlock,
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
error =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
@ -729,6 +738,7 @@ orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<usem> sem,
if (!sem->count) {
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (result != ErrorCode{} || node->second.thr != thread)
break;
@ -737,6 +747,7 @@ orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<usem> sem,
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)

View file

@ -15,9 +15,20 @@ std::errc shared_atomic32::wait_impl(std::uint32_t oldValue,
timeout.tv_sec = (usec_timeout_count / 1000'000);
}
bool unblock = (!useTimeout || usec_timeout.count() > 1000) &&
g_scopedUnblock != nullptr;
if (unblock) {
g_scopedUnblock(true);
}
int result = syscall(SYS_futex, this, FUTEX_WAIT, oldValue,
useTimeout ? &timeout : nullptr);
if (unblock) {
g_scopedUnblock(false);
}
if (result < 0) {
return static_cast<std::errc>(errno);
}

View file

@ -17,17 +17,23 @@ std::errc shared_cv::impl_wait(shared_mutex &mutex, unsigned _val,
std::errc result = {};
bool useTimeout = usec_timeout != static_cast<std::uint64_t>(-1);
while (true) {
result = m_value.wait(_val, usec_timeout == static_cast<std::uint64_t>(-1)
? std::chrono::microseconds::max()
: std::chrono::microseconds(usec_timeout));
result =
m_value.wait(_val, useTimeout ? std::chrono::microseconds(usec_timeout)
: std::chrono::microseconds::max());
bool spurious = result == std::errc::resource_unavailable_try_again ||
result == std::errc::interrupted;
// Cleanup
const auto old = m_value.fetch_op([&](unsigned &value) {
// Remove waiter if no signals
if (!(value & ~c_waiter_mask) &&
result != std::errc::resource_unavailable_try_again) {
value -= 1;
if ((value & ~c_waiter_mask) == 0) {
if (useTimeout || !spurious) {
value -= 1;
}
}
// Try to remove signal
@ -60,7 +66,7 @@ std::errc shared_cv::impl_wait(shared_mutex &mutex, unsigned _val,
#endif
// Possibly spurious wakeup
if (result != std::errc::resource_unavailable_try_again) {
if (useTimeout || !spurious) {
break;
}

View file

@ -801,11 +801,15 @@ static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path,
thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExec);
std::thread([&] {
thread->handle = std::thread([&] {
thread->hostTid = ::gettid();
rx::thread::initialize();
rx::thread::setupSignalStack();
rx::thread::setupThisThread();
ps4Exec(thread, executableModule, argv, envv);
}).join();
});
thread->handle.join();
std::abort();
}
@ -1038,7 +1042,6 @@ int main(int argc, const char *argv[]) {
mainThread->tproc = initProcess;
mainThread->tid = initProcess->pid + baseId;
mainThread->state = orbis::ThreadState::RUNNING;
mainThread->hostTid = ::gettid();
orbis::g_currentThread = mainThread;
if (!isSystem && !vfs::exists(guestArgv[0], mainThread) &&
@ -1191,6 +1194,12 @@ int main(int argc, const char *argv[]) {
}
}
mainThread->hostTid = ::gettid();
mainThread->nativeHandle = pthread_self();
orbis::g_currentThread = mainThread;
rx::thread::setupSignalStack();
rx::thread::setupThisThread();
status =
ps4Exec(mainThread, execEnv, std::move(executableModule), guestArgv, {});

View file

@ -540,6 +540,7 @@ SysResult thr_new(orbis::Thread *thread, orbis::ptr<thr_param> param,
auto proc = thread->tproc;
std::lock_guard lock(proc->mtx);
auto [baseId, childThread] = proc->threadsMap.emplace();
std::lock_guard lockThr(childThread->mtx);
childThread->tproc = proc;
childThread->tid = proc->pid + baseId;
childThread->state = orbis::ThreadState::RUNQ;
@ -569,35 +570,43 @@ SysResult thr_new(orbis::Thread *thread, orbis::ptr<thr_param> param,
ORBIS_RET_ON_ERROR(uread(_rtp, _param.rtp));
ORBIS_LOG_NOTICE(" rtp: ", _rtp.type, _rtp.prio);
}
auto stdthr = std::thread{[=, childThread = Ref<Thread>(childThread)] {
static_cast<void>(
uwrite(_param.child_tid, slong(childThread->tid))); // TODO: verify
auto context = new ucontext_t{};
childThread->handle =
std::thread{[=, childThread = Ref<Thread>(childThread)] {
static_cast<void>(
uwrite(_param.child_tid, slong(childThread->tid))); // TODO: verify
auto context = new ucontext_t{};
context->uc_mcontext.gregs[REG_RDI] =
reinterpret_cast<std::uintptr_t>(_param.arg);
context->uc_mcontext.gregs[REG_RSI] =
reinterpret_cast<std::uintptr_t>(_param.arg);
context->uc_mcontext.gregs[REG_RSP] =
reinterpret_cast<std::uintptr_t>(childThread->stackEnd);
context->uc_mcontext.gregs[REG_RIP] =
reinterpret_cast<std::uintptr_t>(_param.start_func);
context->uc_mcontext.gregs[REG_RDI] =
reinterpret_cast<std::uintptr_t>(_param.arg);
context->uc_mcontext.gregs[REG_RSI] =
reinterpret_cast<std::uintptr_t>(_param.arg);
context->uc_mcontext.gregs[REG_RSP] =
reinterpret_cast<std::uintptr_t>(childThread->stackEnd);
context->uc_mcontext.gregs[REG_RIP] =
reinterpret_cast<std::uintptr_t>(_param.start_func);
childThread->hostTid = ::gettid();
childThread->context = context;
childThread->state = orbis::ThreadState::RUNNING;
childThread->hostTid = ::gettid();
childThread->context = context;
childThread->state = orbis::ThreadState::RUNNING;
rx::thread::setupSignalStack();
rx::thread::setupThisThread();
rx::thread::invoke(childThread.get());
}};
rx::thread::setupSignalStack();
rx::thread::setupThisThread();
rx::thread::invoke(childThread.get());
}};
if (pthread_setname_np(stdthr.native_handle(),
std::to_string(childThread->tid).c_str())) {
std::string name = std::to_string(childThread->tid);
if (childThread->name[0] != '0') {
name += '-';
name += childThread->name;
}
if (name.size() > 15) {
name.resize(15);
}
if (pthread_setname_np(childThread->getNativeHandle(), name.c_str())) {
perror("pthread_setname_np");
}
childThread->handle = std::move(stdthr);
return {};
}
SysResult thr_exit(orbis::Thread *thread, orbis::ptr<orbis::slong> state) {
@ -623,9 +632,7 @@ SysResult thr_kill(orbis::Thread *thread, orbis::slong id, orbis::sint sig) {
}
ORBIS_LOG_FATAL(__FUNCTION__, id, sig, t->hostTid);
std::lock_guard lock(t->tproc->mtx);
t->signalQueue.push_back(sig);
::tgkill(t->tproc->hostPid, t->hostTid, SIGUSR1);
t->sendSignal(sig);
return {};
}
@ -811,6 +818,7 @@ SysResult fork(Thread *thread, slong flags) {
orbis::g_currentThread = newThread;
newThread->retval[0] = 0;
newThread->retval[1] = 1;
newThread->nativeHandle = pthread_self();
thread = orbis::g_currentThread;
@ -830,8 +838,6 @@ SysResult fork(Thread *thread, slong flags) {
return {};
}
volatile bool debuggerPresent = false;
SysResult execve(Thread *thread, ptr<char> fname, ptr<ptr<char>> argv,
ptr<ptr<char>> envv) {
ORBIS_LOG_ERROR(__FUNCTION__, fname);
@ -906,7 +912,13 @@ SysResult execve(Thread *thread, ptr<char> fname, ptr<ptr<char>> argv,
ORBIS_LOG_ERROR(__FUNCTION__, "done");
std::thread([&] {
rx::thread::setupSignalStack();
rx::thread::initialize();
rx::thread::setupThisThread();
thread->hostTid = ::gettid();
thread->nativeHandle = pthread_self();
orbis::g_currentThread = thread;
ps4Exec(thread, executableModule, _argv, _envv);
}).join();
std::abort();
@ -925,6 +937,50 @@ SysResult registerEhFrames(Thread *thread) {
void where(Thread *thread) {
rx::printStackTrace((ucontext_t *)thread->context, thread, 2);
}
void block(Thread *thread) {
if (--thread->unblocked != 0) {
return;
}
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSYS);
if (pthread_sigmask(SIG_BLOCK, &set, nullptr)) {
perror("pthread_sigmask block");
std::abort();
}
// ORBIS_LOG_ERROR("blocking thread", thread->tid,
// orbis::g_currentThread->tid);
std::free(thread->altStack.back());
thread->altStack.pop_back();
thread->sigReturns.pop_back();
}
void unblock(Thread *thread) {
if (thread->unblocked++ != 0) {
return;
}
// ORBIS_LOG_ERROR("unblocking thread", thread->tid,
// orbis::g_currentThread->tid);
rx::thread::copyContext(thread, thread->sigReturns.emplace_back(),
*reinterpret_cast<ucontext_t *>(thread->context));
auto altStack = malloc(rx::thread::getSigAltStackSize());
thread->altStack.push_back(altStack);
rx::thread::setupSignalStack(altStack);
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSYS);
if (pthread_sigmask(SIG_UNBLOCK, &set, nullptr)) {
perror("pthread_sigmask unblock");
std::abort();
}
}
} // namespace
ProcessOps rx::procOpsTable = {
@ -975,4 +1031,6 @@ ProcessOps rx::procOpsTable = {
.processNeeded = processNeeded,
.registerEhFrames = registerEhFrames,
.where = where,
.unblock = unblock,
.block = block,
};

View file

@ -10,18 +10,13 @@
#include <immintrin.h>
#include <link.h>
#include <linux/prctl.h>
#include <print>
#include <rx/align.hpp>
#include <sys/prctl.h>
#include <ucontext.h>
#include <unistd.h>
#include <xbyak/xbyak.h>
static std::size_t getSigStackSize() {
static auto sigStackSize = std::max<std::size_t>(
SIGSTKSZ, ::rx::alignUp(64 * 1024 * 1024, rx::mem::pageSize));
return sigStackSize;
}
static auto setContext = [] {
struct SetContext : Xbyak::CodeGenerator {
SetContext() {
@ -42,7 +37,108 @@ static auto setContext = [] {
return setContextStorage.getCode<void (*)(const mcontext_t &)>();
}();
static void copy(orbis::MContext &dst, const mcontext_t &src) {
static __attribute__((no_stack_protector)) void
handleSigSys(int sig, siginfo_t *info, void *ucontext) {
if (auto hostFs = _readgsbase_u64()) {
_writefsbase_u64(hostFs);
}
// rx::printStackTrace(reinterpret_cast<ucontext_t *>(ucontext),
// rx::thread::g_current, 1);
auto thread = orbis::g_currentThread;
auto prevContext = std::exchange(thread->context, ucontext);
if ((std::uint64_t)&thread < orbis::kMaxAddress) {
ORBIS_LOG_ERROR("unexpected sigsys signal stack", thread->tid, sig,
(std::uint64_t)&thread);
std::abort();
}
orbis::syscall_entry(thread);
thread = orbis::g_currentThread;
thread->context = prevContext;
_writefsbase_u64(thread->fsBase);
}
__attribute__((no_stack_protector)) static void
handleSigUser(int sig, siginfo_t *info, void *ucontext) {
if (auto hostFs = _readgsbase_u64()) {
_writefsbase_u64(hostFs);
}
auto context = reinterpret_cast<ucontext_t *>(ucontext);
bool inGuestCode = context->uc_mcontext.gregs[REG_RIP] < orbis::kMaxAddress;
auto thread = orbis::g_currentThread;
if ((std::uint64_t)&context < orbis::kMaxAddress) {
ORBIS_LOG_ERROR("unexpected sigusr signal stack", thread->tid, sig,
inGuestCode, (std::uint64_t)&context);
std::abort();
}
int guestSignal = info->si_value.sival_int;
if (guestSignal == -1) {
// ORBIS_LOG_ERROR("suspending thread", thread->tid, inGuestCode);
if (inGuestCode) {
thread->unblock();
}
auto [value, locked] = thread->suspendFlags.fetch_op([](unsigned &value) {
if ((value & ~orbis::kThreadSuspendFlag) != 0) {
value |= orbis::kThreadSuspendFlag;
return true;
}
return false;
});
if (locked) {
thread->suspendFlags.notify_all();
value |= orbis::kThreadSuspendFlag;
while (true) {
while ((value & ~orbis::kThreadSuspendFlag) != 0) {
thread->suspendFlags.wait(value);
value = thread->suspendFlags.load(std::memory_order::relaxed);
}
bool unlocked = thread->suspendFlags.op([](unsigned &value) {
if ((value & ~orbis::kThreadSuspendFlag) == 0) {
value &= ~orbis::kThreadSuspendFlag;
return true;
}
return false;
});
if (unlocked) {
thread->suspendFlags.notify_all();
break;
}
}
}
if (inGuestCode) {
thread->block();
}
// ORBIS_LOG_ERROR("thread wake", thread->tid);
}
if (inGuestCode) {
_writefsbase_u64(thread->fsBase);
}
}
std::size_t rx::thread::getSigAltStackSize() {
static auto sigStackSize = std::max<std::size_t>(
SIGSTKSZ, ::rx::alignUp(64 * 1024 * 1024, rx::mem::pageSize));
return sigStackSize;
}
void rx::thread::copyContext(orbis::MContext &dst, const mcontext_t &src) {
// dst.onstack = src.gregs[REG_ONSTACK];
dst.rdi = src.gregs[REG_RDI];
dst.rsi = src.gregs[REG_RSI];
@ -86,123 +182,14 @@ static void copy(orbis::MContext &dst, const mcontext_t &src) {
// dst.xfpustate_len = src.gregs[REG_XFPUSTATE_LEN];
}
static void copy(orbis::Thread *thread, orbis::UContext &dst,
const ucontext_t &src) {
void rx::thread::copyContext(orbis::Thread *thread, orbis::UContext &dst,
const ucontext_t &src) {
dst = {};
dst.stack.sp = thread->stackStart;
dst.stack.size = (char *)thread->stackEnd - (char *)thread->stackStart;
dst.stack.align = 0x10000;
dst.sigmask = thread->sigMask;
copy(dst.mcontext, src.uc_mcontext);
}
static __attribute__((no_stack_protector)) void
handleSigSys(int sig, siginfo_t *info, void *ucontext) {
if (auto hostFs = _readgsbase_u64()) {
_writefsbase_u64(hostFs);
}
// rx::printStackTrace(reinterpret_cast<ucontext_t *>(ucontext),
// rx::thread::g_current, 1);
auto thread = orbis::g_currentThread;
auto prevContext = std::exchange(thread->context, ucontext);
{
std::lock_guard lock(thread->mtx);
copy(thread, thread->sigReturns.emplace_back(),
*reinterpret_cast<ucontext_t *>(ucontext));
}
if ((std::uint64_t)&thread < 0x100'0000'0000) {
ORBIS_LOG_ERROR("unexpected sigsys signal stack", thread->tid, sig,
(std::uint64_t)&thread);
std::abort();
}
auto altStack = malloc(getSigStackSize());
rx::thread::setupSignalStack(altStack);
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSYS);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
orbis::syscall_entry(thread);
pthread_sigmask(SIG_BLOCK, &set, NULL);
std::free(altStack);
if (thread == orbis::g_currentThread) {
std::lock_guard lock(thread->mtx);
thread->sigReturns.pop_back();
}
thread = orbis::g_currentThread;
thread->context = prevContext;
_writefsbase_u64(thread->fsBase);
}
__attribute__((no_stack_protector)) static void
handleSigUser(int sig, siginfo_t *info, void *ucontext) {
if (auto hostFs = _readgsbase_u64()) {
_writefsbase_u64(hostFs);
}
auto context = reinterpret_cast<ucontext_t *>(ucontext);
bool inGuestCode = context->uc_mcontext.gregs[REG_RIP] < 0x100'0000'0000;
auto thread = orbis::g_currentThread;
if ((std::uint64_t)&context < 0x100'0000'0000) {
ORBIS_LOG_ERROR("unexpected sigusr signal stack", thread->tid, sig,
inGuestCode, (std::uint64_t)&context);
std::abort();
}
int guestSignal = -3;
{
std::lock_guard lock(thread->mtx);
if (thread->signalQueue.empty()) {
ORBIS_LOG_ERROR("unexpected user signal", thread->tid, sig, inGuestCode);
return;
}
guestSignal = thread->signalQueue.front();
thread->signalQueue.pop_front();
copy(thread, thread->sigReturns.emplace_back(), *context);
}
if (guestSignal == -1) {
auto altStack = malloc(getSigStackSize());
rx::thread::setupSignalStack(altStack);
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGSYS);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
thread->suspended++;
// ORBIS_LOG_ERROR("suspending thread", thread->tid);
while (thread->suspended > 0) {
::sleep(1);
}
pthread_sigmask(SIG_BLOCK, &set, NULL);
free(altStack);
// ORBIS_LOG_ERROR("thread wake", thread->tid);
}
if (guestSignal == -2) {
// ORBIS_LOG_ERROR("thread resume signal", thread->tid);
std::lock_guard lock(thread->mtx);
thread->sigReturns.pop_back();
--thread->suspended;
}
if (inGuestCode) {
_writefsbase_u64(thread->fsBase);
}
copyContext(dst.mcontext, src.uc_mcontext);
}
void rx::thread::initialize() {
@ -233,12 +220,12 @@ void *rx::thread::setupSignalStack(void *address) {
if (address == NULL) {
std::fprintf(stderr, "attempt to set null signal stack, %p - %zx\n",
address, getSigStackSize());
address, getSigAltStackSize());
std::exit(EXIT_FAILURE);
}
ss.ss_sp = address;
ss.ss_size = getSigStackSize();
ss.ss_size = getSigAltStackSize();
ss.ss_flags = 1 << 31;
if (sigaltstack(&ss, &oss) == -1) {
@ -250,9 +237,9 @@ void *rx::thread::setupSignalStack(void *address) {
}
void *rx::thread::setupSignalStack() {
auto data = malloc(getSigStackSize());
auto data = malloc(getSigAltStackSize());
if (data == nullptr) {
std::fprintf(stderr, "malloc produces null, %zx\n", getSigStackSize());
std::println(stderr, "malloc produces null, {:x}", getSigAltStackSize());
std::exit(EXIT_FAILURE);
}
return setupSignalStack(data);

View file

@ -3,11 +3,15 @@
#include "orbis/thread/Thread.hpp"
namespace rx::thread {
std::size_t getSigAltStackSize();
void initialize();
void deinitialize();
void *setupSignalStack();
void *setupSignalStack(void *address);
void setupThisThread();
void copyContext(orbis::MContext &dst, const mcontext_t &src);
void copyContext(orbis::Thread *thread, orbis::UContext &dst,
const ucontext_t &src);
void invoke(orbis::Thread *thread);
} // namespace rx::thread

View file

@ -933,6 +933,7 @@ void *vm::map(void *addr, std::uint64_t len, std::int32_t prot,
}
if (auto thr = orbis::g_currentThread) {
std::lock_guard lock(orbis::g_context.gpuDeviceMtx);
if (auto gpu = amdgpu::DeviceCtl{orbis::g_context.gpuDevice}) {
gpu.submitMapMemory(thr->tproc->pid, address, len, -1, -1, prot,
address - kMinAddress);