12static const int DEBUG = 0;
15int check(
const char * message,
int result) {
19 if (DEBUG) fprintf(stderr,
"deadlock detected result=%d errno=%d\n", result,
errno);
22 if (DEBUG) fprintf(stderr,
"error detected result=%d errno=%d\n", result,
errno);
33 context->id = pthread_self();
34 context->start = NULL;
36 check(
"coroutine_initialize_main:pthread_mutex_init",
37 pthread_mutex_init(&context->guard, NULL)
40 check(
"coroutine_initialize_main:pthread_cond_init",
41 pthread_cond_init(&context->schedule, NULL)
44 context->suspended = 0;
45 context->initialized = 1;
46 context->thread_created = 0;
50void coroutine_initialize(
52 coroutine_start start,
56 assert(start && stack && size >= 1024);
59 context->start = start;
60 context->stack = stack;
63 check(
"coroutine_initialize:pthread_mutex_init",
64 pthread_mutex_init(&context->guard, NULL)
67 check(
"coroutine_initialize:pthread_cond_init",
68 pthread_cond_init(&context->schedule, NULL)
73 context->suspended = 1;
74 context->initialized = 1;
75 context->thread_created = 0;
80int is_locked(pthread_mutex_t * mutex) {
81 int result = pthread_mutex_trylock(mutex);
85 pthread_mutex_unlock(mutex);
95void coroutine_guard_unlock(
void * _context)
99 if (DEBUG) fprintf(stderr,
"coroutine_guard_unlock:pthread_mutex_unlock\n");
101 check(
"coroutine_guard_unlock:pthread_mutex_unlock",
102 pthread_mutex_unlock(&context->guard)
106void * coroutine_trampoline(
void * _context)
110 context->start(context->from, context);
121 result = pthread_attr_init(&attr);
126 result = pthread_attr_setstack(&attr, context->stack, (
size_t)context->size);
128 pthread_attr_destroy(&attr);
132 result = pthread_create(&context->id, &attr, coroutine_trampoline, context);
133 pthread_attr_destroy(&attr);
139 context->thread_created = 1;
149 check(
"coroutine_transfer:pthread_mutex_lock(current)",
150 pthread_mutex_lock(¤t->guard)
153 check(
"coroutine_transfer:pthread_mutex_lock(target)",
154 pthread_mutex_lock(&target->guard)
161 check(
"coroutine_transfer:pthread_mutex_unlock(target)",
162 pthread_mutex_unlock(&target->guard)
165 check(
"coroutine_transfer:pthread_mutex_unlock(current)",
166 pthread_mutex_unlock(¤t->guard)
172 assert(current->initialized);
173 assert(target->initialized);
174 assert(current != target);
178 coroutine_lock_pair(current, target);
180 if (current->start == NULL) {
183 current->id = pthread_self();
186 assert(current->thread_created);
187 assert(pthread_equal(current->id, pthread_self()));
189 assert(!current->suspended);
190 assert(target->suspended);
194 current->suspended = 1;
195 target->suspended = 0;
196 target->from = current;
199 if (target->start != NULL && !target->thread_created) {
200 if (DEBUG) fprintf(stderr,
"coroutine_transfer:coroutine_create_thread...\n");
201 result = coroutine_create_thread(target);
203 if (DEBUG) fprintf(stderr,
"coroutine_transfer:coroutine_create_thread failed\n");
206 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_cond_signal(target)\n");
207 result = pthread_cond_signal(&target->schedule);
211 target->from = previous;
212 target->suspended = 1;
213 current->suspended = 0;
214 coroutine_unlock_pair(current, target);
219 check(
"coroutine_transfer:pthread_mutex_unlock(target)",
220 pthread_mutex_unlock(&target->guard)
223 pthread_cleanup_push(coroutine_guard_unlock, current);
225 while (current->suspended) {
227 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_cond_wait(schedule=%p, guard=%p, is_locked=%d)\n", ¤t->schedule, ¤t->guard, is_locked(¤t->guard));
228 check(
"coroutine_transfer:pthread_cond_wait",
229 pthread_cond_wait(¤t->schedule, ¤t->guard)
233 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_cleanup_pop\n");
234 pthread_cleanup_pop(1);
238 pthread_testcancel();
242 return current->from;
247 if (DEBUG) fprintf(stderr,
"coroutine_join:pthread_cancel\n");
248 int result = pthread_cancel(context->id);
249 if (result == -1 &&
errno == ESRCH) {
254 check(
"coroutine_join:pthread_cancel", result);
256 if (DEBUG) fprintf(stderr,
"coroutine_join:pthread_join\n");
257 check(
"coroutine_join:pthread_join",
258 pthread_join(context->id, NULL)
261 if (DEBUG) fprintf(stderr,
"coroutine_join:pthread_join done\n");
266 if (DEBUG) fprintf(stderr,
"coroutine_destroy\n");
270 if (!context->initialized)
return;
272 if (context->thread_created) {
273 coroutine_join(context);
274 context->thread_created = 0;
277 if (DEBUG) fprintf(stderr,
"coroutine_destroy:pthread_cond_destroy(%p)\n", &context->schedule);
278 pthread_cond_destroy(&context->schedule);
279 pthread_mutex_destroy(&context->guard);
280 context->initialized = 0;
#define errno
Ractor-aware version of errno.