GCC Code Coverage Report


Directory: src/gate/
File: src/gate/platform/posix/posixucontext.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 38 42 90.5%
Functions: 9 9 100.0%
Branches: 9 16 56.2%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/platform/posix/posixucontext.h"
29 #include "gate/results.h"
30
31 #if defined(GATE_SYS_OPENBSD)
32 # define GATE_POSIX_UCONTEXT_SJLJ_IMPL 1
33 #elif defined(GATE_SYS_POSIX)
34 # define GATE_POSIX_UCONTEXT_NATIVE_IMPL 1
35 #endif
36
37
38 #if defined(GATE_POSIX_UCONTEXT_SJLJ_IMPL)
39
40 #include "gate/atomics.h"
41 #include <signal.h>
42 #include <setjmp.h>
43 #include <pthread.h>
44
45 typedef struct sjlj_uctx_class
46 {
47 jmp_buf anchor;
48 jmp_buf init_anchor;
49
50 void* stack;
51 gate_size_t stack_size;
52
53 void(*target_func)(int, int, int, int);
54 int params[4];
55 } sjlj_uctx_t;
56
57 gate_result_t gate_posix_uctx_init()
58 {
59 return GATE_RESULT_OK;
60 }
61
62 void gate_posix_uctx_setup(void* uctx, void* ptr_stack, gate_size_t stack_size)
63 {
64 sjlj_uctx_t* ptr_ctx = (sjlj_uctx_t*)uctx;
65
66 ptr_ctx->stack = ptr_stack;
67 ptr_ctx->stack_size = stack_size;
68 }
69
70 static sjlj_uctx_t* current_setup_ctx = NULL;
71 static gate_atomic_int_t current_setup_completed;
72
73 static void gate_posix_uctx_dispatcher_handler(int sig_num)
74 {
75 sjlj_uctx_t* ptr_ctx = current_setup_ctx;
76 void(*callback)(int, int, int, int);
77 int p[4];
78
79 callback = ptr_ctx->target_func;
80 p[0] = ptr_ctx->params[0];
81 p[1] = ptr_ctx->params[1];
82 p[2] = ptr_ctx->params[2];
83 p[3] = ptr_ctx->params[3];
84
85 gate_atomic_int_set(&current_setup_completed, 1);
86
87 if (0 == setjmp(ptr_ctx->anchor))
88 {
89 /* first callstack-setup */
90 longjmp(ptr_ctx->init_anchor, 1);
91 }
92 else
93 {
94 /* longjmp from swap */
95 callback(p[0], p[1], p[2], p[3]);
96 }
97 }
98
99 gate_result_t gate_posix_uctx_make(void* uctx, void(*func)(int, int, int, int), int a1, int a2, int a3, int a4)
100 {
101 sjlj_uctx_t* ptr_ctx = (sjlj_uctx_t*)uctx;
102 sigset_t sigs;
103 sigset_t original_sigs;
104 struct sigaction sig_action = GATE_INIT_EMPTY;
105 struct sigaction old_sig_action = GATE_INIT_EMPTY;
106 struct sigaltstack sig_stack = GATE_INIT_EMPTY;
107 struct sigaltstack old_sig_stack = GATE_INIT_EMPTY;
108
109 ptr_ctx->target_func = func;
110 ptr_ctx->params[0] = a1;
111 ptr_ctx->params[1] = a2;
112 ptr_ctx->params[2] = a3;
113 ptr_ctx->params[3] = a4;
114
115 static gate_atomic_lock_t ctx_make_lock = GATE_ATOMIC_LOCK_INIT;
116
117 gate_atomic_lock_acquire(&ctx_make_lock);
118
119
120 if (0 == setjmp(ptr_ctx->init_anchor))
121 {
122 /* anchor set, now */
123
124 sigemptyset(&sigs);
125 sigaddset(&sigs, SIGUSR1);
126 pthread_sigmask(SIG_BLOCK, &sigs, &original_sigs);
127
128 sig_action.sa_handler = &gate_posix_uctx_dispatcher_handler;
129 sig_action.sa_flags = SA_ONSTACK;
130 sigemptyset(&sig_action.sa_mask);
131 sigaction(SIGUSR1, &sig_action, &old_sig_action);
132
133 sig_stack.ss_sp = ptr_ctx->stack;
134 sig_stack.ss_size = ptr_ctx->stack_size;
135 sig_stack.ss_flags = 0;
136 sigaltstack(&sig_stack, &old_sig_stack);
137
138 current_setup_ctx = ptr_ctx;
139 gate_atomic_int_set(&current_setup_completed, 0);
140
141 pthread_kill(pthread_self(), SIGUSR1);
142 sigfillset(&sigs);
143 sigdelset(&sigs, SIGUSR1);
144 while (gate_atomic_int_get(&current_setup_completed) == 0)
145 {
146 sigsuspend(&sigs);
147 }
148 }
149 else
150 {
151 }
152
153 gate_atomic_lock_release(&ctx_make_lock);
154
155 sigaltstack(NULL, &sig_stack);
156 sig_stack.ss_flags = SS_DISABLE;
157 sigaltstack(&sig_stack, NULL);
158
159 if (!(old_sig_stack.ss_flags & SS_DISABLE))
160 {
161 sigaltstack(&old_sig_stack, NULL);
162 }
163 sigaction(SIGUSR1, &old_sig_action, NULL);
164 pthread_sigmask(SIG_SETMASK, &sigs, NULL);
165
166 return GATE_RESULT_OK;
167 }
168
169 int gate_posix_uctx_swap(void* save_ctx, void* load_ctx)
170 {
171 sjlj_uctx_t* ptr_save = (sjlj_uctx_t*)save_ctx;
172 sjlj_uctx_t* ptr_load = (sjlj_uctx_t*)load_ctx;
173 if (!ptr_save || !ptr_load)
174 {
175 return -1;
176 }
177
178 if (0 == setjmp(ptr_save->anchor))
179 {
180 longjmp(ptr_load->anchor, 1);
181 }
182 return 0;
183 }
184
185 int gate_posix_uctx_get(void* uctx)
186 {
187 sjlj_uctx_t* ptr_ctx = (sjlj_uctx_t*)uctx;
188 return setjmp(ptr_ctx->anchor);
189 }
190
191 int gate_posix_uctx_set(void const* uctx)
192 {
193 sjlj_uctx_t* ptr_ctx = (sjlj_uctx_t*)uctx;
194 longjmp(ptr_ctx->anchor, 1);
195 return -1;
196 }
197
198 #endif /* GATE_POSIX_UCONTEXT_SJLJ_IMPL */
199
200
201
202 #if defined(GATE_POSIX_UCONTEXT_NATIVE_IMPL)
203
204 #if defined(GATE_SYS_DARWIN)
205 # ifndef _XOPEN_SOURCE
206 # define _XOPEN_SOURCE
207 # endif
208 #endif
209
210 #include "gate/platforms.h"
211
212 #include <ucontext.h>
213 #include <dlfcn.h>
214
215 typedef void(*makecontext_func_t)(ucontext_t* ucp, void(*func)(), int argc, ...);
216 typedef int(*swapcontext_func_t)(ucontext_t* oucp, ucontext_t* ucp);
217 typedef int(*getcontext_func_t)(ucontext_t* ucp);
218 typedef int(*setcontext_func_t)(const ucontext_t* ucp);
219
220 static makecontext_func_t volatile makecontext_func = NULL;
221 static swapcontext_func_t volatile swapcontext_func = NULL;
222 static getcontext_func_t volatile getcontext_func = NULL;
223 static setcontext_func_t volatile setcontext_func = NULL;
224
225
226 #if defined(HAVE_MAKECONTEXT)
227
228 74 static int swapcontext_wrapper(ucontext_t* oucp, ucontext_t* ucp)
229 {
230 74 return swapcontext(oucp, ucp);
231 }
232 11 static int getcontext_wrapper(ucontext_t* ucp)
233 {
234 11 return getcontext(ucp);
235 }
236 1 static int setcontext_wrapper(const ucontext_t* ucp)
237 {
238 1 return setcontext(ucp);
239 }
240
241
242 4 gate_result_t gate_posix_uctx_init()
243 {
244
5/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
4 if (!makecontext_func || !swapcontext_func || !getcontext_func || !setcontext_func)
245 {
246 2 makecontext_func = &makecontext;
247 2 swapcontext_func = &swapcontext_wrapper;
248 2 getcontext_func = &getcontext_wrapper;
249 2 setcontext_func = &setcontext_wrapper;
250 }
251 4 return GATE_RESULT_OK;
252 }
253
254 #else
255
256 static void* volatile libucontext_handle = NULL;
257
258 static void unload_uctx_atexit()
259 {
260 if (NULL != libucontext_handle)
261 {
262 void* handle = libucontext_handle;
263 libucontext_handle = NULL;
264 gate_posix_dlclose(handle);
265 }
266 }
267
268 static void load_uctx_from_libucontext()
269 {
270 if (NULL == libucontext_handle)
271 {
272 libucontext_handle = gate_posix_dlopen("libucontext.so.1", RTLD_GLOBAL);
273 if (NULL != libucontext_handle)
274 {
275 gate_platform_atexit(&unload_uctx_atexit);
276 }
277 else
278 {
279 return;
280 }
281 }
282
283 makecontext_func = (makecontext_func_t)gate_posix_dlsym(libucontext_handle, "makecontext");
284 swapcontext_func = (swapcontext_func_t)gate_posix_dlsym(libucontext_handle, "swapcontext");
285 getcontext_func = (getcontext_func_t)gate_posix_dlsym(libucontext_handle, "getcontext");
286 setcontext_func = (setcontext_func_t)gate_posix_dlsym(libucontext_handle, "setcontext");
287 }
288
289
290 gate_result_t gate_posix_uctx_init()
291 {
292 if (makecontext_func && swapcontext_func && getcontext_func && setcontext_func)
293 {
294 /* functions already loaded */
295 return GATE_RESULT_OK;
296 }
297
298 /* try global symbols: */
299 makecontext_func = (makecontext_func_t)gate_posix_global_sym("makecontext");
300 swapcontext_func = (swapcontext_func_t)gate_posix_global_sym("swapcontext");
301 getcontext_func = (getcontext_func_t)gate_posix_global_sym("getcontext");
302 setcontext_func = (setcontext_func_t)gate_posix_global_sym("setcontext");
303
304 if (makecontext_func && swapcontext_func && getcontext_func && setcontext_func)
305 {
306 return GATE_RESULT_OK;
307 }
308
309 /* try dynamic loading: */
310 load_uctx_from_libucontext();
311
312 return (makecontext_func && swapcontext_func && getcontext_func && setcontext_func)
313 ? GATE_RESULT_OK : GATE_RESULT_NOTSUPPORTED;
314 }
315
316 #endif
317
318
319 11 gate_result_t gate_posix_uctx_make(void* uctx, void(*func)(int, int, int, int), int a1, int a2, int a3, int a4)
320 {
321 11 ucontext_t* ptr_context = (ucontext_t*)uctx;
322
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!makecontext_func)
324 {
325 return GATE_RESULT_NOTSUPPORTED;
326 }
327 11 makecontext_func(ptr_context, (void(*)(void))func, 4, a1, a2, a3, a4);
328 11 return GATE_RESULT_OK;
329 }
330 74 int gate_posix_uctx_swap(void* save_ctx, void* load_ctx)
331 {
332 74 ucontext_t* ptr_save = (ucontext_t*)save_ctx;
333 74 ucontext_t* ptr_load = (ucontext_t*)load_ctx;
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (!swapcontext_func)
335 {
336 return -1;
337 }
338 74 return swapcontext_func(ptr_save, ptr_load);
339 }
340 11 void gate_posix_uctx_setup(void* uctx, void* ptr_stack, gate_size_t stack_size)
341 {
342 11 ucontext_t* ptr_ctx = (ucontext_t*)uctx;
343 11 ptr_ctx->uc_stack.ss_sp = ptr_stack;
344 11 ptr_ctx->uc_stack.ss_size = stack_size;
345 11 ptr_ctx->uc_stack.ss_flags = 0;
346 11 ptr_ctx->uc_link = NULL;
347 11 }
348 11 int gate_posix_uctx_get(void* uctx)
349 {
350 11 ucontext_t* ptr_ctx = (ucontext_t*)uctx;
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!getcontext_func)
352 {
353 return -1;
354 }
355 11 return getcontext_func(ptr_ctx);
356 }
357 1 int gate_posix_uctx_set(void const* uctx)
358 {
359 1 ucontext_t const* ptr_ctx = (ucontext_t const*)uctx;
360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!setcontext_func)
361 {
362 return -1;
363 }
364 1 return setcontext_func(ptr_ctx);
365 }
366
367 #endif /* GATE_POSIX_UCONTEXT_NATIVE_IMPL */
368