libcommunism
Userspace cooperative threading library
SysV.cpp
Go to the documentation of this file.
1 
4 #include "Common.h"
5 #include "CothreadPrivate.h"
6 
7 #include "SysV.S"
8 
9 #include <cstddef>
10 #include <stdexcept>
11 
12 using namespace libcommunism;
13 using namespace libcommunism::internal;
14 
18 const size_t Amd64::kNumSavedRegisters{6};
19 
27 void Amd64::ValidateStackSize(const size_t size) {
28  if(!size) throw std::runtime_error("Size may not be nil");
29  if(size % kStackAlignment) throw std::runtime_error("Stack is misaligned");
30 }
31 
42 void* Amd64::AllocStack(const size_t bytes) {
43  void* buf{ nullptr };
44  int err{ -1 };
45 
46  err = posix_memalign(&buf, kStackAlignment, bytes);
47  if (err) {
48  throw std::runtime_error("posix_memalign() failed");
49  }
50 
51  return buf;
52 }
53 
61 void Amd64::DeallocStack(void* stack) {
62  free(stack);
63 }
64 
80 void Amd64::Prepare(Amd64 *wrap, const Entry &entry) {
81  static_assert(offsetof(Amd64, stackTop) == COTHREAD_OFF_CONTEXT_TOP, "cothread stack top is invalid");
82 
83  // build the context structure we pass to our "fake" entry point
84  auto info = new CallInfo{entry};
85  if(!info) throw std::runtime_error("Failed to allocate call info");
86 
87  // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
88  // prepare some space for a stack frame (zeroed registers; four function call params)
89  auto &stackBuf = wrap->stack;
90  auto stackFrame = reinterpret_cast<std::byte *>(stackBuf.data());
91  stackFrame += ((stackBuf.size()*sizeof(typeof(*stackBuf.data()))) & ~(0x10-1))
92  - (sizeof(uintptr_t) * (4 + kNumSavedRegisters));
93  auto stack = reinterpret_cast<uintptr_t *>(stackFrame);
94 
95  // method to execute if main method returns
96  *--stack = reinterpret_cast<uintptr_t>(&Amd64::EntryReturnedStub);
97 
98  // and then jump to the stub that calls the entry point
99  *--stack = reinterpret_cast<uintptr_t>(info);
100  *--stack = reinterpret_cast<uintptr_t>(&Amd64::DereferenceCallInfo);
101  *--stack = reinterpret_cast<uintptr_t>(&Amd64::JumpToEntry);
102  // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
103 
104  // clear the region that registers are written into (so they're all zeroed)
105  for(size_t i = 0; i < kNumSavedRegisters; i++) {
106  *--stack = 0;
107  }
108 
109  // restore the stack pointer to the correct point
110  wrap->stackTop = stack;
111 }
112 
Architecture specific methods for working with cothreads on amd64 based systems.
Definition: Common.h:16
static const size_t kNumSavedRegisters
Definition: Common.h:120
static constexpr const size_t kStackAlignment
Definition: Common.h:137
Implementation details (including architecture/platform specific code) for the library.
Definition: Common.h:11
Main namespace for the libcommunism library.
Definition: Common.h:11
std::span< uintptr_t > stack
Stack used by this cothread, if any.
Definition: CothreadImpl.h:88