ucontext.h
1 /*
2  * Copyright (C) 2013 - 2016 Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
3  * Copyright (C) 2025 carl-tud
4  *
5  * This file is subject to the terms and conditions of the GNU Lesser
6  * General Public License v2.1. See the file LICENSE in the top level
7  * directory for more details.
8  */
9 
10 #pragma once
11 
12 #if USE_LIBUCONTEXT
13 # include <libucontext/libucontext.h>
14 #else
15 # include <ucontext.h>
16 #endif /* USE_LIBUCONTEXT */
17 
18 #include <stdint.h>
19 #include <stdbool.h>
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
30 /* MARK: - Context accessors */
41 static inline uintptr_t _context_get_fptr(ucontext_t *context) {
42 # if defined(__FreeBSD__) /* FreeBSD */
43  return (uintptr_t)((struct sigcontext *)context)->sc_eip;
44 # elif defined(__linux__) /* Linux */
45 # if defined(__arm__)
46  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.arm_pc;
47 # elif defined(__x86_64__)
48  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP];
49 # elif defined(__i386__)
50  return (uintptr_t)((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP];
51 # else
52 # error "Unsupported Linux architecture"
53 # endif
54 # else
55 # error "Operating system unsupported"
56 # endif
57 }
58 
64 static inline void _context_set_fptr(ucontext_t *context, uintptr_t func) {
65 # if defined(__FreeBSD__) /* FreeBSD */
66  ((struct sigcontext *)context)->sc_eip = (unsigned int)func;
67 # elif defined(__linux__) /* Linux */
68 # if defined(__arm__)
69  ((ucontext_t *)context)->uc_mcontext.arm_lr = func;
70  ((ucontext_t *)context)->uc_mcontext.arm_pc = func;
71 # elif defined(__x86_64__)
72  ((ucontext_t *)context)->uc_mcontext.gregs[REG_RIP] = (greg_t)func;
73 # elif defined(__i386__)
74  ((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP] = func;
75 # else
76 # error "Unsupported Linux architecture"
77 # endif
78 # else
79 # error "Operating system unsupported"
80 # endif
81 }
84 /* MARK: - 64-bit support for makecontext */
89 #if defined(__LP64__) || defined(DOXYGEN)
97 extern void _start_task_func64(void);
98 #endif
99 
109 static inline void makecontext64(ucontext_t *context, void (*func)(void), void* arg) {
110 # if defined(__LP64__)
111  /* makecontext accepts int arguments. In RIOT, we use void* for the optional argument.
112  * To not truncate the argument pointer, we pass it in a register to _start_task_func64. */
113  makecontext(context, (void (*)(void))_start_task_func64, 0);
114 
115 # if defined(__x86_64__)
116 # if defined(__linux__)
117  context->uc_mcontext.gregs[REG_R14] = (greg_t)func;
118  context->uc_mcontext.gregs[REG_R15] = (greg_t)arg;
119 # endif
120 # endif
121 
122 # else
123  /* On 32-bit platforms, the width of an int is enough to fit a pointer. */
124  makecontext(context, (void (*)(void))func, 1, arg);
125 # endif
126 }
131 #ifdef __cplusplus
132 }
133 #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:64
static uintptr_t _context_get_fptr(ucontext_t *context)
Retrieves function pointer generated during calls to makecontext/setcontext/swapcontext
Definition: ucontext.h:41
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:109