… | |
… | |
88 | volatile void *arg = coro_init_arg; |
88 | volatile void *arg = coro_init_arg; |
89 | |
89 | |
90 | coro_transfer (new_coro, create_coro); |
90 | coro_transfer (new_coro, create_coro); |
91 | |
91 | |
92 | #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64 |
92 | #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64 |
|
|
93 | /*asm (".cfi_startproc");*/ |
93 | asm (".cfi_undefined rip"); |
94 | /*asm (".cfi_undefined rip");*/ |
94 | #endif |
95 | #endif |
95 | |
96 | |
96 | func ((void *)arg); |
97 | func ((void *)arg); |
|
|
98 | |
|
|
99 | #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64 |
|
|
100 | /*asm (".cfi_endproc");*/ |
|
|
101 | #endif |
97 | |
102 | |
98 | /* the new coro returned. bad. just abort() for now */ |
103 | /* the new coro returned. bad. just abort() for now */ |
99 | abort (); |
104 | abort (); |
100 | } |
105 | } |
101 | |
106 | |
… | |
… | |
118 | # if CORO_ASM |
123 | # if CORO_ASM |
119 | |
124 | |
120 | #if __arm__ && \ |
125 | #if __arm__ && \ |
121 | (defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \ |
126 | (defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \ |
122 | || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ \ |
127 | || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ \ |
123 | || __ARCH_ARCH == 7) |
128 | || __ARM_ARCH == 7) |
124 | #define CORO_ARM 1 |
129 | #define CORO_ARM 1 |
125 | #endif |
130 | #endif |
126 | |
131 | |
127 | #if _WIN32 || __CYGWIN__ |
132 | #if _WIN32 || __CYGWIN__ |
128 | #define CORO_WIN_TIB 1 |
133 | #define CORO_WIN_TIB 1 |
… | |
… | |
500 | coro_func func; |
505 | coro_func func; |
501 | void *arg; |
506 | void *arg; |
502 | coro_context *self, *main; |
507 | coro_context *self, *main; |
503 | }; |
508 | }; |
504 | |
509 | |
505 | static pthread_t null_tid; |
|
|
506 | |
|
|
507 | /* I'd so love to cast pthread_mutex_unlock to void (*)(void *)... */ |
|
|
508 | static void |
|
|
509 | mutex_unlock_wrapper (void *arg) |
|
|
510 | { |
|
|
511 | pthread_mutex_unlock ((pthread_mutex_t *)arg); |
|
|
512 | } |
|
|
513 | |
|
|
514 | static void * |
510 | static void * |
515 | coro_init (void *args_) |
511 | coro_init (void *args_) |
516 | { |
512 | { |
517 | struct coro_init_args *args = (struct coro_init_args *)args_; |
513 | struct coro_init_args *args = (struct coro_init_args *)args_; |
518 | coro_func func = args->func; |
514 | coro_func func = args->func; |
519 | void *arg = args->arg; |
515 | void *arg = args->arg; |
520 | |
516 | |
521 | pthread_mutex_lock (&coro_mutex); |
|
|
522 | |
|
|
523 | /* we try to be good citizens and use deferred cancellation and cleanup handlers */ |
|
|
524 | pthread_cleanup_push (mutex_unlock_wrapper, &coro_mutex); |
|
|
525 | coro_transfer (args->self, args->main); |
517 | coro_transfer (args->self, args->main); |
526 | func (arg); |
518 | func (arg); |
527 | pthread_cleanup_pop (1); |
|
|
528 | |
519 | |
529 | return 0; |
520 | return 0; |
530 | } |
521 | } |
531 | |
522 | |
532 | void |
523 | void |
533 | coro_transfer (coro_context *prev, coro_context *next) |
524 | coro_transfer (coro_context *prev, coro_context *next) |
534 | { |
525 | { |
|
|
526 | pthread_mutex_lock (&coro_mutex); |
|
|
527 | |
|
|
528 | next->flags = 1; |
535 | pthread_cond_signal (&next->cv); |
529 | pthread_cond_signal (&next->cv); |
|
|
530 | |
|
|
531 | prev->flags = 0; |
|
|
532 | |
|
|
533 | while (!prev->flags) |
536 | pthread_cond_wait (&prev->cv, &coro_mutex); |
534 | pthread_cond_wait (&prev->cv, &coro_mutex); |
537 | #if __FreeBSD__ /* freebsd is of course broken and needs manual testcancel calls... yay... */ |
535 | |
538 | pthread_testcancel (); |
536 | if (prev->flags == 2) |
539 | #endif |
537 | { |
|
|
538 | pthread_mutex_unlock (&coro_mutex); |
|
|
539 | pthread_cond_destroy (&prev->cv); |
|
|
540 | pthread_detach (pthread_self ()); |
|
|
541 | pthread_exit (0); |
|
|
542 | } |
|
|
543 | |
|
|
544 | pthread_mutex_unlock (&coro_mutex); |
540 | } |
545 | } |
541 | |
546 | |
542 | void |
547 | void |
543 | coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) |
548 | coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) |
544 | { |
549 | { |
… | |
… | |
547 | |
552 | |
548 | if (!once) |
553 | if (!once) |
549 | { |
554 | { |
550 | once = 1; |
555 | once = 1; |
551 | |
556 | |
552 | pthread_mutex_lock (&coro_mutex); |
|
|
553 | pthread_cond_init (&nctx.cv, 0); |
557 | pthread_cond_init (&nctx.cv, 0); |
554 | null_tid = pthread_self (); |
|
|
555 | } |
558 | } |
556 | |
559 | |
557 | pthread_cond_init (&ctx->cv, 0); |
560 | pthread_cond_init (&ctx->cv, 0); |
558 | |
561 | |
559 | if (coro) |
562 | if (coro) |
560 | { |
563 | { |
561 | pthread_attr_t attr; |
564 | pthread_attr_t attr; |
562 | struct coro_init_args args; |
565 | struct coro_init_args args; |
|
|
566 | pthread_t id; |
563 | |
567 | |
564 | args.func = coro; |
568 | args.func = coro; |
565 | args.arg = arg; |
569 | args.arg = arg; |
566 | args.self = ctx; |
570 | args.self = ctx; |
567 | args.main = &nctx; |
571 | args.main = &nctx; |
… | |
… | |
575 | pthread_attr_setstacksize (&attr, (size_t)ssize); |
579 | pthread_attr_setstacksize (&attr, (size_t)ssize); |
576 | #else |
580 | #else |
577 | pthread_attr_setstack (&attr, sptr, (size_t)ssize); |
581 | pthread_attr_setstack (&attr, sptr, (size_t)ssize); |
578 | #endif |
582 | #endif |
579 | pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); |
583 | pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); |
580 | pthread_create (&ctx->id, &attr, coro_init, &args); |
584 | pthread_create (&id, &attr, coro_init, &args); |
581 | |
585 | |
582 | coro_transfer (args.main, args.self); |
586 | coro_transfer (args.main, args.self); |
583 | } |
587 | } |
584 | else |
|
|
585 | ctx->id = null_tid; |
|
|
586 | } |
588 | } |
587 | |
589 | |
588 | void |
590 | void |
589 | coro_destroy (coro_context *ctx) |
591 | coro_destroy (coro_context *ctx) |
590 | { |
592 | { |
591 | if (!pthread_equal (ctx->id, null_tid)) |
593 | pthread_mutex_lock (&coro_mutex); |
592 | { |
594 | ctx->flags = 2; |
593 | pthread_cancel (ctx->id); |
595 | pthread_cond_signal (&ctx->cv); |
594 | pthread_mutex_unlock (&coro_mutex); |
596 | pthread_mutex_unlock (&coro_mutex); |
595 | pthread_join (ctx->id, 0); |
|
|
596 | pthread_mutex_lock (&coro_mutex); |
|
|
597 | } |
|
|
598 | |
|
|
599 | pthread_cond_destroy (&ctx->cv); |
|
|
600 | } |
597 | } |
601 | |
598 | |
602 | /*****************************************************************************/ |
599 | /*****************************************************************************/ |
603 | /* fiber backend */ |
600 | /* fiber backend */ |
604 | /*****************************************************************************/ |
601 | /*****************************************************************************/ |