libcommunism
Userspace cooperative threading library
Windows.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 
20 const size_t Amd64::kNumSavedRegisters{ 8 + (10 * 2) };
21 
29 void Amd64::ValidateStackSize(const size_t size) {
30  if (!size) throw std::runtime_error("Size may not be nil");
31  if (size % kStackAlignment) throw std::runtime_error("Stack is misaligned");
32 }
33 
47 void* Amd64::AllocStack(const size_t bytes) {
48  auto ret = _aligned_malloc(bytes, kStackAlignment);
49  if (!ret) {
50  throw std::runtime_error("failed to allocate stack");
51  }
52  return ret;
53 }
54 
62 void Amd64::DeallocStack(void* stack) {
63  _aligned_free(stack);
64 }
65 
81 void Amd64::Prepare(Amd64 *wrap, const Cothread::Entry& entry) {
82  static_assert(offsetof(Amd64, stackTop) == COTHREAD_OFF_CONTEXT_TOP, "cothread stack top is invalid");
83 
84  // build the context structure we pass to our "fake" entry point
85  auto info = new CallInfo{ entry };
86  if (!info) throw std::runtime_error("Failed to allocate call info");
87 
88  // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
89  // prepare some space for a stack frame (zeroed registers; four function call params)
90  auto& stackBuf = wrap->stack;
91  auto stackFrame = reinterpret_cast<std::byte*>(stackBuf.data());
92  stackFrame += ((stackBuf.size() * sizeof(uintptr_t)) & ~(0x10 - 1))
93  - (sizeof(uintptr_t) * (4 + kNumSavedRegisters));
94  auto stack = reinterpret_cast<uintptr_t*>(stackFrame);
95 
96  // method to execute if main method returns
97  *--stack = reinterpret_cast<uintptr_t>(&Amd64::EntryReturnedStub);
98 
99  // and then jump to the stub that calls the entry point
100  *--stack = reinterpret_cast<uintptr_t>(info);
101  *--stack = reinterpret_cast<uintptr_t>(&Amd64::DereferenceCallInfo);
102  *--stack = reinterpret_cast<uintptr_t>(&Amd64::JumpToEntry);
103  // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
104 
105  // clear the region that registers are written into (so they're all zeroed)
106  for (size_t i = 0; i < kNumSavedRegisters; i++) {
107  *--stack = 0;
108  }
109 
110  // restore the stack pointer to the correct point
111  wrap->stackTop = stack;
112 }
std::function< void()> Entry
Type alias for an entry point of a cothread.
Definition: Cothread.h:27
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