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