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.