44#if !_WIN32 && !defined(__NEWLIB__)
51#elif _POSIX_MAPPED_FILES
56#if !_WIN32 && LELY_HAVE_VALGRIND
57#include <valgrind/valgrind.h>
60#ifndef LELY_FIBER_MINSTKSZ
63#define LELY_FIBER_MINSTKSZ MINSIGSTKSZ
65#define LELY_FIBER_MINSTKSZ 8192
67#define LELY_FIBER_MINSTKSZ 4096
71#ifndef LELY_FIBER_STKSZ
73#define LELY_FIBER_STKSZ 131072
76#if !_WIN32 && _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
99static void *guard_mmap(
void *addr,
size_t len,
int prot);
107static void guard_munmap(
void *addr,
size_t len);
112#if _POSIX_C_SOURCE >= 200112L && (!defined(__NEWLIB__) || defined(__CYGWIN__))
117static inline void sigjmpto(sigjmp_buf from, sigjmp_buf to,
int savemask);
123static inline void jmpto(jmp_buf from, jmp_buf to);
147#if _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
156#if LELY_HAVE_VALGRIND
160#if _POSIX_C_SOURCE >= 200112L && (!defined(__NEWLIB__) || defined(__CYGWIN__))
170#define FIBER_ALIGNOF _Alignof(max_align_t)
171#define FIBER_SIZEOF ALIGN(sizeof(fiber_t), FIBER_ALIGNOF)
226 dwFlags |= FIBER_FLAG_FLOAT_SWITCH;
227 assert(!thr->
main.lpFiber);
228 thr->
main.lpFiber = ConvertThreadToFiberEx(NULL, dwFlags);
229 if (!thr->
main.lpFiber)
251 assert(thr->
main.lpFiber);
252 ConvertFiberToThread();
253 thr->
main.lpFiber = NULL;
266#if !_WIN32 && _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
275 data_size =
ALIGN(data_size, FIBER_ALIGNOF);
281 stack_size =
ALIGN(stack_size, FIBER_ALIGNOF);
283 size_t size = FIBER_SIZEOF + data_size;
285#if _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
298 goto error_malloc_fiber;
316#if _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
317 fiber->stack_size = 0;
318 fiber->stack_addr = NULL;
324 fiber->stack_size = stack_size;
325 fiber->stack_addr = guard_mmap(NULL,
fiber->stack_size,
326 PROT_READ | PROT_WRITE);
327 if (!
fiber->stack_addr) {
329 goto error_create_stack;
331 sp =
fiber->stack_addr;
335#if LELY_HAVE_VALGRIND
337 fiber->id = VALGRIND_STACK_REGISTER(sp, (
char *)sp + stack_size);
345 dwFlags |= FIBER_FLAG_FLOAT_SWITCH;
346 fiber->lpFiber = CreateFiberEx(
348 if (!
fiber->lpFiber) {
350 goto error_CreateFiberEx;
353#if _POSIX_C_SOURCE >= 200112L && (!defined(__NEWLIB__) || defined(__CYGWIN__))
356 fiber, sp, stack_size) == -1) {
379#if LELY_HAVE_VALGRIND
380 VALGRIND_STACK_DEREGISTER(
fiber->id);
382#if _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
384 if (
fiber->stack_addr)
385 guard_munmap(
fiber->stack_addr,
fiber->stack_size);
401 DeleteFiber(
fiber->lpFiber);
403#if LELY_HAVE_VALGRIND
404 VALGRIND_STACK_DEREGISTER(
fiber->id);
406#if _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
407 if (
fiber->stack_addr)
408 guard_munmap(
fiber->stack_addr,
fiber->stack_size);
460 dwErrCode = GetLastError();
472#if !_WIN32 && !defined(__NEWLIB__)
484 SwitchToFiber(to->lpFiber);
485#elif _POSIX_C_SOURCE >= 200112L \
486 && (!defined(__NEWLIB__) || defined(__CYGWIN__))
497#if !_WIN32 && !defined(__NEWLIB__)
506 SetLastError(dwErrCode);
525#if !_WIN32 && _POSIX_MAPPED_FILES && defined(MAP_ANONYMOUS)
528guard_mmap(
void *addr,
size_t len,
int prot)
531 page_size = sysconf(_SC_PAGE_SIZE);
532 assert(page_size > 0);
537 addr = (
char *)addr - page_size;
540 len =
ALIGN(len, page_size);
546 addr = mmap(addr, len + 2 * page_size, prot,
547 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
548 if (addr == MAP_FAILED) {
552 addr = (
char *)addr + page_size;
555 if (mprotect((
char *)addr - page_size, page_size, PROT_NONE) == -1) {
560 if (mprotect((
char *)addr + len, page_size, PROT_NONE) == -1) {
568 munmap((
char *)addr - page_size, len + 2 * page_size);
575guard_munmap(
void *addr,
size_t len)
578 assert(page_size > 0);
581 len =
ALIGN(len, page_size);
583 munmap((
char *)addr - page_size, len + 2 * page_size);
590#if _POSIX_C_SOURCE >= 200112L && (!defined(__NEWLIB__) || defined(__CYGWIN__))
592sigjmpto(sigjmp_buf from, sigjmp_buf to,
int savemask)
594 if (!sigsetjmp(from, savemask))
599jmpto(jmp_buf from, jmp_buf to)
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_INVAL
Invalid argument.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
#define _Thread_local
An object whose identifier is declared with the storage-class specifier _Thread_local has thread stor...
#define _Noreturn
A function declared with a _Noreturn function specifier SHALL not return to its caller.
fiber_t * fiber_resume_with(fiber_t *fiber, fiber_func_t *func, void *arg)
Suspends the calling fiber and resumes the specified fiber, optionally executing a function before re...
#define LELY_FIBER_MINSTKSZ
The minimum size (in bytes) of a fiber stack frame.
void * fiber_data(const fiber_t *fiber)
Returns a pointer to the data region of the specified fiber, or of the calling fiber if fiber is NULL...
int fiber_thrd_init(int flags)
Initializes the fiber associated with the calling thread.
fiber_t * fiber_create(fiber_func_t *func, void *arg, int flags, size_t data_size, size_t stack_size)
Creates a new fiber, allocates a stack and sets up a calling environment to begin executing the speci...
static void sigjmpto(sigjmp_buf from, sigjmp_buf to, int savemask)
Saves the from calling environment with sigsetjmp(from, savemask) and restores the to calling environ...
void fiber_thrd_fini(void)
Finalizes the fiber associated with the calling thread.
static _Noreturn void fiber_start(void *arg)
The function running in a fiber.
fiber_t * fiber_resume(fiber_t *fiber)
Equivalent to fiber_resume_with(fiber, NULL, NULL).
#define LELY_FIBER_STKSZ
The default size (in bytes) of a fiber stack frame.
void fiber_destroy(fiber_t *fiber)
Destroys the specified fiber.
This header file is part of the utilities library; it contains the fiber declarations.
#define FIBER_SAVE_MASK
A flag specifying a fiber to save and restore the signal mask (only supported on POSIX platforms).
#define FIBER_GUARD_STACK
A flag specifying a fiber to add a guard page when allocating the stack frame so that the kernel gene...
#define FIBER_SAVE_ERROR
A flag specifying a fiber to save and restore the error values (i.e., errno and GetLastError() on Win...
fiber_t * fiber_func_t(fiber_t *fiber, void *arg)
The type of the function executed by a fiber.
#define FIBER_SAVE_FENV
A flag specifying a fiber to save and restore the floating-point environment.
#define FIBER_SAVE_ALL
A combination of those flags in FIBER_SAVE_MASK, FIBER_SAVE_FENV and FIBER_SAVE_ERROR that are suppor...
This is the public header file of the utilities library.
#define powerof2(x)
Returns 1 if x is a power of two, and 0 otherwise.
#define ALIGN(x, a)
Rounds x up to the nearest multiple of a.
This header file is part of the utilities library; it contains the mkjmp() and sigmkjmp() function de...
int mkjmp(jmp_buf env, void(*func)(void *), void *arg, void *sp, size_t size)
Creates and stores a calling environment with a user-provided stack suitable for use by longjmp().
int sigmkjmp(sigjmp_buf env, int savemask, void(*func)(void *), void *arg, void *sp, size_t size)
Creates and stores a calling environment with a user-provided stack suitable for use by siglongjmp().
This is the internal header file of the utilities library.
This header file is part of the C11 and POSIX compatibility library; it includes <stddef....
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A thread-local struct containing the fiber associated with the thread and a pointer to the fiber curr...
size_t refcnt
The reference counter tracking the number of calls to fiber_thrd_init() minus those to fiber_thrd_fin...
fiber_t * curr
A pointer to the fiber currently running on this thread.
fiber_t main
The fiber representing this thread.
int flags
The flags provided to fiber_create().
void * arg
The second argument supplied to func.
void * data
A pointer to the data region.
struct fiber_thrd * thr
A pointer to the thread that resumed this fiber.
fiber_func_t * func
A pointer to the function to be executed in the fiber.
fiber_t * from
A pointer to the now suspended fiber that resumed this fiber.
sigjmp_buf env
The saved registers and signal mask.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd....