16 #include <system_error>
24 "main stack size is too small for sigjmp_buf!");
26 thread_local std::array<uintptr_t, SetJmp::kMainStackSize> SetJmp::gMainStack;
28 SetJmp::EntryContext *SetJmp::gCurrentlyPreparing{
nullptr};
29 std::mutex SetJmp::gSignalLock;
44 allocSize +=
sizeof(sigjmp_buf);
56 throw std::runtime_error(
"posix_memalign() failed");
60 throw std::runtime_error(
"failed to allocate stack");
64 this->
stack = {
reinterpret_cast<uintptr_t *
>(buf), allocSize /
sizeof(uintptr_t)};
65 this->ownsStack =
true;
83 _aligned_free(this->
stack.data());
85 free(this->
stack.data());
94 auto from =
static_cast<SetJmp *
>(_from);
96 if(!sigsetjmp(*SetJmp::JmpBufFor(from), 0)) {
97 std::atomic_thread_fence(std::memory_order_release);
98 siglongjmp(*SetJmp::JmpBufFor(
this), 1);
111 return new SetJmp(SetJmp::gMainStack);
120 void SetJmp::InvokeCothreadDidReturnHandler(
Cothread *from) {
139 struct sigaction handler, oldHandler;
140 stack_t
stack{}, oldStack{};
142 auto jbuf = JmpBufFor(thread);
143 memset(jbuf, 0,
sizeof(*jbuf));
146 auto offset =
sizeof(sigjmp_buf);
151 stack.ss_sp =
reinterpret_cast<std::byte *
>(thread->
stack.data()) + offset;
152 stack.ss_size = (thread->
stack.size() *
sizeof(uintptr_t)) - offset;
154 auto info =
new EntryContext( thread, entry);
155 if(!info)
throw std::runtime_error(
"Failed to allocate context");
159 std::lock_guard<std::mutex> lock(gSignalLock);
161 err = sigaltstack(&
stack, &oldStack);
163 throw std::system_error(errno, std::generic_category(),
"sigaltstack");
166 gCurrentlyPreparing = info;
167 std::atomic_thread_fence(std::memory_order_release);
169 handler.sa_handler = SignalHandlerSetupThunk;
170 handler.sa_flags = SA_ONSTACK;
171 sigemptyset(&handler.sa_mask);
173 err = sigaction(SIGUSR1, &handler, &oldHandler);
175 throw std::system_error(errno, std::generic_category(),
"sigaction");
177 err =
raise(SIGUSR1);
179 throw std::system_error(errno, std::generic_category(),
"raise");
181 sigaltstack(&oldStack,
nullptr);
182 sigaction(SIGUSR1, &oldHandler,
nullptr);
183 }
catch(
const std::exception &) {
200 void SetJmp::SignalHandlerSetupThunk(
int signal) {
203 auto ctx = gCurrentlyPreparing;
204 if(sigsetjmp(*JmpBufFor(ctx->impl), 0)) {
Instance of a single cooperative thread.
std::function< void()> Entry
Type alias for an entry point of a cothread.
static Cothread * Current()
Context switching utilizing the C library setjmp() and longjmp() methods.
static constexpr const size_t kStackAlignment
SetJmp(const Entry &entry, const size_t stackSize=0)
void switchTo(CothreadImpl *from) override
static constexpr const size_t kDefaultStackSize
static constexpr const size_t kMainStackSize
Implementation details (including architecture/platform specific code) for the library.
std::function< void(libcommunism::Cothread *)> gReturnHandler
Main namespace for the libcommunism library.
CothreadImpl * AllocKernelThreadWrapper()
Abstract interface for a platform implementation of cothreads.
std::span< uintptr_t > stack
Stack used by this cothread, if any.