39#ifndef LELY_UTIL_FIBER_HPP_
40#define LELY_UTIL_FIBER_HPP_
82operator~(FiberFlag rhs) {
83 return static_cast<FiberFlag
>(~static_cast<int>(rhs));
87operator&(FiberFlag lhs, FiberFlag rhs) {
88 return static_cast<FiberFlag
>(
static_cast<int>(lhs) &
static_cast<int>(rhs));
92operator^(FiberFlag lhs, FiberFlag rhs) {
93 return static_cast<FiberFlag>(
static_cast<int>(lhs) ^
static_cast<int>(rhs));
97operator|(FiberFlag lhs, FiberFlag rhs) {
98 return static_cast<FiberFlag>(
static_cast<int>(lhs) |
static_cast<int>(rhs));
102operator&=(FiberFlag& lhs, FiberFlag rhs) {
103 return lhs = lhs & rhs;
107operator^=(FiberFlag& lhs, FiberFlag rhs) {
108 return lhs = lhs ^ rhs;
112operator|=(FiberFlag& lhs, FiberFlag rhs) {
113 return lhs = lhs | rhs;
123 bool terminated{
false};
125 ::std::exception_ptr eptr{
nullptr};
140 FiberThread() : FiberThread(static_cast<
FiberFlag>(0)) {}
149 explicit FiberThread(FiberFlag flags) {
164 FiberThread(FiberFlag flags,
bool& already) {
167 already = result != 0;
170 FiberThread(
const FiberThread&) =
delete;
171 FiberThread(FiberThread&&) =
delete;
173 FiberThread& operator=(
const FiberThread&) =
delete;
174 FiberThread& operator=(FiberThread&&) =
delete;
183 static detail::FiberData*
186 static detail::FiberData data_;
188 static thread_local detail::FiberData data_;
202 Fiber() noexcept = default;
204 Fiber(const Fiber&) = delete;
211 Fiber(Fiber&& other) noexcept { swap(other); }
216 template <
class F,
class = typename ::std::enable_if<!::std::is_same<
217 typename ::std::decay<F>::type, Fiber>::value>::type>
218 explicit Fiber(F&& f) : Fiber(::
std::forward<F>(f), 0) {}
222 Fiber(F&& f, FiberFlag flags) : Fiber(::
std::forward<F>(f), flags, 0) {}
226 Fiber(F&& f, ::std::size_t stack_size)
227 : Fiber(::
std::forward<F>(f), static_cast<
FiberFlag>(0), stack_size) {}
242 template <
class F,
class = typename ::std::enable_if<compat::is_invocable_r<
243 Fiber, F, Fiber&&>::value>::type>
244 Fiber(F&& f, FiberFlag flags, ::std::size_t stack_size) {
246 &func_<
decltype(f)>,
static_cast<void*
>(::std::addressof(f)),
247 static_cast<int>(flags),
sizeof(detail::FiberData), stack_size);
249 auto data = data_(fiber_);
251 new (data) detail::FiberData();
253 *
this = ::std::move(*this).resume();
255 auto eptr = data->eptr;
258 ::std::rethrow_exception(eptr);
262 Fiber& operator=(
const Fiber&) =
delete;
272 operator=(Fiber&& other)
noexcept {
293 auto data = data_(fiber_);
295 if (!data->terminated) {
297 *
this = ::std::move(*this).resume();
306 explicit operator bool() const noexcept {
return fiber_ !=
nullptr; }
308 operator fiber_t*() &&
noexcept {
329 return resume_(Fiber(
fiber_resume(::std::move(*
this))));
348 resume_with(F&& f) && {
352 f = (*
static_cast<F*
>(arg))(::std::move(f));
355 if (!data) data = FiberThread::data_();
356 data->eptr = ::std::current_exception();
358 return static_cast<fiber_t*
>(::std::move(f));
360 auto arg =
static_cast<void*
>(::std::addressof(f));
366 swap(Fiber& other)
noexcept {
368 swap(fiber_, other.fiber_);
375 static detail::FiberData*
380 Fiber resume_(Fiber&& f);
393 fiber_unwind() noexcept = default;
395 explicit fiber_unwind(Fiber&& f) noexcept : f_(::
std::move(f)) {}
407 using F_ = typename ::std::decay<F>::type;
408 F_ func{::std::forward<F_>(
static_cast<F
>(*
static_cast<F_*
>(arg)))};
415 if (data->eptr) ::std::rethrow_exception(data->eptr);
417 if (!data->unwind) f = func(::std::move(f));
418 }
catch (fiber_unwind& e) {
419 f = ::std::move(e.f_);
421 data->terminated =
true;
422 return ::std::move(f);
427 data->eptr = ::std::current_exception();
437Fiber::resume_(Fiber&& f) {
439 if (!data) data = FiberThread::data_();
444 auto eptr = data->eptr;
445 data->eptr =
nullptr;
447 if (data->unwind)
throw fiber_unwind(::std::move(f));
448 if (eptr) ::std::rethrow_exception(eptr);
450 return ::std::move(f);
This header file is part of the utilities library; it contains C++ convenience functions for creating...
void throw_errc(int errc=get_errc())
Throws an std::system_error exception corresponding to the specified or current (thread-specific) nat...
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).
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 FIBER_GUARD_STACK
A flag specifying a fiber to add a guard page when allocating the stack frame so that the kernel gene...
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.
#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_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...
void fiber_thrd_fini(void)
Finalizes the fiber associated with the calling thread.
#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...
fiber_t * fiber_resume(fiber_t *fiber)
Equivalent to fiber_resume_with(fiber, NULL, NULL).
void fiber_destroy(fiber_t *fiber)
Destroys the specified fiber.
FiberFlag
Specifies which properties of the calling environment are saved or restored by a fiber when it is sus...
@ SAVE_MASK
The fiber saves and restores the signal mask (only supported on POSIX platforms).
@ SAVE_ALL
The combination of FiberFlag::SAVE_MASK, FiberFlag::SAVE_FENV and FiberFlag::SAVE_ERROR that is suppo...
@ SAVE_FENV
The fiber saves and restores the floating-point environment.
@ GUARD_STACK
The fiber adds a guard page when allocating the stack frame so that the kernel generates a SIGSEGV si...
@ SAVE_ERROR
The fiber saves and restores the error values (i.e., errno and GetLastError() on Windows).
This header file is part of the compatibility library; it includes <type_traits> and defines any miss...