summaryrefslogtreecommitdiff
path: root/libcr
diff options
context:
space:
mode:
Diffstat (limited to 'libcr')
-rw-r--r--libcr/coroutine.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/libcr/coroutine.c b/libcr/coroutine.c
index c446276..a947ae9 100644
--- a/libcr/coroutine.c
+++ b/libcr/coroutine.c
@@ -135,6 +135,8 @@
#define ARRAY_LEN(arr) (sizeof(arr)/sizeof((arr)[0]))
#define NEXT_POWER_OF_2(x) ((1ULL)<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)))
+#define UNUSED(name)
+
#define ALWAYS_INLINE [[gnu::always_inline]] inline
#define NEVER_INLINE [[gnu::noinline]]
@@ -158,7 +160,10 @@
/* For a signal to be *in* the mask means that the signal is
* *blocked*. */
- #define _CR_SIG_SENTINEL SIGHUP
+ #define _CR_SIG_SENTINEL SIGURG
+ #if CONFIG_COROUTINE_GDB
+ #define _CR_SIG_GDB SIGWINCH
+ #endif
bool cr_is_in_intrhandler(void) {
sigset_t cur_mask;
@@ -205,6 +210,19 @@
sigemptyset(&zero);
sigprocmask(SIG_SETMASK, &zero, NULL);
}
+ #if CONFIG_COROUTINE_GDB
+ static void _cr_gdb_intrhandler(int UNUSED(sig)) {}
+ #endif
+ static void cr_plat_init(void) {
+ #if CONFIG_COROUTINE_GDB
+ int r;
+ struct sigaction action = {
+ .sa_handler = _cr_gdb_intrhandler,
+ };
+ r = sigaction(_CR_SIG_GDB, &action, NULL);
+ assert(r == 0);
+ #endif
+ }
#elif __ARM_ARCH_6M__ && __ARM_EABI__
bool cr_is_in_intrhandler(void) {
uint32_t isr_number;
@@ -242,6 +260,7 @@
assert(!_cr_plat_are_interrupts_enabled());
asm volatile ("cpsie i");
}
+ static void cr_plat_init(void) {}
#else
#error unsupported platform (not __unix__, not __ARM_ARCH_6M__ && __ARM_EABI__)
#endif
@@ -327,14 +346,7 @@
uintptr_t sp;
#endif
} cr_plat_jmp_buf;
- #if CONIG_COROUTINE_GDB
- NEVER_INLINE
- #endif
static void _cr_plat_setjmp_pre(cr_plat_jmp_buf *env [[gnu::unused]]) {
- #if CONIG_COROUTINE_GDB
- /* Prevent the call from being optimized away. */
- asm ("");
- #endif
#if CONFIG_COROUTINE_MEASURE_STACK
env->sp = cr_plat_get_sp();
#endif
@@ -415,8 +427,12 @@ static const uint8_t stack_pattern[] = {
/* global variables ***********************************************************/
+static bool coroutine_initialized = false;
static cr_plat_jmp_buf coroutine_add_env;
static cr_plat_jmp_buf coroutine_main_env;
+#if CONFIG_COROUTINE_GDB
+static cr_plat_jmp_buf coroutine_gdb_env;
+#endif
/*
* Invariants (and non-invariants):
@@ -471,7 +487,26 @@ static inline cid_t coroutine_ringbuf_pop(void) {
return coroutine_ringbuf.buf[coroutine_ringbuf.tail++ % ARRAY_LEN(coroutine_ringbuf.buf)];
}
+#if CONFIG_COROUTINE_GDB
+NEVER_INLINE void cr_gdb_breakpoint(void) {
+ /* Prevent the call from being optimized away. */
+ asm ("");
+}
+NEVER_INLINE void cr_gdb_readjmp(cr_plat_jmp_buf *env) {
+ if (!cr_plat_setjmp(&coroutine_gdb_env))
+ cr_plat_longjmp(env, 2);
+}
+#define cr_setjmp(env) ({ \
+ int val = cr_plat_setjmp(env); \
+ if (val == 2) { \
+ cr_gdb_breakpoint(); \
+ cr_plat_longjmp(&coroutine_gdb_env, 1); \
+ } \
+ val; \
+ })
+#else
#define cr_setjmp(env) cr_plat_setjmp(env)
+#endif
#define cr_longjmp(env) cr_plat_longjmp(env, 1)
static inline void assert_cid(cid_t cid) {
@@ -511,6 +546,11 @@ cid_t coroutine_add_with_stack_size(size_t stack_size,
debugf("coroutine_add_with_stack_size(%zu, \"%s\", %p, %p)...",
stack_size, name, fn, args);
+ if (!coroutine_initialized) {
+ cr_plat_init();
+ coroutine_initialized = true;
+ }
+
cid_t child;
{
size_t base = last_created;
@@ -587,6 +627,10 @@ cid_t coroutine_add(const char *name, cr_fn_t fn, void *args) {
void coroutine_main(void) {
debugf("coroutine_main()");
+ if (!coroutine_initialized) {
+ cr_plat_init();
+ coroutine_initialized = true;
+ }
bool saved = cr_save_and_disable_interrupts();
assert(saved);
assert(!cr_is_in_intrhandler());