standalone: fix w/h confusion
[pcsx_rearmed.git] / deps / libretro-common / libco / sjlj.c
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
21 extern "C" {
22 #endif
23
24 typedef struct
25 {
26    sigjmp_buf context;
27    void (*coentry)(void);
28    void *stack;
29 } cothread_struct;
30
31 static thread_local cothread_struct co_primary;
32 static thread_local cothread_struct *creating, *co_running = 0;
33
34 static void springboard(int ignored)
35 {
36    if (sigsetjmp(creating->context, 0))
37       co_running->coentry();
38 }
39
40 cothread_t co_active(void)
41 {
42   if (!co_running)
43      co_running = &co_primary;
44   return (cothread_t)co_running;
45 }
46
47 cothread_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
92 void 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
102 void 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