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 
co_active(void)31 cothread_t co_active(void)
32 {
33    if (!co_running)
34       co_running = &co_primary;
35    return (cothread_t)co_running;
36 }
37 
co_create(unsigned int heapsize,void (* coentry)(void))38 cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
39 {
40    if (!co_running)
41       co_running = &co_primary;
42    ucontext_t *thread = (ucontext_t*)malloc(sizeof(ucontext_t));
43 
44    if(thread)
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 
co_delete(cothread_t cothread)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 
co_switch(cothread_t cothread)71 void co_switch(cothread_t cothread)
72 {
73    ucontext_t *old_thread = co_running;
74 
75    co_running = (ucontext_t*)cothread;
76    swapcontext(old_thread, co_running);
77 }
78 
79 #ifdef __cplusplus
80 }
81 #endif
82