ucontext.h
1 /*
2  * SPDX-FileCopyrightText: 2013-2016 Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
3  * SPDX-FileCopyrightText: 2025 carl-tud
4  * SPDX-License-Identifier: LGPL-2.1-only
5  */
6 
7 #pragma once
8 
9 #if USE_LIBUCONTEXT
10 # include <libucontext/libucontext.h>
11 #else
12 # include <ucontext.h>
13 #endif /* USE_LIBUCONTEXT */
14 
15 #include <stdint.h>
16 #include <stdbool.h>
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
27 /* MARK: - Context accessors */
38 static inline uintptr_t _context_get_fptr(ucontext_t *context) {
39 # if defined(__FreeBSD__) /* FreeBSD */
40  return (uintptr_t)((struct sigcontext *)context)->sc_eip;
41 # elif defined(__linux__) /* Linux */
42 # if defined(__arm__)
43  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.arm_pc;
44 # elif defined(__x86_64__)
45  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP];
46 # elif defined(__i386__)
47  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP];
48 # else
49 # error "Unsupported Linux architecture"
50 # endif
51 # else
52 # error "Operating system unsupported"
53 # endif
54 }
55 
61 static inline void _context_set_fptr(ucontext_t *context, uintptr_t func) {
62 # if defined(__FreeBSD__) /* FreeBSD */
63  ((struct sigcontext *)context)->sc_eip = (unsigned int)func;
64 # elif defined(__linux__) /* Linux */
65 # if defined(__arm__)
66  ((ucontext_t *)context)->uc_mcontext.arm_lr = func;
67  ((ucontext_t *)context)->uc_mcontext.arm_pc = func;
68 # elif defined(__x86_64__)
69  ((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP] = (greg_t)func;
70 # elif defined(__i386__)
71  ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP] = func;
72 # else
73 # error "Unsupported Linux architecture"
74 # endif
75 # else
76 # error "Operating system unsupported"
77 # endif
78 }
81 /* MARK: - 64-bit support for makecontext */
86 #if defined(__LP64__) || defined(DOXYGEN)
94 extern void _start_task_func64(void);
95 #endif
96 
106 static inline void makecontext64(ucontext_t *context, void (*func)(void), void* arg) {
107 # if defined(__LP64__)
108  /* makecontext accepts int arguments. In RIOT, we use void* for the optional argument.
109  * To not truncate the argument pointer, we pass it in a register to _start_task_func64. */
110  makecontext(context, (void (*)(void))_start_task_func64, 0);
111 
112 # if defined(__x86_64__)
113 # if defined(__linux__)
114  context->uc_mcontext.gregs[REG_R14] = (greg_t)func;
115  context->uc_mcontext.gregs[REG_R15] = (greg_t)arg;
116 # endif
117 # endif
118 
119 # else
120  /* On 32-bit platforms, the width of an int is enough to fit a pointer. */
121  makecontext(context, (void (*)(void))func, 1, arg);
122 # endif
123 }
128 #ifdef __cplusplus
129 }
130 #endif
void _start_task_func64(void)
Invokes thread task function.
static void _context_set_fptr(ucontext_t *context, uintptr_t func)
Retrieves function pointer generated during calls to makecontext/setcontext/swapcontext
Definition: ucontext.h:61
static uintptr_t _context_get_fptr(ucontext_t *context)
Retrieves function pointer generated during calls to makecontext/setcontext/swapcontext
Definition: ucontext.h:38
static void makecontext64(ucontext_t *context, void(*func)(void), void *arg)
Like makecontext, allows 64-bit wide function argument on 64-bit platforms.
Definition: ucontext.h:106