13static const int DEBUG = 0;
16int check(
const char * message,
int result) {
20 if (DEBUG) fprintf(stderr,
"deadlock detected result=%d errno=%d\n", result,
errno);
23 if (DEBUG) fprintf(stderr,
"error detected result=%d errno=%d\n", result,
errno);
34 context->id = pthread_self();
36 check(
"coroutine_initialize_main:pthread_cond_init",
37 pthread_cond_init(&context->schedule, NULL)
41 assert(context->shared);
43 context->shared->main = context;
44 context->shared->count = 1;
47 pthread_mutexattr_t attr;
48 pthread_mutexattr_init(&attr);
49 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
51 check(
"coroutine_initialize_main:pthread_mutex_init",
52 pthread_mutex_init(&context->shared->guard, &attr)
55 check(
"coroutine_initialize_main:pthread_mutex_init",
56 pthread_mutex_init(&context->shared->guard, NULL)
63 if (context->shared) {
64 size_t count = (context->shared->count -= 1);
67 if (DEBUG) fprintf(stderr,
"coroutine_release:pthread_mutex_destroy(%p)\n", &context->shared->guard);
68 pthread_mutex_destroy(&context->shared->guard);
69 free(context->shared);
72 context->shared = NULL;
74 if (DEBUG) fprintf(stderr,
"coroutine_release:pthread_cond_destroy(%p)\n", &context->schedule);
75 pthread_cond_destroy(&context->schedule);
79void coroutine_initialize(
81 coroutine_start start,
85 assert(start && stack && size >= 1024);
88 context->shared = NULL;
89 context->start = start;
90 context->stack = stack;
95int is_locked(pthread_mutex_t * mutex) {
96 int result = pthread_mutex_trylock(mutex);
100 pthread_mutex_unlock(mutex);
110void coroutine_guard_unlock(
void * _context)
114 if (DEBUG) fprintf(stderr,
"coroutine_guard_unlock:pthread_mutex_unlock\n");
116 check(
"coroutine_guard_unlock:pthread_mutex_unlock",
117 pthread_mutex_unlock(&context->shared->guard)
124 if (DEBUG) fprintf(stderr,
"coroutine_wait:pthread_mutex_lock(guard=%p is_locked=%d)\n", &context->shared->guard, is_locked(&context->shared->guard));
125 check(
"coroutine_wait:pthread_mutex_lock",
126 pthread_mutex_lock(&context->shared->guard)
129 if (DEBUG) fprintf(stderr,
"coroutine_wait:pthread_mutex_unlock(guard)\n");
130 pthread_mutex_unlock(&context->shared->guard);
134void coroutine_trampoline_cleanup(
void *_context) {
136 coroutine_release(context);
139void * coroutine_trampoline(
void * _context)
142 assert(context->shared);
144 pthread_cleanup_push(coroutine_trampoline_cleanup, context);
146 coroutine_wait(context);
148 context->start(context->from, context);
150 pthread_cleanup_pop(1);
161 result = pthread_attr_init(&attr);
166 result = pthread_attr_setstack(&attr, context->stack, (
size_t)context->size);
168 pthread_attr_destroy(&attr);
172 result = pthread_cond_init(&context->schedule, NULL);
174 pthread_attr_destroy(&attr);
178 result = pthread_create(&context->id, &attr, coroutine_trampoline, context);
180 pthread_attr_destroy(&attr);
181 if (DEBUG) fprintf(stderr,
"coroutine_create_thread:pthread_cond_destroy(%p)\n", &context->schedule);
182 pthread_cond_destroy(&context->schedule);
186 context->shared->count += 1;
193 assert(current->shared);
196 target->from = current;
198 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_mutex_lock(guard=%p is_locked=%d)\n", ¤t->shared->guard, is_locked(¤t->shared->guard));
199 pthread_mutex_lock(¤t->shared->guard);
200 pthread_cleanup_push(coroutine_guard_unlock, current);
203 if (target->shared == NULL) {
204 target->shared = current->shared;
206 if (DEBUG) fprintf(stderr,
"coroutine_transfer:coroutine_create_thread...\n");
207 if (coroutine_create_thread(target)) {
208 if (DEBUG) fprintf(stderr,
"coroutine_transfer:coroutine_create_thread failed\n");
209 target->shared = NULL;
210 target->from = previous;
214 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_cond_signal(target)\n");
215 pthread_cond_signal(&target->schedule);
219 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_cond_wait(schedule=%p, guard=%p, is_locked=%d)\n", ¤t->schedule, ¤t->shared->guard, is_locked(¤t->shared->guard));
220 check(
"coroutine_transfer:pthread_cond_wait",
221 pthread_cond_wait(¤t->schedule, ¤t->shared->guard)
224 if (DEBUG) fprintf(stderr,
"coroutine_transfer:pthread_cleanup_pop\n");
225 pthread_cleanup_pop(1);
229 pthread_testcancel();
232 target->from = previous;
239 if (DEBUG) fprintf(stderr,
"coroutine_join:pthread_cancel\n");
240 int result = pthread_cancel(context->id);
241 if (result == -1 &&
errno == ESRCH) {
246 check(
"coroutine_join:pthread_cancel", result);
248 if (DEBUG) fprintf(stderr,
"coroutine_join:pthread_join\n");
249 check(
"coroutine_join:pthread_join",
250 pthread_join(context->id, NULL)
253 if (DEBUG) fprintf(stderr,
"coroutine_join:pthread_join done\n");
258 if (DEBUG) fprintf(stderr,
"coroutine_destroy\n");
263 if (context->shared == NULL)
return;
265 if (context == context->shared->main) {
266 context->shared->main = NULL;
267 coroutine_release(context);
269 coroutine_join(context);
270 assert(context->shared == NULL);
#define errno
Ractor-aware version of errno.