git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / libco / ucontext.c
1 /*
2   libco.ucontext (2008-01-28)
3   author: Nach
4   license: public domain
5 */
6
7 /*
8  * WARNING: the overhead of POSIX ucontext is very high,
9  * assembly versions of libco or libco_sjlj should be much faster
10  *
11  * This library only exists for two reasons:
12  * 1 - as an initial test for the viability of a ucontext implementation
13  * 2 - to demonstrate the power and speed of libco over existing implementations,
14  *     such as pth (which defaults to wrapping ucontext on unix targets)
15  *
16  * Use this library only as a *last resort*
17  */
18
19 #define LIBCO_C
20 #include <libco.h>
21 #include <stdlib.h>
22 #include <ucontext.h>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 static thread_local ucontext_t co_primary;
29 static thread_local ucontext_t *co_running = 0;
30
31 cothread_t co_active(void)
32 {
33    if (!co_running)
34       co_running = &co_primary;
35    return (cothread_t)co_running;
36 }
37
38 cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
39 {
40    ucontext_t *thread;
41    if (!co_running)
42       co_running = &co_primary;
43
44    if ((thread = (ucontext_t*)malloc(sizeof(ucontext_t))))
45    {
46       if ((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize)))
47       {
48          thread->uc_link = co_running;
49          thread->uc_stack.ss_size = heapsize;
50          makecontext(thread, coentry, 0);
51       }
52       else
53       {
54          co_delete((cothread_t)thread);
55          thread = 0;
56       }
57    }
58    return (cothread_t)thread;
59 }
60
61 void co_delete(cothread_t cothread)
62 {
63    if (!cothread)
64       return;
65
66    if (((ucontext_t*)cothread)->uc_stack.ss_sp)
67       free(((ucontext_t*)cothread)->uc_stack.ss_sp);
68    free(cothread);
69 }
70
71 void co_switch(cothread_t cothread)
72 {
73    ucontext_t *old_thread = co_running;
74    co_running             = (ucontext_t*)cothread;
75    swapcontext(old_thread, co_running);
76 }
77
78 #ifdef __cplusplus
79 }
80 #endif