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