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 {};