1 #ifndef ZTH_CONTEXT_CONTEXT_H
2 #define ZTH_CONTEXT_CONTEXT_H
32 # ifndef ZTH_OS_WINDOWS
37 # include <sys/mman.h>
43 # ifdef ZTH_HAVE_VALGRIND
44 # include <valgrind/memcheck.h>
47 # ifdef ZTH_ENABLE_ASAN
48 # include <sanitizer/common_interface_defs.h>
70 template <
typename Impl>
76 # ifdef ZTH_ENABLE_ASAN
95 return static_cast<Impl&
>(*this);
101 Impl
const&
impl() const noexcept
103 return static_cast<Impl const&
>(*this);
112 :
p(
static_cast<char*
>(
p))
121 constexpr
operator bool() const noexcept
123 return p !=
nullptr &&
size > 0;
167 m_stackUsable =
Stack();
169 if(
attr().stackSize == 0)
178 impl().valgrindRegister();
182 impl().deallocStack(m_stack);
194 impl().stackGuardDeinit();
195 impl().valgrindDeregister();
196 impl().deinitStack(m_stack);
197 m_stackUsable = m_stack =
Stack();
207 size_t const page =
impl().pageSize();
208 zth_assert(__builtin_popcount((
unsigned int)page) == 1);
221 impl().stackAlign(usable);
241 # ifdef ZTH_HAVE_MMAN
242 (size_t)sysconf(_SC_PAGESIZE);
262 return m_stackUsable;
270 # ifndef ZTH_OS_WINDOWS
274 # ifdef ZTH_HAVE_MMAN
277 size +=
impl().pageSize() * 2;
294 # ifdef ZTH_HAVE_MMAN
297 mmap(
nullptr, size, PROT_READ | PROT_WRITE,
298 MAP_PRIVATE | MAP_ANONYMOUS |
MAP_STACK, -1, 0);
303 if(
unlikely((p = (
void*)allocate_noexcept<char>(size)) ==
nullptr)) {
320 # ifdef ZTH_HAVE_MMAN
338 size_t const ps =
impl().pageSize();
341 uintptr_t stack_old = (uintptr_t)
stack.
p;
348 uintptr_t stack_new = ((uintptr_t)(stack_old + ps - 1u) & ~(ps - 1u));
351 # ifdef ZTH_HAVE_MMAN
361 stack.
p = (
char*)stack_new;
369 # ifdef ZTH_USE_VALGRIND
373 m_valgrind_stack_id = VALGRIND_STACK_REGISTER(
374 m_stackUsable.
p, m_stackUsable.
p + m_stackUsable.
size - 1u);
376 if(RUNNING_ON_VALGRIND)
377 zth_dbg(context,
"[%s] Stack of context %p has Valgrind id %u",
387 # ifdef ZTH_USE_VALGRIND
388 VALGRIND_STACK_DEREGISTER(m_valgrind_stack_id);
389 m_valgrind_stack_id = 0;
398 # ifdef ZTH_HAVE_MMAN
403 size_t const ps =
impl().pageSize();
405 if(
unlikely(mprotect(m_stackUsable.
p - ps, ps, PROT_NONE)))
407 if(
unlikely(mprotect(m_stackUsable.
p + m_stackUsable.
size, ps, PROT_NONE)))
430 return reinterpret_cast<uintptr_t
>(&i) <
reinterpret_cast<uintptr_t
>(reference);
475 static void set_sp(jmp_buf& env,
void**
sp) noexcept;
480 static void set_pc(jmp_buf& env,
void*
sp) noexcept;
513 # ifdef ZTH_ENABLE_ASAN
523 # ifdef ZTH_ENABLE_ASAN
545 # ifdef ZTH_USE_VALGRIND
547 unsigned int m_valgrind_stack_id;
549 # ifdef ZTH_ENABLE_ASAN
555 template <
typename Impl>
556 static Impl* current_context() noexcept;
561 # if defined(ZTH_ARCH_ARM)
569 # if defined(ZTH_CONTEXT_SIGALTSTACK)
571 # elif defined(ZTH_CONTEXT_SJLJ)
573 # elif defined(ZTH_CONTEXT_UCONTEXT)
575 # elif defined(ZTH_CONTEXT_WINFIBER)
578 # error Unknown context switching approach.
Base class of the Context.
static void stack_push(void **&sp, void *p) noexcept
Push data into the stack.
void stackGuardDeinit() noexcept
Release the guards around the memory.
static size_t pageSize() noexcept
Get system's page size.
static bool stackGrowsDown(void const *reference)
Checks if the stack grows down or up.
void context_pop_regs() noexcept
Post-sjlj context restoring.
Stack const & stack() const noexcept
Return the stack address.
static void deinit() noexcept
Final system cleanup.
int initStack(Stack &stack, Stack &usable) noexcept
Allocate and initialize stack.
void * stack_switch(void *stack, size_t size, void *(*f)(void *) noexcept, void *arg) noexcept
int stackGuardInit() noexcept
Initialize guards around the stack memory.
void die() noexcept
Flag fiber as died after it returned from context_entry().
void stackGuard() noexcept
Configure the guard for the current fiber.
static void set_sp(jmp_buf &env, void **sp) noexcept
Set the stack pointer in a jmp_buf.
Impl & impl() noexcept
Return Impl this.
static void context_trampoline_from_jmp_buf()
Entry point to jump to from a (sig)jmp_buf.
void context_prepare_jmp(Impl &to, jmp_buf &env) noexcept
Pre-sjlj jump.
static void set_pc(jmp_buf &env, void *sp) noexcept
Set the program counter in a jmp_buf.
ContextAttr const & attr() const noexcept
Return the context attributes, requested by the user.
int create() noexcept
Create context.
void * allocStack(size_t size) noexcept
Allocate requested size of stack memory.
void deallocStack(Stack &stack) noexcept
Frees the previously allocated stack.
void * stackGuard(void *p) noexcept
Configure the guard for the address.
void valgrindRegister() noexcept
Register the current stack to valgrind.
static void ** sp(Stack const &stack) noexcept
Get the initial stack pointer for the given stack.
Impl const & impl() const noexcept
Return Impl this.
void context_switch(Context &to) noexcept
Perform a context switch.
ContextAttr & attr() noexcept
Return the context attributes, requested by the user.
void stackGuard(Stack const &stack) noexcept
Configure the guard for the given stack.
void destroy() noexcept
Destroy and cleanup context.
Stack const & stackUsable() const noexcept
Return the start of the actual usable stack.
void deinitStack(Stack &stack) noexcept
Deinit and free stack.
void stackAlign(Stack &stack) noexcept
Compute and modify the stack alignment and size, within the allocated space.
void valgrindDeregister() noexcept
Deregister the current stack from valgrind.
bool alive() const noexcept
Check if fiber is still running.
size_t calcStackSize(size_t size) noexcept
Compute the stack size, given the requested user size and current configuration.
constexpr ContextBase(ContextAttr const &attr) noexcept
void context_push_regs() noexcept
Pre-sjlj context saving.
static int init() noexcept
One-time system initialization.
Worker & currentWorker() noexcept
Return the (thread-local) singleton Worker instance.
void stack_watermark_init(void *stack, size_t size) noexcept
Initialize the memory region for stack high water marking.
#define zth_dbg(group, fmt, a...)
Debug printf()-like function.
void context_entry(Context *context)
static bool const EnableStackGuard
When true, enable stack guards.
constexpr Stack(size_t size=0) noexcept
constexpr Stack(void *p, size_t size) noexcept
#define zth_assert(expr)
assert(), but better integrated in Zth.
#define ZTH_CLASS_NOCOPY(Class)
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.