Zth (libzth)
Loading...
Searching...
No Matches
context.h
Go to the documentation of this file.
1#ifndef ZTH_CONTEXT_H
2#define ZTH_CONTEXT_H
3/*
4 * SPDX-FileCopyrightText: 2019-2026 Jochem Rutgers
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 */
8
9#include <libzth/macros.h>
10
11#include <libzth/config.h>
12
36#ifdef ZTH_STACK_SWITCH
37EXTERN_C ZTH_EXPORT void*
38zth_stack_switch(void* stack, size_t size, void* (*f)(void*) noexcept, void* arg) noexcept;
39#else // !ZTH_STACK_SWITCH
40# define zth_stack_switch(stack, size, f, arg) \
41 ({ \
42 (void)(stack); \
43 (void)(size); \
44 ((f)(arg)); \
45 })
46#endif // !ZTH_STACK_SWITCH
47
48#ifdef __cplusplus
49# include <libzth/util.h>
50
51# if __cplusplus >= 201103L
52# include <tuple>
53# endif
54
55# if __cplusplus < 201103L
56# undef ZTH_STACK_SWITCH98
57// Always use C++98-compatible stack_switch() implementation.
58# define ZTH_STACK_SWITCH98 1
59# elif !defined(ZTH_STACK_SWITCH98)
60// By default only use C++11 stack_switch() implementation, but this can be
61// overridden for testing purposes.
62# define ZTH_STACK_SWITCH98 0
63# endif
64
65namespace zth {
66
67class Context;
68
70 typedef void* EntryArg;
71 typedef void (*Entry)(EntryArg);
72
73 constexpr explicit ContextAttr(Entry entry_ = nullptr, EntryArg arg_ = EntryArg()) noexcept
74 : stackSize(Config::DefaultFiberStackSize)
75 , entry(entry_)
76 , arg(arg_)
77 {}
78
79 size_t stackSize;
82};
83
84int context_init() noexcept;
85void context_deinit() noexcept;
86int context_create(Context*& context, ContextAttr const& attr) noexcept;
87void context_switch(Context* from, Context* to) noexcept;
88void context_destroy(Context* context) noexcept;
89size_t context_stack_usage(Context* context) noexcept;
90
91void stack_watermark_init(void* stack, size_t size) noexcept;
92size_t stack_watermark_size(void* stack) noexcept;
93size_t stack_watermark_maxused(void* stack) noexcept;
94size_t stack_watermark_remaining(void* stack) noexcept;
95
96
97
98namespace impl {
99
100# if ZTH_STACK_SWITCH98
101template <typename R>
102struct FunctionIO0 {
103 union {
104 struct {
105 R (*f)();
106 };
107 R r;
108 };
109
110 void* operator()()
111 {
112 r = f();
113 return &r;
114 }
115};
116
117template <>
118struct FunctionIO0<void> {
119 union {
120 struct {
121 void (*f)();
122 };
123 };
124
125 void* operator()()
126 {
127 f();
128 return nullptr;
129 }
130};
131
132template <typename R, typename A1>
133struct FunctionIO1 {
134 union {
135 struct {
136 R (*f)(A1);
137 A1 a1;
138 };
139 R r;
140 };
141
142 void* operator()()
143 {
144 r = f(a1);
145 return &r;
146 }
147};
148
149template <typename A1>
150struct FunctionIO1<void, A1> {
151 union {
152 struct {
153 void (*f)(A1);
154 A1 a1;
155 };
156 };
157
158 void* operator()()
159 {
160 f(a1);
161 return nullptr;
162 }
163};
164
165template <typename R, typename A1, typename A2>
166struct FunctionIO2 {
167 union {
168 struct {
169 R (*f)(A1, A2);
170 A1 a1;
171 A2 a2;
172 };
173 R r;
174 };
175
176 void* operator()()
177 {
178 r = f(a1, a2);
179 return &r;
180 }
181};
182
183template <typename A1, typename A2>
184struct FunctionIO2<void, A1, A2> {
185 union {
186 struct {
187 void (*f)(A1, A2);
188 A1 a1;
189 A2 a2;
190 };
191 };
192
193 void* operator()()
194 {
195 f(a1, a2);
196 return nullptr;
197 }
198};
199
200template <typename R, typename A1, typename A2, typename A3>
201struct FunctionIO3 {
202 union {
203 struct {
204 R (*f)(A1, A2, A3);
205 A1 a1;
206 A2 a2;
207 A3 a3;
208 };
209 R r;
210 };
211 void* operator()()
212 {
213 r = f(a1, a2, a3);
214 return &r;
215 }
216};
217
218template <typename A1, typename A2, typename A3>
219struct FunctionIO3<void, A1, A2, A3> {
220 union {
221 struct {
222 void (*f)(A1, A2, A3);
223 A1 a1;
224 A2 a2;
225 A3 a3;
226 };
227 };
228
229 void* operator()()
230 {
231 f(a1, a2, a3);
232 return nullptr;
233 }
234};
235
236# elif __cplusplus >= 201103L
237
238template <typename T>
239struct Packed {
240 using type = typename std::decay<T>::type;
241};
242
243template <typename T>
244struct Packed<T&> {
245 using type = std::reference_wrapper<typename std::decay<T>::type>;
246};
247
248template <typename... A>
249struct Arguments {
250 template <typename R>
251 using function_type = R(A...);
252 using tuple_type = std::tuple<typename Packed<A>::type...>;
253 constexpr static size_t size = sizeof...(A);
254};
255
256template <typename R, typename A, typename A_>
258 union {
259 struct {
260 typename A::template function_type<R>* f;
261 typename A_::tuple_type a;
262 };
264 };
265
266 void* operator()() noexcept
267 {
268 call(typename SequenceGenerator<A::size>::type(), A());
269 return &r;
270 }
271
272private:
273 template <size_t... S, typename... _A>
274 void call(Sequence<S...>, Arguments<_A...>) noexcept
275 {
276 r = f(std::forward<_A>(std::get<S>(a))...);
277 }
278};
279
280template <typename A, typename A_>
281struct FunctionION<void, A, A_> {
282 union {
283 struct {
284 typename A::template function_type<void>* f;
285 typename A_::tuple_type a;
286 };
287 };
288
289 void* operator()() noexcept
290 {
291 call(typename SequenceGenerator<A::size>::type(), A());
292 return nullptr;
293 }
294
295private:
296 template <size_t... S, typename... _A>
297 void call(Sequence<S...>, Arguments<_A...>) noexcept
298 {
299 f(std::forward<_A>(std::get<S>(a))...);
300 }
301};
302# endif // C++11
303
304template <typename F>
305void* stack_switch_fwd(void* f) noexcept
306{
307 return (*static_cast<F*>(f))();
308}
309
310} // namespace impl
311
312# if ZTH_STACK_SWITCH98
316template <typename R>
317inline R stack_switch(void* stack, size_t size, R (*f)())
318{
319 impl::FunctionIO0<R> f_ = {{f}};
320 return *static_cast<R*>(
321 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
322}
323
329inline void stack_switch(void* stack, size_t size, void (*f)())
330{
331 impl::FunctionIO0<void> f_ = {{f}};
332 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
333}
334
339template <typename R, typename A1>
340inline R stack_switch(void* stack, size_t size, R (*f)(A1), A1 a1)
341{
342 impl::FunctionIO1<R, A1> f_ = {{f, a1}};
343 return *static_cast<R*>(
344 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
345}
346
351template <typename A1>
352inline void stack_switch(void* stack, size_t size, void (*f)(A1), A1 a1)
353{
354 impl::FunctionIO1<void, A1> f_ = {{f, a1}};
355 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
356}
357
362template <typename R, typename A1, typename A2>
363inline R stack_switch(void* stack, size_t size, R (*f)(A1, A2), A1 a1, A2 a2)
364{
365 impl::FunctionIO2<R, A1, A2> f_ = {{f, a1, a2}};
366 return *static_cast<R*>(
367 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
368}
369
374template <typename A1, typename A2>
375inline void stack_switch(void* stack, size_t size, void (*f)(A1, A2), A1 a1, A2 a2)
376{
377 impl::FunctionIO2<void, A1, A2> f_ = {{f, a1, a2}};
378 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
379}
380
385template <typename R, typename A1, typename A2, typename A3>
386inline R stack_switch(void* stack, size_t size, R (*f)(A1, A2, A3), A1 a1, A2 a2, A3 a3)
387{
388 impl::FunctionIO3<R, A1, A2, A3> f_ = {{f, a1, a2, a3}};
389 return *static_cast<R*>(
390 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
391}
392
397template <typename A1, typename A2, typename A3>
398inline void stack_switch(void* stack, size_t size, void (*f)(A1, A2, A3), A1 a1, A2 a2, A3 a3)
399{
400 impl::FunctionIO3<void, A1, A2, A3> f_ = {{f, a1, a2, a3}};
401 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
402}
403
404# elif __cplusplus >= 201103L // !ZTH_STACK_SWITCH98
405
411template <typename R, typename... A, typename... A_>
412inline typename std::enable_if<!std::is_void<R>::value, R>::type
413stack_switch(void* stack, size_t size, R (*f)(A...) noexcept, A_&&... a) noexcept
414{
416 {f, {std::forward<A_>(a)...}}};
417 return std::move(*static_cast<typename impl::Packed<R>::type*>(
418 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_)));
419}
420
426template <typename... A, typename... A_>
427inline void stack_switch(void* stack, size_t size, void (*f)(A...) noexcept, A_&&... a) noexcept
428{
429 impl::FunctionION<void, impl::Arguments<A...>, impl::Arguments<A_&&...>> f_{
430 {f, {std::forward<A_>(a)...}}};
431 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
432}
433# endif // !ZTH_STACK_SWITCH98
434
435} // namespace zth
436#endif // __cplusplus
437#endif // ZTH_CONTEXT_H
#define zth_stack_switch(stack, size, f, arg)
Call the function f using the new stack pointer.
Definition context.h:40
std::enable_if<!std::is_void< R >::value, R >::type stack_switch(void *stack, size_t size, R(*f)(A...) noexcept, A_ &&... a) noexcept
Call the function f using the new stack pointer.
Definition context.h:413
void * stack_switch_fwd(void *f) noexcept
Definition context.h:305
int context_init() noexcept
One-time context mechanism initialization.
Definition context.cpp:29
The configuration of Zth.
Definition zth_config.h:26
constexpr ContextAttr(Entry entry_=nullptr, EntryArg arg_=EntryArg()) noexcept
Definition context.h:73
EntryArg arg
Definition context.h:81
size_t stackSize
Definition context.h:79
void * EntryArg
Definition context.h:70
void(* Entry)(EntryArg)
Definition context.h:71
R(A...) function_type
Definition context.h:251
std::tuple< typename Packed< A >::type... > tuple_type
Definition context.h:252
A::template function_type< void > * f
Definition context.h:284
Packed< R >::type r
Definition context.h:263
A_::tuple_type a
Definition context.h:261
void * operator()() noexcept
Definition context.h:266
A::template function_type< R > * f
Definition context.h:260
std::reference_wrapper< typename std::decay< T >::type > type
Definition context.h:245
typename std::decay< T >::type type
Definition context.h:240