1 #include "context.h"
2 #include <assert.h>
3 #include <sched.h>
4 #include <stdlib.h>
5
6 static __thread context_t* cur;
7
context_t()8 context_t::context_t()
9 : creator(NULL), func(NULL), arg(NULL),
10 #ifndef USE_UCONTEXT
11 mutex(PTHREAD_MUTEX_INITIALIZER),
12 cond(PTHREAD_COND_INITIALIZER), flag(0)
13 #else
14 context(new ucontext_t)
15 #endif
16 {
17 }
18
19 #ifdef USE_UCONTEXT
20 #ifndef GLIBC_64BIT_PTR_BUG
wrapper(context_t * ctx)21 void context_t::wrapper(context_t* ctx)
22 {
23 #else
24 void context_t::wrapper(unsigned int hi, unsigned int lo)
25 {
26 context_t* ctx = reinterpret_cast<context_t*>(static_cast<unsigned long>(lo) | (static_cast<unsigned long>(hi) << 32));
27 #endif
28 ctx->creator->switch_to();
29 ctx->func(ctx->arg);
30 }
31 #else
32 void* context_t::wrapper(void* a)
33 {
34 context_t* ctx = static_cast<context_t*>(a);
35 cur = ctx;
36 ctx->creator->switch_to();
37
38 ctx->func(ctx->arg);
39 return NULL;
40 }
41 #endif
42
43 void context_t::init(void (*f)(void*), void* a)
44 {
45 func = f;
46 arg = a;
47 creator = current();
48
49 #ifdef USE_UCONTEXT
50 getcontext(context.get());
51 context->uc_link = creator->context.get();
52 context->uc_stack.ss_size = 64*1024;
53 context->uc_stack.ss_sp = new void*[context->uc_stack.ss_size/sizeof(void*)];
54 #ifndef GLIBC_64BIT_PTR_BUG
55 makecontext(context.get(), (void(*)(void))&context_t::wrapper, 1, this);
56 #else
57 unsigned int hi(reinterpret_cast<unsigned long>(this) >> 32);
58 unsigned int lo(reinterpret_cast<unsigned long>(this));
59 makecontext(context.get(), (void(*)(void))&context_t::wrapper, 2, hi, lo);
60 #endif
61 switch_to();
62 #else
63 assert(flag == 0);
64
65 pthread_mutex_lock(&creator->mutex);
66 creator->flag = 0;
67 if (pthread_create(&thread, NULL, &context_t::wrapper, this) != 0)
68 abort();
69 pthread_detach(thread);
70 while (!creator->flag)
71 pthread_cond_wait(&creator->cond, &creator->mutex);
72 pthread_mutex_unlock(&creator->mutex);
73 #endif
74 }
75
76 context_t::~context_t()
77 {
78 assert(this != cur);
79 }
80
81 void context_t::switch_to()
82 {
83 assert(this != cur);
84 #ifdef USE_UCONTEXT
85 context_t* prev = cur;
86 cur = this;
87 if (swapcontext(prev->context.get(), context.get()) != 0)
88 abort();
89 #else
90 cur->flag = 0;
91 this->flag = 1;
92 pthread_mutex_lock(&this->mutex);
93 pthread_cond_signal(&this->cond);
94 pthread_mutex_unlock(&this->mutex);
95 pthread_mutex_lock(&cur->mutex);
96 while (!cur->flag)
97 pthread_cond_wait(&cur->cond, &cur->mutex);
98 pthread_mutex_unlock(&cur->mutex);
99 #endif
100 }
101
102 context_t* context_t::current()
103 {
104 if (cur == NULL)
105 {
106 cur = new context_t;
107 #ifdef USE_UCONTEXT
108 getcontext(cur->context.get());
109 #else
110 cur->thread = pthread_self();
111 cur->flag = 1;
112 #endif
113 }
114 return cur;
115 }
116