qr_reader-native 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-mruby.txt +22 -0
- data/LICENSE-spinel.txt +19 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/ext/qr_reader_native/SPINEL_VERSION +1 -0
- data/ext/qr_reader_native/extconf.rb +8 -0
- data/ext/qr_reader_native/mruby/error.h +13 -0
- data/ext/qr_reader_native/mruby/internal.h +145 -0
- data/ext/qr_reader_native/mruby/string.h +22 -0
- data/ext/qr_reader_native/mruby.h +93 -0
- data/ext/qr_reader_native/mruby_shim.h +118 -0
- data/ext/qr_reader_native/qr_reader_native.c +13513 -0
- data/ext/qr_reader_native/qr_reader_native.h +29 -0
- data/ext/qr_reader_native/qr_reader_native_ext.c +598 -0
- data/ext/qr_reader_native/re_cased.h +71 -0
- data/ext/qr_reader_native/re_compile.c +5784 -0
- data/ext/qr_reader_native/re_ctype.h +3540 -0
- data/ext/qr_reader_native/re_exec.c +2190 -0
- data/ext/qr_reader_native/re_internal.h +671 -0
- data/ext/qr_reader_native/re_prop.h +4629 -0
- data/ext/qr_reader_native/re_spinel.c +363 -0
- data/ext/qr_reader_native/re_spinel.h +22 -0
- data/ext/qr_reader_native/re_spinel_utf8.inc +97 -0
- data/ext/qr_reader_native/re_utf8.c +156 -0
- data/ext/qr_reader_native/sp_alloc.c +1447 -0
- data/ext/qr_reader_native/sp_alloc.h +1196 -0
- data/ext/qr_reader_native/sp_argf.h +33 -0
- data/ext/qr_reader_native/sp_array.c +1052 -0
- data/ext/qr_reader_native/sp_array.h +456 -0
- data/ext/qr_reader_native/sp_bigint.c +5826 -0
- data/ext/qr_reader_native/sp_bigint.h +117 -0
- data/ext/qr_reader_native/sp_cold.c +5259 -0
- data/ext/qr_reader_native/sp_compat.h +402 -0
- data/ext/qr_reader_native/sp_core.c +818 -0
- data/ext/qr_reader_native/sp_core.h +56 -0
- data/ext/qr_reader_native/sp_crypto.c +877 -0
- data/ext/qr_reader_native/sp_crypto.h +169 -0
- data/ext/qr_reader_native/sp_dtoa.c +1533 -0
- data/ext/qr_reader_native/sp_dtoa.h +29 -0
- data/ext/qr_reader_native/sp_encoding_names.h +172 -0
- data/ext/qr_reader_native/sp_enum.h +86 -0
- data/ext/qr_reader_native/sp_exc.c +1185 -0
- data/ext/qr_reader_native/sp_exc.h +186 -0
- data/ext/qr_reader_native/sp_exc_ctx.h +56 -0
- data/ext/qr_reader_native/sp_fiber.c +889 -0
- data/ext/qr_reader_native/sp_fiber.h +162 -0
- data/ext/qr_reader_native/sp_fiber_ctx.h +84 -0
- data/ext/qr_reader_native/sp_format.c +695 -0
- data/ext/qr_reader_native/sp_format.h +83 -0
- data/ext/qr_reader_native/sp_gc.c +1793 -0
- data/ext/qr_reader_native/sp_gc.h +762 -0
- data/ext/qr_reader_native/sp_hash.c +131 -0
- data/ext/qr_reader_native/sp_hash.h +131 -0
- data/ext/qr_reader_native/sp_inspect.c +215 -0
- data/ext/qr_reader_native/sp_inspect.h +128 -0
- data/ext/qr_reader_native/sp_io.c +1676 -0
- data/ext/qr_reader_native/sp_io.h +272 -0
- data/ext/qr_reader_native/sp_iobuffer.c +1014 -0
- data/ext/qr_reader_native/sp_iobuffer.h +167 -0
- data/ext/qr_reader_native/sp_marshal.c +487 -0
- data/ext/qr_reader_native/sp_marshal.h +60 -0
- data/ext/qr_reader_native/sp_net.c +1029 -0
- data/ext/qr_reader_native/sp_net.h +205 -0
- data/ext/qr_reader_native/sp_pack.c +1254 -0
- data/ext/qr_reader_native/sp_poly_cold.c +1220 -0
- data/ext/qr_reader_native/sp_proc.c +410 -0
- data/ext/qr_reader_native/sp_proc.h +327 -0
- data/ext/qr_reader_native/sp_process.c +547 -0
- data/ext/qr_reader_native/sp_process_status.c +211 -0
- data/ext/qr_reader_native/sp_process_status.h +66 -0
- data/ext/qr_reader_native/sp_random.c +287 -0
- data/ext/qr_reader_native/sp_random.h +52 -0
- data/ext/qr_reader_native/sp_range.h +144 -0
- data/ext/qr_reader_native/sp_re.c +1379 -0
- data/ext/qr_reader_native/sp_re.h +186 -0
- data/ext/qr_reader_native/sp_re_names.h +59 -0
- data/ext/qr_reader_native/sp_sched.c +4044 -0
- data/ext/qr_reader_native/sp_sched.h +295 -0
- data/ext/qr_reader_native/sp_slab.c +1507 -0
- data/ext/qr_reader_native/sp_str.c +1462 -0
- data/ext/qr_reader_native/sp_str.h +306 -0
- data/ext/qr_reader_native/sp_str_crypt.c +23 -0
- data/ext/qr_reader_native/sp_string.c +92 -0
- data/ext/qr_reader_native/sp_string.h +253 -0
- data/ext/qr_reader_native/sp_system.c +78 -0
- data/ext/qr_reader_native/sp_system.h +18 -0
- data/ext/qr_reader_native/sp_time.c +860 -0
- data/ext/qr_reader_native/sp_time.h +100 -0
- data/ext/qr_reader_native/sp_types.h +292 -0
- data/ext/qr_reader_native/spinel_rt.h +19017 -0
- data/ext/qr_reader_native/unicase.c +399 -0
- data/ext/qr_reader_native/unicase.h +901 -0
- data/lib/qr_reader/native.rb +6 -0
- metadata +153 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/* sp_fiber.h -- Fiber runtime surface.
|
|
2
|
+
*
|
|
3
|
+
* The sp_Fiber struct (a cooperative coroutine) is shared between the generated
|
|
4
|
+
* translation unit and lib/sp_fiber.c, which holds the function bodies. The
|
|
5
|
+
* context switch lives in sp_fiber_ctx.h (a portable asm switch on x86_64 /
|
|
6
|
+
* aarch64, ucontext elsewhere) -- no <ucontext.h> here, so OpenBSD compiles.
|
|
7
|
+
* `storage` is an opaque pointer to fiber-local variable storage. */
|
|
8
|
+
#ifndef SP_FIBER_H
|
|
9
|
+
#define SP_FIBER_H
|
|
10
|
+
|
|
11
|
+
#include "sp_gc.h" /* sp_RbVal */
|
|
12
|
+
#include "sp_fiber_ctx.h"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/* A green thread's whole C stack: the build-time default, 256 KB (half of
|
|
16
|
+
CRuby's machine stack for a fiber). The mapping is virtual space until a
|
|
17
|
+
page is touched, so what a fiber costs is the depth it actually reaches,
|
|
18
|
+
not this number; what it bounds is how deep a call chain, or how large a
|
|
19
|
+
frame, a fiber can run (#4496). The size a program runs with is
|
|
20
|
+
sp_fiber_stack_size, settable at run time: SPINEL_FIBER_STACK=<bytes>
|
|
21
|
+
(K/M suffixes) in the environment wins, else the hint the generated
|
|
22
|
+
program gives (an unoptimised build asks for more, its frames being many
|
|
23
|
+
times -O2's), else this default. */
|
|
24
|
+
#ifndef SP_FIBER_STACK_SIZE
|
|
25
|
+
#define SP_FIBER_STACK_SIZE (256*1024)
|
|
26
|
+
#endif
|
|
27
|
+
extern size_t sp_fiber_stack_size;
|
|
28
|
+
/* the generated program's request, honoured unless the environment says otherwise */
|
|
29
|
+
void sp_fiber_stack_hint(size_t bytes);
|
|
30
|
+
/* The PROT_NONE guard below it. One page catches a frame that grows past the
|
|
31
|
+
stack a page at a time, and nothing else: a C compiler that emits no stack
|
|
32
|
+
probes (gcc on Linux, by default) lets a 51 KB frame step straight over a
|
|
33
|
+
4 KB guard into whatever mapping sits below, and the program runs on with
|
|
34
|
+
that mapping corrupted (#4496). The guard is virtual space only, never
|
|
35
|
+
touched, so it is sized to the largest frame a build is likely to emit
|
|
36
|
+
rather than to a page; a frame larger than this still has to be probed. */
|
|
37
|
+
#ifndef SP_FIBER_GUARD_SIZE
|
|
38
|
+
#define SP_FIBER_GUARD_SIZE (256*1024)
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
/* ThreadSanitizer support: the asm context switch swaps stacks without TSan's
|
|
42
|
+
knowledge, so a fiber program reports spurious "unexpected memory mapping"
|
|
43
|
+
or false races. Under -fsanitize=thread we give each fiber a TSan fiber
|
|
44
|
+
handle and call __tsan_switch_to_fiber at every swap so TSan follows the
|
|
45
|
+
cooperative switch. SP_TSAN is set only in that build (a separate archive),
|
|
46
|
+
so the fiber struct carries the two extra fields only there -- the archive
|
|
47
|
+
and the generated TU agree because both are compiled with -fsanitize=thread. */
|
|
48
|
+
#ifndef __has_feature /* gcc lacks __has_feature; clang has it */
|
|
49
|
+
#define __has_feature(x) 0
|
|
50
|
+
#endif
|
|
51
|
+
#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
|
|
52
|
+
#define SP_TSAN 1
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
typedef struct sp_Fiber{sp_fiber_ctx ctx;sp_fiber_ctx caller_ctx;char*stack;size_t stack_size;int state;int transferred;sp_RbVal yielded_value;sp_RbVal resumed_value;void(*body)(struct sp_Fiber*);void*user_data;int saved_exc_top;int saved_catch_top;void*exc_ctx;int raised;const char*raised_cls;const char*raised_msg;void*raised_obj;int inject;int inject_defer;const char*inj_cls;const char*inj_msg;void*inj_obj;void*storage;void*attrs;/* per-fiber attributes (Fiber.attr_accessor): a table of the fiber's own, never copied into a new fiber as `storage` is */void***saved_roots;int saved_nroots;int saved_roots_cap;struct sp_Fiber*fiber_next;struct sp_Fiber*fiber_prev;struct sp_Fiber*resumer;/* the fiber suspended inside #resume of this one, until it returns: the chain from the running fiber back to the root is what the collector roots; every other suspended fiber lives by reference (#4525) */const char*birth_file;sp_int birth_line;int pass_argc;unsigned owner;/* id + 1 of the thread that made it (#6110); 0: no owner */struct sp_Fiber*return_to;/* where it goes if it ends after a transfer: the innermost fiber still inside a resume (NULL: the thread's main fiber) */unsigned char thread_main;/* a Thread's own fiber (its main fiber) */unsigned char blocking;/* Fiber.new(blocking: true), or inside Fiber.blocking { } *//* how many values the first resume passed (-1: not known), so |a| can tell resume(1, 2) from resume([1, 2]) *//* the Fiber.new site, for #inspect */
|
|
56
|
+
#ifdef SP_TSAN
|
|
57
|
+
void *tsan_fiber; /* __tsan fiber handle for this coroutine */
|
|
58
|
+
struct sp_Fiber *caller_fiber; /* who switched into us (the swap-out target) */
|
|
59
|
+
#endif
|
|
60
|
+
}sp_Fiber;
|
|
61
|
+
|
|
62
|
+
/* The currently-running fiber; the generated TU reads it directly for
|
|
63
|
+
`Fiber.current` and as the implicit receiver of Fiber operations. Per-worker
|
|
64
|
+
(SP_TLS) in the threaded build so each worker tracks the green thread it runs;
|
|
65
|
+
the generated TU is compiled with the matching -DSP_THREADS. (The scheduler
|
|
66
|
+
root fiber it is initialized to stays a shared static until per-worker root
|
|
67
|
+
fibers land with the workers.) */
|
|
68
|
+
extern SP_TLS sp_Fiber *sp_fiber_current;
|
|
69
|
+
|
|
70
|
+
/* Adopt the calling OS thread's root fiber (its native scheduler stack) as its
|
|
71
|
+
current coroutine, and read that per-worker root back. Worker 0 calls
|
|
72
|
+
sp_fiber_worker_init from sp_sched_init; helper workers from their startup. In
|
|
73
|
+
the single-threaded build the root is a shared static and these are inert. */
|
|
74
|
+
void sp_fiber_worker_init(void);
|
|
75
|
+
sp_Fiber *sp_fiber_worker_root(void);
|
|
76
|
+
/* Switch from a green thread back to the fiber that ran it, without the
|
|
77
|
+
checks Fiber#transfer makes (that fiber may be one the main thread resumed). */
|
|
78
|
+
void sp_fiber_sched_switch(sp_Fiber *f);
|
|
79
|
+
/* Publish the running worker's shadow-stack roots into its current green thread
|
|
80
|
+
(for a stop-the-world collector to mark while the worker is parked). */
|
|
81
|
+
void sp_fiber_publish_current_roots(void);
|
|
82
|
+
/* Mark a fiber's published (saved) roots; used by the collector to reach a
|
|
83
|
+
parked worker's root fiber, which is not on the global fiber list. */
|
|
84
|
+
void sp_fiber_mark_roots(sp_Fiber *f);
|
|
85
|
+
void sp_fiber_mark_chain(sp_Fiber *f); /* f and every resumer waiting on it (#4525) */
|
|
86
|
+
|
|
87
|
+
/* Public Fiber API (called from the generated TU). */
|
|
88
|
+
sp_Fiber *sp_Fiber_new(void (*body)(sp_Fiber *));
|
|
89
|
+
sp_RbVal sp_Fiber_resume(sp_Fiber *f, sp_RbVal val);
|
|
90
|
+
sp_RbVal sp_Fiber_yield(sp_RbVal val);
|
|
91
|
+
unsigned sp_thread_owner_id(void); /* lib/sp_sched.c */
|
|
92
|
+
sp_Fiber *sp_thread_main_fiber(void); /* lib/sp_sched.c */
|
|
93
|
+
/* The fiber a green thread switches back to: the one that ran it on this
|
|
94
|
+
worker, else the worker's root. */
|
|
95
|
+
sp_Fiber *sp_sched_home_fiber(void); /* lib/sp_sched.c */
|
|
96
|
+
sp_RbVal sp_Fiber_resume_n(sp_Fiber *f, sp_RbVal val, int argc);
|
|
97
|
+
sp_RbVal sp_Fiber_transfer_n(sp_Fiber *f, sp_RbVal val, int argc);
|
|
98
|
+
sp_RbVal sp_Fiber_transfer(sp_Fiber *f, sp_RbVal val);
|
|
99
|
+
/* Like sp_Fiber_transfer, but captures f's unhandled termination exception into
|
|
100
|
+
the out-params (for the thread scheduler) instead of re-raising it. When
|
|
101
|
+
f's thread stopped inside a Fiber it resumed, `at` is that fiber and the
|
|
102
|
+
switch goes there (NULL: to f). */
|
|
103
|
+
sp_RbVal sp_Fiber_transfer_catch(sp_Fiber *f, sp_Fiber *at, sp_RbVal val, int *out_raised,
|
|
104
|
+
const char **out_cls, const char **out_msg, void **out_obj);
|
|
105
|
+
/* Fiber#raise: inject an exception at the fiber's suspension point (or at entry
|
|
106
|
+
for an unstarted fiber). cls/msg describe a class+message; obj, when non-NULL,
|
|
107
|
+
is a pre-built exception object to raise instead. Returns the next yielded
|
|
108
|
+
value, or re-raises in the caller if the fiber does not handle it. */
|
|
109
|
+
sp_RbVal sp_Fiber_raise(sp_Fiber *f, const char *cls, const char *msg, void *obj);
|
|
110
|
+
/* Fiber#kill: terminate the fiber (running its ensure blocks); returns it. */
|
|
111
|
+
sp_Fiber *sp_Fiber_kill(sp_Fiber *f);
|
|
112
|
+
sp_bool sp_Fiber_alive(sp_Fiber *f);
|
|
113
|
+
sp_bool sp_Fiber_blocking_p(sp_Fiber *f); /* #blocking? */
|
|
114
|
+
sp_Fiber *sp_Fiber_at(sp_Fiber *f, const char *file, sp_int line);
|
|
115
|
+
const char *sp_Fiber_inspect(sp_Fiber *f); /* #inspect / #to_s */
|
|
116
|
+
sp_RbVal sp_Fiber_storage_get(sp_Fiber *f, sp_sym k);
|
|
117
|
+
void sp_Fiber_storage_set(sp_Fiber *f, sp_sym k, sp_RbVal v);
|
|
118
|
+
void sp_Fiber_storage_put(sp_Fiber *f, sp_sym k, sp_RbVal v);
|
|
119
|
+
sp_int sp_Fiber_storage_len(sp_Fiber *f);
|
|
120
|
+
sp_sym sp_Fiber_storage_key(sp_Fiber *f, sp_int i);
|
|
121
|
+
sp_RbVal sp_Fiber_storage_val(sp_Fiber *f, sp_int i);
|
|
122
|
+
void sp_Fiber_storage_clear(sp_Fiber *f);
|
|
123
|
+
void sp_Fiber_storage_empty(sp_Fiber *f);
|
|
124
|
+
sp_RbVal sp_Fiber_attr_get(sp_Fiber *f, sp_sym k);
|
|
125
|
+
void sp_Fiber_attr_set(sp_Fiber *f, sp_sym k, sp_RbVal v);
|
|
126
|
+
/* Reached from sp_re_mark_globals in the generated TU during a GC pass. */
|
|
127
|
+
void sp_mark_fiber_root_storage(void);
|
|
128
|
+
|
|
129
|
+
/* Thread #kill / #raise: the scheduler queues a pending inject on a target
|
|
130
|
+
fiber, then fires it when that thread next runs (in its own context). */
|
|
131
|
+
void sp_fiber_set_raise_inject(sp_Fiber *f, const char *cls, const char *msg, void *obj);
|
|
132
|
+
void sp_fiber_set_kill_inject(sp_Fiber *f);
|
|
133
|
+
/* ConditionVariable waits defer async delivery until their mutex is reacquired. */
|
|
134
|
+
void sp_fiber_defer_inject(void);
|
|
135
|
+
void sp_fiber_undefer_inject(void);
|
|
136
|
+
void sp_fiber_fire_inject_if_pending(void);
|
|
137
|
+
int sp_fiber_inject_pending(sp_Fiber *f); /* lock-free acquire peek */
|
|
138
|
+
SP_NORETURN void sp_fiber_raise_kill_self(void);
|
|
139
|
+
|
|
140
|
+
/* A C stack that ran out is CRuby's SystemStackError, and a program that
|
|
141
|
+
rescues it goes on running. The raise cannot live here: the exception
|
|
142
|
+
stack is thread-local state in the generated translation unit, which this
|
|
143
|
+
archive is compiled without. The generated TU installs this hook, and the
|
|
144
|
+
fault handler calls it instead of reporting and dying -- on the alternate
|
|
145
|
+
signal stack, so the raise runs on memory the overflow did not touch.
|
|
146
|
+
NULL (nothing installed, or no handler armed) keeps the old report. */
|
|
147
|
+
extern void (*sp_stack_overflow_raise_fn)(void);
|
|
148
|
+
void sp_sig_unblock(int a, int b);
|
|
149
|
+
void sp_stack_guard_init(void);
|
|
150
|
+
/* Run the program body on a stack this library maps (see sp_main_stack_run);
|
|
151
|
+
sp_main_stack_hint asks for a size, SPINEL_MAIN_STACK in the environment
|
|
152
|
+
wins over it. */
|
|
153
|
+
void sp_main_stack_hint(size_t bytes);
|
|
154
|
+
void sp_main_stack_run(void (*body)(void));
|
|
155
|
+
|
|
156
|
+
/* The running thread's own stack, for the fault handler's overflow test: a
|
|
157
|
+
fault just below `lo` is this stack growing past its end. Recorded per
|
|
158
|
+
thread when the handler is armed. */
|
|
159
|
+
extern SP_TLS char *sp_thread_stack_lo;
|
|
160
|
+
extern SP_TLS char *sp_thread_stack_hi;
|
|
161
|
+
|
|
162
|
+
#endif
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* sp_fiber_ctx.h -- portable coroutine context switch for sp_fiber.c.
|
|
2
|
+
*
|
|
3
|
+
* Replaces POSIX <ucontext.h> (getcontext/makecontext/swapcontext), which
|
|
4
|
+
* OpenBSD removed in 5.7 (W^X / ASLR hardening) and which is deprecated on
|
|
5
|
+
* macOS. On x86_64 and aarch64 we use a tiny cooperative register switch
|
|
6
|
+
* written as file-scope inline asm (defined in sp_fiber.c): it lands in .text
|
|
7
|
+
* (W^X-safe, unlike libco's executable data blob), does no syscall (unlike
|
|
8
|
+
* swapcontext's sigprocmask, so it's faster), and only saves the callee-saved
|
|
9
|
+
* registers + stack pointer. The "context" is therefore just the saved stack
|
|
10
|
+
* pointer; all other state lives on the coroutine's own stack. Other
|
|
11
|
+
* architectures fall back to <ucontext.h>.
|
|
12
|
+
*
|
|
13
|
+
* sp_ctx_swap(from, to) save the current context into *from,
|
|
14
|
+
* then switch to *to.
|
|
15
|
+
* sp_ctx_make(ctx, base, size, entry) prime a fresh context so the first swap
|
|
16
|
+
* into it begins executing entry() on the
|
|
17
|
+
* stack [base, base+size). entry must
|
|
18
|
+
* never return.
|
|
19
|
+
*/
|
|
20
|
+
#ifndef SP_FIBER_CTX_H
|
|
21
|
+
#define SP_FIBER_CTX_H
|
|
22
|
+
|
|
23
|
+
#include <stddef.h>
|
|
24
|
+
#include <stdint.h>
|
|
25
|
+
|
|
26
|
+
/* Windows takes the ucontext fallback, which lib/win32 provides: its x64
|
|
27
|
+
ABI saves more registers, and a switch there also moves the stack bounds
|
|
28
|
+
the thread's TEB holds. */
|
|
29
|
+
#if (defined(__x86_64__) || defined(__aarch64__)) && !defined(_WIN32)
|
|
30
|
+
#define SP_FIBER_ASM 1
|
|
31
|
+
#else
|
|
32
|
+
#define SP_FIBER_ASM 0
|
|
33
|
+
#endif
|
|
34
|
+
|
|
35
|
+
#if SP_FIBER_ASM
|
|
36
|
+
|
|
37
|
+
/* The whole machine context is the saved stack pointer; the callee-saved
|
|
38
|
+
registers are pushed onto / popped from the coroutine's own stack by
|
|
39
|
+
sp_ctx_swap (see the file-scope asm in sp_fiber.c). */
|
|
40
|
+
typedef struct sp_fiber_ctx { void *sp; } sp_fiber_ctx;
|
|
41
|
+
|
|
42
|
+
static inline void sp_ctx_make(sp_fiber_ctx *ctx, void *base, size_t size,
|
|
43
|
+
void (*entry)(void)) {
|
|
44
|
+
uintptr_t top = ((uintptr_t)base + size) & ~(uintptr_t)15; /* 16B-align the top */
|
|
45
|
+
#if defined(__x86_64__)
|
|
46
|
+
/* SysV AMD64: entry's first instruction needs rsp%16 == 8 (as if reached by
|
|
47
|
+
`call`). sp_ctx_swap pops 6 callee-saved regs then `ret`s into the slot
|
|
48
|
+
just above them: [entry][rbp][rbx][r12][r13][r14][r15<-sp]. */
|
|
49
|
+
void **s = (void **)(top - 8);
|
|
50
|
+
*--s = (void *)entry; /* `ret` target, at top-16 */
|
|
51
|
+
for (int i = 0; i < 6; i++) *--s = 0; /* rbp, rbx, r12, r13, r14, r15 */
|
|
52
|
+
ctx->sp = s; /* top-64 */
|
|
53
|
+
#else /* __aarch64__ */
|
|
54
|
+
/* Mirror the aarch64 sp_ctx_swap frame: 160 bytes holding x19..x30 (12) then
|
|
55
|
+
d8..d15 (8). x30 (lr = entry) sits at offset 88 (slot 11). On the first
|
|
56
|
+
swap the ldp's load zeros + entry into lr and `ret` (br x30) jumps to it. */
|
|
57
|
+
void **s = (void **)(top - 160);
|
|
58
|
+
for (int i = 0; i < 20; i++) s[i] = 0;
|
|
59
|
+
s[11] = (void *)entry; /* x30 (lr) */
|
|
60
|
+
ctx->sp = s;
|
|
61
|
+
#endif
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#else /* portable fallback: POSIX ucontext */
|
|
65
|
+
|
|
66
|
+
#include <ucontext.h>
|
|
67
|
+
typedef struct sp_fiber_ctx { ucontext_t uc; } sp_fiber_ctx;
|
|
68
|
+
|
|
69
|
+
static inline void sp_ctx_make(sp_fiber_ctx *ctx, void *base, size_t size,
|
|
70
|
+
void (*entry)(void)) {
|
|
71
|
+
getcontext(&ctx->uc);
|
|
72
|
+
ctx->uc.uc_stack.ss_sp = base;
|
|
73
|
+
ctx->uc.uc_stack.ss_size = size;
|
|
74
|
+
ctx->uc.uc_link = NULL; /* entry never returns (trampoline switches) */
|
|
75
|
+
makecontext(&ctx->uc, entry, 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#endif
|
|
79
|
+
|
|
80
|
+
/* Defined as file-scope asm in sp_fiber.c (asm backend) or a swapcontext
|
|
81
|
+
wrapper (fallback). */
|
|
82
|
+
void sp_ctx_swap(sp_fiber_ctx *from, sp_fiber_ctx *to);
|
|
83
|
+
|
|
84
|
+
#endif /* SP_FIBER_CTX_H */
|