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(
74 Entry entry_ = nullptr, EntryArg arg_ = EntryArg(),
75 size_t stackSize_ = Config::DefaultFiberStackSize) noexcept
76 : entry(entry_)
77 , arg(arg_)
78 , stackSize(stackSize_)
79 {}
80
83 size_t stackSize;
84};
85
89struct Stack {
90 constexpr Stack(void* p_, size_t size_) noexcept
91 : p(static_cast<char*>(p_))
92 , size(size_)
93 {}
94
95 constexpr explicit Stack(size_t size_ = 0) noexcept
96 : p()
97 , size(size_)
98 {}
99
100 constexpr operator bool() const noexcept
101 {
102 return p != nullptr && size > 0;
103 }
104
105 char* p;
106 size_t size;
107};
108
109int context_init() noexcept;
110void context_deinit() noexcept;
111int context_create(Context*& context, ContextAttr const& attr) noexcept;
112void context_switch(Context* from, Context* to) noexcept;
113void context_destroy(Context* context) noexcept;
114size_t context_stack_usage(Context* context) noexcept;
115
116void stack_watermark_init(void* stack, size_t size) noexcept;
117size_t stack_watermark_size(void* stack) noexcept;
118size_t stack_watermark_maxused(void* stack) noexcept;
119size_t stack_watermark_remaining(void* stack) noexcept;
120
121
122
123namespace impl {
124
125# if ZTH_STACK_SWITCH98
126template <typename R>
127struct FunctionIO0 {
128 union {
129 struct {
130 R (*f)();
131 };
132 R r;
133 };
134
135 void* operator()()
136 {
137 r = f();
138 return &r;
139 }
140};
141
142template <>
143struct FunctionIO0<void> {
144 union {
145 struct {
146 void (*f)();
147 };
148 };
149
150 void* operator()()
151 {
152 f();
153 return nullptr;
154 }
155};
156
157template <typename R, typename A1>
158struct FunctionIO1 {
159 union {
160 struct {
161 R (*f)(A1);
162 A1 a1;
163 };
164 R r;
165 };
166
167 void* operator()()
168 {
169 r = f(a1);
170 return &r;
171 }
172};
173
174template <typename A1>
175struct FunctionIO1<void, A1> {
176 union {
177 struct {
178 void (*f)(A1);
179 A1 a1;
180 };
181 };
182
183 void* operator()()
184 {
185 f(a1);
186 return nullptr;
187 }
188};
189
190template <typename R, typename A1, typename A2>
191struct FunctionIO2 {
192 union {
193 struct {
194 R (*f)(A1, A2);
195 A1 a1;
196 A2 a2;
197 };
198 R r;
199 };
200
201 void* operator()()
202 {
203 r = f(a1, a2);
204 return &r;
205 }
206};
207
208template <typename A1, typename A2>
209struct FunctionIO2<void, A1, A2> {
210 union {
211 struct {
212 void (*f)(A1, A2);
213 A1 a1;
214 A2 a2;
215 };
216 };
217
218 void* operator()()
219 {
220 f(a1, a2);
221 return nullptr;
222 }
223};
224
225template <typename R, typename A1, typename A2, typename A3>
226struct FunctionIO3 {
227 union {
228 struct {
229 R (*f)(A1, A2, A3);
230 A1 a1;
231 A2 a2;
232 A3 a3;
233 };
234 R r;
235 };
236 void* operator()()
237 {
238 r = f(a1, a2, a3);
239 return &r;
240 }
241};
242
243template <typename A1, typename A2, typename A3>
244struct FunctionIO3<void, A1, A2, A3> {
245 union {
246 struct {
247 void (*f)(A1, A2, A3);
248 A1 a1;
249 A2 a2;
250 A3 a3;
251 };
252 };
253
254 void* operator()()
255 {
256 f(a1, a2, a3);
257 return nullptr;
258 }
259};
260
261# elif __cplusplus >= 201103L
262
263template <typename T>
264struct Packed {
265 using type = typename std::decay<T>::type;
266};
267
268template <typename T>
269struct Packed<T&> {
270 using type = std::reference_wrapper<typename std::decay<T>::type>;
271};
272
273template <typename... A>
274struct Arguments {
275 template <typename R>
276 using function_type = R(A...);
277 using tuple_type = std::tuple<typename Packed<A>::type...>;
278 constexpr static size_t size = sizeof...(A);
279};
280
281template <typename R, typename A, typename A_>
283 union {
284 struct {
285 typename A::template function_type<R>* f;
286 typename A_::tuple_type a;
287 };
289 };
290
291 void* operator()() noexcept
292 {
293 call(typename SequenceGenerator<A::size>::type(), A());
294 return &r;
295 }
296
297private:
298 template <size_t... S, typename... _A>
299 void call(Sequence<S...>, Arguments<_A...>) noexcept
300 {
301 r = f(std::forward<_A>(std::get<S>(a))...);
302 }
303};
304
305template <typename A, typename A_>
306struct FunctionION<void, A, A_> {
307 union {
308 struct {
309 typename A::template function_type<void>* f;
310 typename A_::tuple_type a;
311 };
312 };
313
314 void* operator()() noexcept
315 {
316 call(typename SequenceGenerator<A::size>::type(), A());
317 return nullptr;
318 }
319
320private:
321 template <size_t... S, typename... _A>
322 void call(Sequence<S...>, Arguments<_A...>) noexcept
323 {
324 f(std::forward<_A>(std::get<S>(a))...);
325 }
326};
327# endif // C++11
328
329template <typename F>
330void* stack_switch_fwd(void* f) noexcept
331{
332 return (*static_cast<F*>(f))();
333}
334
335} // namespace impl
336
337# if ZTH_STACK_SWITCH98
341template <typename R>
342inline R stack_switch(void* stack, size_t size, R (*f)())
343{
344 impl::FunctionIO0<R> f_ = {{f}};
345 return *static_cast<R*>(
346 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
347}
348
354inline void stack_switch(void* stack, size_t size, void (*f)())
355{
356 impl::FunctionIO0<void> f_ = {{f}};
357 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
358}
359
364template <typename R, typename A1>
365inline R stack_switch(void* stack, size_t size, R (*f)(A1), A1 a1)
366{
367 impl::FunctionIO1<R, A1> f_ = {{f, a1}};
368 return *static_cast<R*>(
369 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
370}
371
376template <typename A1>
377inline void stack_switch(void* stack, size_t size, void (*f)(A1), A1 a1)
378{
379 impl::FunctionIO1<void, A1> f_ = {{f, a1}};
380 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
381}
382
387template <typename R, typename A1, typename A2>
388inline R stack_switch(void* stack, size_t size, R (*f)(A1, A2), A1 a1, A2 a2)
389{
390 impl::FunctionIO2<R, A1, A2> f_ = {{f, a1, a2}};
391 return *static_cast<R*>(
392 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
393}
394
399template <typename A1, typename A2>
400inline void stack_switch(void* stack, size_t size, void (*f)(A1, A2), A1 a1, A2 a2)
401{
402 impl::FunctionIO2<void, A1, A2> f_ = {{f, a1, a2}};
403 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
404}
405
410template <typename R, typename A1, typename A2, typename A3>
411inline R stack_switch(void* stack, size_t size, R (*f)(A1, A2, A3), A1 a1, A2 a2, A3 a3)
412{
413 impl::FunctionIO3<R, A1, A2, A3> f_ = {{f, a1, a2, a3}};
414 return *static_cast<R*>(
415 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_));
416}
417
422template <typename A1, typename A2, typename A3>
423inline void stack_switch(void* stack, size_t size, void (*f)(A1, A2, A3), A1 a1, A2 a2, A3 a3)
424{
425 impl::FunctionIO3<void, A1, A2, A3> f_ = {{f, a1, a2, a3}};
426 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
427}
428
429# elif __cplusplus >= 201103L // !ZTH_STACK_SWITCH98
430
436template <typename R, typename... A, typename... A_>
437inline typename std::enable_if<!std::is_void<R>::value, R>::type
438stack_switch(void* stack, size_t size, R (*f)(A...) noexcept, A_&&... a) noexcept
439{
441 {f, {std::forward<A_>(a)...}}};
442 return std::move(*static_cast<typename impl::Packed<R>::type*>(
443 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_)));
444}
445
451template <typename... A, typename... A_>
452inline void stack_switch(void* stack, size_t size, void (*f)(A...) noexcept, A_&&... a) noexcept
453{
454 impl::FunctionION<void, impl::Arguments<A...>, impl::Arguments<A_&&...>> f_{
455 {f, {std::forward<A_>(a)...}}};
456 zth_stack_switch(stack, size, &impl::stack_switch_fwd<decltype(f_)>, &f_);
457}
458# endif // !ZTH_STACK_SWITCH98
459
460} // namespace zth
461#endif // __cplusplus
462#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:438
void * stack_switch_fwd(void *f) noexcept
Definition context.h:330
int context_init() noexcept
One-time context mechanism initialization.
Definition context.cpp:29
EntryArg arg
Definition context.h:82
constexpr ContextAttr(Entry entry_=nullptr, EntryArg arg_=EntryArg(), size_t stackSize_=Config::DefaultFiberStackSize) noexcept
Definition context.h:73
size_t stackSize
Definition context.h:83
void * EntryArg
Definition context.h:70
void(* Entry)(EntryArg)
Definition context.h:71
static size_t const DefaultFiberStackSize
Default fiber stack size in bytes.
Definition config.h:140
Stack information.
Definition context.h:89
char * p
Definition context.h:105
constexpr Stack(void *p_, size_t size_) noexcept
Definition context.h:90
size_t size
Definition context.h:106
constexpr Stack(size_t size_=0) noexcept
Definition context.h:95
R(A...) function_type
Definition context.h:276
std::tuple< typename Packed< A >::type... > tuple_type
Definition context.h:277
A::template function_type< void > * f
Definition context.h:309
Packed< R >::type r
Definition context.h:288
A_::tuple_type a
Definition context.h:286
void * operator()() noexcept
Definition context.h:291
A::template function_type< R > * f
Definition context.h:285
std::reference_wrapper< typename std::decay< T >::type > type
Definition context.h:270
typename std::decay< T >::type type
Definition context.h:265