git subrepo pull --force deps/lightrec
[pcsx_rearmed.git] / deps / libretro-common / libco / sjlj.c
CommitLineData
3719602c
PC
1/*
2 libco.sjlj (2008-01-28)
3 author: Nach
4 license: public domain
5*/
6
7/*
8 * Note this was designed for UNIX systems. Based on ideas expressed in a paper
9 * by Ralf Engelschall.
10 * For SJLJ on other systems, one would want to rewrite springboard() and
11 * co_create() and hack the jmb_buf stack pointer.
12 */
13
14#define LIBCO_C
15#include <libco.h>
16#include <stdlib.h>
17#include <signal.h>
18#include <setjmp.h>
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24typedef struct
25{
26 sigjmp_buf context;
27 void (*coentry)(void);
28 void *stack;
29} cothread_struct;
30
31static thread_local cothread_struct co_primary;
32static thread_local cothread_struct *creating, *co_running = 0;
33
34static void springboard(int ignored)
35{
36 if (sigsetjmp(creating->context, 0))
37 co_running->coentry();
38}
39
40cothread_t co_active(void)
41{
42 if (!co_running)
43 co_running = &co_primary;
44 return (cothread_t)co_running;
45}
46
47cothread_t co_create(unsigned int size, void (*coentry)(void))
48{
49 cothread_struct *thread;
50 if (!co_running)
51 co_running = &co_primary;
52
53 if ((thread = (cothread_struct*)malloc(sizeof(cothread_struct))))
54 {
55 stack_t stack;
56 stack_t old_stack;
57
58 thread->coentry = thread->stack = 0;
59
60 stack.ss_flags = 0;
61 stack.ss_size = size;
62 thread->stack = stack.ss_sp = malloc(size);
63
64 if (stack.ss_sp && !sigaltstack(&stack, &old_stack))
65 {
66 struct sigaction old_handler = {{0}};
67 struct sigaction handler = {{0}};
68 handler.sa_handler = springboard;
69 handler.sa_flags = SA_ONSTACK;
70 sigemptyset(&handler.sa_mask);
71 creating = thread;
72
73 if (!sigaction(SIGUSR1, &handler, &old_handler))
74 {
75 if (!raise(SIGUSR1))
76 thread->coentry = coentry;
77 sigaltstack(&old_stack, 0);
78 sigaction(SIGUSR1, &old_handler, 0);
79 }
80 }
81
82 if (thread->coentry != coentry)
83 {
84 co_delete(thread);
85 thread = 0;
86 }
87 }
88
89 return (cothread_t)thread;
90}
91
92void co_delete(cothread_t cothread)
93{
94 if (cothread)
95 {
96 if (((cothread_struct*)cothread)->stack)
97 free(((cothread_struct*)cothread)->stack);
98 free(cothread);
99 }
100}
101
102void co_switch(cothread_t cothread)
103{
104 if (!sigsetjmp(co_running->context, 0))
105 {
106 co_running = (cothread_struct*)cothread;
107 siglongjmp(co_running->context, 1);
108 }
109}
110
111#ifdef __cplusplus
112}
113#endif