From 365077772d3d8d5d479febd0388d7e74ef08d508 Mon Sep 17 00:00:00 2001 From: aliaspider Date: Mon, 8 Dec 2014 22:56:33 +0100 Subject: start implementing the libretro interface. (not working yet) --- libco/sjlj.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 libco/sjlj.c (limited to 'libco/sjlj.c') diff --git a/libco/sjlj.c b/libco/sjlj.c new file mode 100644 index 0000000..f074714 --- /dev/null +++ b/libco/sjlj.c @@ -0,0 +1,115 @@ +/* + libco.sjlj (2008-01-28) + author: Nach + license: public domain +*/ + +/* + * Note this was designed for UNIX systems. Based on ideas expressed in a paper + * by Ralf Engelschall. + * For SJLJ on other systems, one would want to rewrite springboard() and + * co_create() and hack the jmb_buf stack pointer. + */ + +#define LIBCO_C +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + sigjmp_buf context; + void (*coentry)(void); + void *stack; +} cothread_struct; + +static thread_local cothread_struct co_primary; +static thread_local cothread_struct *creating, *co_running = 0; + +static void springboard(int ignored) +{ + if(sigsetjmp(creating->context, 0)) + co_running->coentry(); +} + +cothread_t co_active(void) +{ + if (!co_running) + co_running = &co_primary; + return (cothread_t)co_running; +} + +cothread_t co_create(unsigned int size, void (*coentry)(void)) +{ + if(!co_running) + co_running = &co_primary; + + cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct)); + + if(thread) + { + struct sigaction handler; + struct sigaction old_handler; + + stack_t stack; + stack_t old_stack; + + thread->coentry = thread->stack = 0; + + stack.ss_flags = 0; + stack.ss_size = size; + thread->stack = stack.ss_sp = malloc(size); + + if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) + { + handler.sa_handler = springboard; + handler.sa_flags = SA_ONSTACK; + sigemptyset(&handler.sa_mask); + creating = thread; + + if(!sigaction(SIGUSR1, &handler, &old_handler)) + { + if(!raise(SIGUSR1)) + thread->coentry = coentry; + sigaltstack(&old_stack, 0); + sigaction(SIGUSR1, &old_handler, 0); + } + } + + if(thread->coentry != coentry) + { + co_delete(thread); + thread = 0; + } + } + + return (cothread_t)thread; +} + +void co_delete(cothread_t cothread) +{ + if(cothread) + { + if(((cothread_struct*)cothread)->stack) + free(((cothread_struct*)cothread)->stack); + free(cothread); + } +} + +void co_switch(cothread_t cothread) +{ + if(!sigsetjmp(co_running->context, 0)) + { + co_running = (cothread_struct*)cothread; + siglongjmp(co_running->context, 1); + } +} + +#ifdef __cplusplus +} +#endif -- cgit v1.2.3