int main(int argc, char **argv) { coro_create(&mainctx, NULL, NULL, NULL, 0); coro_stack_alloc(&stack, 0); coro_create(&ctx, coro_body, NULL, stack.sptr, stack.ssze); printf("Created a coro\n"); coro_transfer(&mainctx, &ctx); printf("Back in main\n"); coro_transfer(&mainctx, &ctx); printf("Back in main again\n"); return 0; }
void coro_body(void *arg) { int i = *(int*)arg; while(1) { count++; if(i == (INX - 1)) { coro_transfer(&ctx[i], &mainctx); continue; } coro_transfer(&ctx[i], &ctx[i+1]); } }
void join() { if (!detached) return; #if defined(__APPLE__) || defined(__linux__) /* Release GIL and disassociate from thread state (which was originally associated with the main Python thread) */ py::gil_scoped_release thread_state(true); coro_transfer(&ctx_main, &ctx_thread); coro_stack_free(&stack); /* Destroy the thread state that was created in mainloop() */ { py::gil_scoped_acquire acquire; acquire.dec_ref(); } #endif thread.join(); detached = false; #if defined(__APPLE__) || defined(__linux__) /* Reacquire GIL and reassociate with thread state [via RAII destructor in 'thread_state'] */ #endif }
int main() { coro_initialize(); enum { STACKSIZE = 4096 }; struct timeval tpend, tpstart; void* stack; stack = malloc(STACKSIZE); void* args = NULL; int count = 0; coro_create(testContext, test, args, stack, STACKSIZE); gettimeofday(&tpstart, 0); while(count++ < 1000000) { coro_transfer(mainContext, testContext); } gettimeofday(&tpend, 0); float timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec; timeuse /= 1000000; printf("libcoro 切换1百万次耗时: %f 秒\n",timeuse); free(stack); // printf("\nreturn to the main\n"); return 0; }
int main(int argc, char **argv) { long counter = atol(argv[1]); int stacksize = atoi(argv[2]); printf("total:%ld, stackszie:%dKB\n", counter, stacksize); coro_stack_alloc(&mainstack, stacksize*1024); coro_create(&mainctx, NULL, NULL, mainstack.sptr, mainstack.ssze); int i; for(i=0; i<INX; i++) { index[i] = i; coro_stack_alloc(&stack[i], stacksize*1024); coro_create(&ctx[i], coro_body, &index[i], stack[i].sptr, stack[i].ssze); } while(1) { coro_transfer(&mainctx, &ctx[0]); count++; if(count > counter) { break; } } printf("switch count:%ld\n", count); return 0; }
void _swapFiber( Fiber *to, Fiber *from ) { assert( to->sptr ); assert( from->sptr ); coro_transfer( &to->coro_ctx, &from->coro_ctx ); }
void cerl_callback test(void* args) { for(;;) { //printf("\nthis is the test\n"); coro_transfer(testContext, mainContext); } }
void uvc_switch(uvc_ctx *prev, uvc_ctx *next){ printf("[switch] %s -> %s\n", prev->name, next->name); uvc_thread_env *env = uvc_get_env(); next->status = UVC_STATUS_RUNING; prev->status = UVC_STATUS_READY; env->runing_task = next; coro_transfer(&prev->cur, &next->cur); }
void ugh_subreq_wait(ugh_client_t *c) { if (0 < c->wait) { is_main_coro = 1; coro_transfer(&c->ctx, &ctx_main); is_main_coro = 0; } }
static void * coro_init (void *args_) { struct coro_init_args *args = (struct coro_init_args *)args_; coro_func func = args->func; void *arg = args->arg; coro_transfer (args->self, args->main); func (arg); return 0; }
static void coro_init (void) { volatile coro_func func = coro_init_func; volatile void *arg = coro_init_arg; coro_transfer (new_coro, create_coro); #if __GCC_HAVE_DWARF2_CFI_ASM && __amd64 asm (".cfi_undefined rip"); #endif func ((void *)arg); /* the new coro returned. bad. just abort() for now */ abort (); }
static void * coro_init (void *args_) { struct coro_init_args *args = (struct coro_init_args *)args_; coro_func func = args->func; void *arg = args->arg; pthread_mutex_lock (&coro_mutex); /* we try to be good citizens and use deferred cancellation and cleanup handlers */ pthread_cleanup_push (mutex_unlock_wrapper, &coro_mutex); coro_transfer (args->self, args->main); func (arg); pthread_cleanup_pop (1); return 0; }
void coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) { static coro_context nctx; static int once; if (!once) { once = 1; pthread_mutex_lock (&coro_mutex); pthread_cond_init (&nctx.cv, 0); null_tid = pthread_self (); } pthread_cond_init (&ctx->cv, 0); if (coro) { pthread_attr_t attr; struct coro_init_args args; args.func = coro; args.arg = arg; args.self = ctx; args.main = &nctx; pthread_attr_init (&attr); #if __UCLIBC__ /* exists, but is borked */ /*pthread_attr_setstacksize (&attr, (size_t)ssize);*/ #elif __CYGWIN__ /* POSIX, not here */ pthread_attr_setstacksize (&attr, (size_t)ssize); #else pthread_attr_setstack (&attr, sptr, (size_t)ssize); #endif pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); pthread_create (&ctx->id, &attr, coro_init, &args); coro_transfer (args.main, args.self); } else ctx->id = null_tid; }
static void ugh_client_wcb_recv(EV_P_ ev_io *w, int tev) { int nb; ugh_client_t *c = aux_memberof(ugh_client_t, wev_recv, w); nb = aux_unix_recv(w->fd, c->buf_recv.data, c->buf_recv.size); log_debug("client recv: %d: %.*s", nb, nb, c->buf_recv.data); if (0 == nb) { ugh_client_del(c); return; } if (0 > nb) { if (EAGAIN == errno) { ev_timer_again(loop, &c->wev_timeout); return; } ugh_client_del(c); return; } c->buf_recv.data += nb; c->buf_recv.size -= nb; ev_timer_again(loop, &c->wev_timeout); if (NULL == c->request_end) { int status = ugh_parser_client(c, c->buf_recv.data - nb, nb); if (UGH_AGAIN == status) { return; } if (UGH_HTTP_BAD_REQUEST <= status) { ugh_client_send(c, status); return; } if (UGH_HTTP_POST == c->method) { ugh_header_t *hdr_content_length = ugh_client_header_get_nt(c, "Content-Length"); if (0 != hdr_content_length->value.size) { c->content_length = atoi(hdr_content_length->value.data); if (c->content_length > (c->buf_recv.size + (c->buf_recv.data - c->request_end))) { c->body.data = aux_pool_nalloc(c->pool, c->content_length); c->body.size = c->buf_recv.data - c->request_end; memcpy(c->body.data, c->request_end, c->body.size); c->buf_recv.data = c->body.data + c->body.size; c->buf_recv.size = c->content_length - c->body.size; } else { c->body.data = c->request_end; c->body.size = c->buf_recv.data - c->request_end; } if (c->body.size < c->content_length) { return; } } } } else if (UGH_HTTP_POST == c->method) { c->body.size += nb; if (c->body.size < c->content_length) { return; } } ev_io_stop(loop, &c->wev_recv); ev_timer_stop(loop, &c->wev_timeout); #if 1 /* prepare post args */ ugh_header_t *hdr_content_type = ugh_client_header_get_nt(c, "Content-Type"); if (sizeof("application/x-www-form-urlencoded") - 1 == hdr_content_type->value.size && 0 == strncmp(hdr_content_type->value.data, "application/x-www-form-urlencoded", hdr_content_type->value.size)) { ugh_parser_client_body(c, c->body.data, c->body.size); } #endif #if 1 /* UGH_CORO ENABLE */ c->stack = aux_pool_malloc(c->pool, UGH_CORO_STACK); if (NULL == c->stack) { ugh_client_send(c, UGH_HTTP_INTERNAL_SERVER_ERROR); return; } coro_create(&c->ctx, ugh_client_ccb_handle, c, c->stack, UGH_CORO_STACK, &ctx_main); is_main_coro = 0; coro_transfer(&ctx_main, &c->ctx); is_main_coro = 1; #endif #if 0 /* UGH_CORO DISABLE */ ugh_client_ccb_handle(c); #endif }
void coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize) { coro_context nctx; # if CORO_SJLJ stack_t ostk, nstk; struct sigaction osa, nsa; sigset_t nsig, osig; # endif if (!coro) return; coro_init_func = coro; coro_init_arg = arg; new_coro = ctx; create_coro = &nctx; # if CORO_SJLJ /* we use SIGUSR2. first block it, then fiddle with it. */ sigemptyset (&nsig); sigaddset (&nsig, SIGUSR2); sigprocmask (SIG_BLOCK, &nsig, &osig); nsa.sa_handler = trampoline; sigemptyset (&nsa.sa_mask); nsa.sa_flags = SA_ONSTACK; if (sigaction (SIGUSR2, &nsa, &osa)) { perror ("sigaction"); abort (); } /* set the new stack */ nstk.ss_sp = STACK_ADJUST_PTR (sptr, ssize); /* yes, some platforms (IRIX) get this wrong. */ nstk.ss_size = STACK_ADJUST_SIZE (sptr, ssize); nstk.ss_flags = 0; if (sigaltstack (&nstk, &ostk) < 0) { perror ("sigaltstack"); abort (); } trampoline_done = 0; kill (getpid (), SIGUSR2); sigfillset (&nsig); sigdelset (&nsig, SIGUSR2); while (!trampoline_done) sigsuspend (&nsig); sigaltstack (0, &nstk); nstk.ss_flags = SS_DISABLE; if (sigaltstack (&nstk, 0) < 0) perror ("sigaltstack"); sigaltstack (0, &nstk); if (~nstk.ss_flags & SS_DISABLE) abort (); if (~ostk.ss_flags & SS_DISABLE) sigaltstack (&ostk, 0); sigaction (SIGUSR2, &osa, 0); sigprocmask (SIG_SETMASK, &osig, 0); # elif CORO_LOSER coro_setjmp (ctx->env); #if __CYGWIN__ && __i386__ ctx->env[8] = (long) coro_init; ctx->env[7] = (long) ((char *)sptr + ssize) - sizeof (long); #elif __CYGWIN__ && __x86_64__ ctx->env[7] = (long) coro_init; ctx->env[6] = (long) ((char *)sptr + ssize) - sizeof (long); #elif defined __MINGW32__ ctx->env[5] = (long) coro_init; ctx->env[4] = (long) ((char *)sptr + ssize) - sizeof (long); #elif defined _M_IX86 ((_JUMP_BUFFER *)&ctx->env)->Eip = (long) coro_init; ((_JUMP_BUFFER *)&ctx->env)->Esp = (long) STACK_ADJUST_PTR (sptr, ssize) - sizeof (long); #elif defined _M_AMD64 ((_JUMP_BUFFER *)&ctx->env)->Rip = (__int64) coro_init; ((_JUMP_BUFFER *)&ctx->env)->Rsp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64); #elif defined _M_IA64 ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64) coro_init; ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64) STACK_ADJUST_PTR (sptr, ssize) - sizeof (__int64); #else #error "microsoft libc or architecture not supported" #endif # elif CORO_LINUX coro_setjmp (ctx->env); #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP) ctx->env[0].__jmpbuf[JB_PC] = (long) coro_init; ctx->env[0].__jmpbuf[JB_SP] = (long) STACK_ADJUST_PTR (sptr, ssize) - sizeof (long); #elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__) ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init; ctx->env[0].__jmpbuf[0].__sp = (int *) ((char *)sptr + ssize) - sizeof (long); #elif defined (__GNU_LIBRARY__) && defined (__i386__) ctx->env[0].__jmpbuf[0].__pc = (char *) coro_init; ctx->env[0].__jmpbuf[0].__sp = (void *) ((char *)sptr + ssize) - sizeof (long); #elif defined (__GNU_LIBRARY__) && defined (__x86_64__) ctx->env[0].__jmpbuf[JB_PC] = (long) coro_init; ctx->env[0].__jmpbuf[0].__sp = (void *) ((char *)sptr + ssize) - sizeof (long); #else #error "linux libc or architecture not supported" #endif # elif CORO_IRIX coro_setjmp (ctx->env, 0); ctx->env[JB_PC] = (__uint64_t)coro_init; ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long); # elif CORO_ASM #if __i386__ || __x86_64__ ctx->sp = (void **)(ssize + (char *)sptr); *--ctx->sp = (void *)abort; /* needed for alignment only */ *--ctx->sp = (void *)coro_init; #if CORO_WIN_TIB *--ctx->sp = 0; /* ExceptionList */ *--ctx->sp = (char *)sptr + ssize; /* StackBase */ *--ctx->sp = sptr; /* StackLimit */ #endif #elif CORO_ARM /* return address stored in lr register, don't push anything */ #else #error unsupported architecture #endif ctx->sp -= NUM_SAVED; memset (ctx->sp, 0, sizeof (*ctx->sp) * NUM_SAVED); #if __i386__ || __x86_64__ /* done already */ #elif CORO_ARM ctx->sp[0] = coro; /* r4 */ ctx->sp[1] = arg; /* r5 */ ctx->sp[8] = (char *)coro_init; /* lr */ #else #error unsupported architecture #endif # elif CORO_UCONTEXT getcontext (&(ctx->uc)); ctx->uc.uc_link = 0; ctx->uc.uc_stack.ss_sp = sptr; ctx->uc.uc_stack.ss_size = (size_t)ssize; ctx->uc.uc_stack.ss_flags = 0; makecontext (&(ctx->uc), (void (*)())coro_init, 0); # endif coro_transfer (create_coro, new_coro); }
void coro_body(void *arg) { printf("OK\n"); coro_transfer(&ctx, &mainctx); printf("Back in coro\n"); coro_transfer(&ctx, &mainctx); }
void coro_switch(coroutine *from, coroutine *to) { ASSERT(from); ASSERT(to); coro_transfer(&from->ctx, &to->ctx); }
int ugh_subreq_del(ugh_subreq_t *r, uint32_t ft_type, int ft_errno) { ev_io_stop(loop, &r->wev_recv); ev_io_stop(loop, &r->wev_send); ev_io_stop(loop, &r->wev_connect); ev_timer_stop(loop, &r->wev_timeout); ev_timer_stop(loop, &r->wev_timeout_connect); close(r->wev_recv.fd); switch (ft_type) { case UGH_UPSTREAM_FT_ERROR: log_warn("connection or read/write error (%d: %s) on upstream socket (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s" , ft_errno , aux_strerror(ft_errno) , (int) r->u.host.size, r->u.host.data , (int) r->u.port.size, r->u.port.data , (int) r->u.uri.size, r->u.uri.data , r->u.args.size ? "?" : "" , (int) r->u.args.size, r->u.args.data , inet_ntoa(r->addr.sin_addr) , ntohs(r->addr.sin_port) , (int) r->c->uri.size, r->c->uri.data , r->c->args.size ? "?" : "" , (int) r->c->args.size, r->c->args.data ); break; case UGH_UPSTREAM_FT_TIMEOUT: log_warn("upstream timeout (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s" , (int) r->u.host.size, r->u.host.data , (int) r->u.port.size, r->u.port.data , (int) r->u.uri.size, r->u.uri.data , r->u.args.size ? "?" : "" , (int) r->u.args.size, r->u.args.data , inet_ntoa(r->addr.sin_addr) , ntohs(r->addr.sin_port) , (int) r->c->uri.size, r->c->uri.data , r->c->args.size ? "?" : "" , (int) r->c->args.size, r->c->args.data ); break; case UGH_UPSTREAM_FT_INVALID_HEADER: log_warn("invalid header in upstream response (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s" , (int) r->u.host.size, r->u.host.data , (int) r->u.port.size, r->u.port.data , (int) r->u.uri.size, r->u.uri.data , r->u.args.size ? "?" : "" , (int) r->u.args.size, r->u.args.data , inet_ntoa(r->addr.sin_addr) , ntohs(r->addr.sin_port) , (int) r->c->uri.size, r->c->uri.data , r->c->args.size ? "?" : "" , (int) r->c->args.size, r->c->args.data ); break; case UGH_UPSTREAM_FT_HTTP_500: case UGH_UPSTREAM_FT_HTTP_502: case UGH_UPSTREAM_FT_HTTP_503: case UGH_UPSTREAM_FT_HTTP_504: case UGH_UPSTREAM_FT_HTTP_404: case UGH_UPSTREAM_FT_HTTP_5XX: case UGH_UPSTREAM_FT_HTTP_4XX: log_warn("error status %u in upstream response (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s" , r->status , (int) r->u.host.size, r->u.host.data , (int) r->u.port.size, r->u.port.data , (int) r->u.uri.size, r->u.uri.data , r->u.args.size ? "?" : "" , (int) r->u.args.size, r->u.args.data , inet_ntoa(r->addr.sin_addr) , ntohs(r->addr.sin_port) , (int) r->c->uri.size, r->c->uri.data , r->c->args.size ? "?" : "" , (int) r->c->args.size, r->c->args.data ); break; case UGH_UPSTREAM_FT_TIMEOUT_CONNECT: log_warn("upstream connect timeout (%.*s:%.*s%.*s%s%.*s, addr=%s:%u) while %.*s%s%.*s" , (int) r->u.host.size, r->u.host.data , (int) r->u.port.size, r->u.port.data , (int) r->u.uri.size, r->u.uri.data , r->u.args.size ? "?" : "" , (int) r->u.args.size, r->u.args.data , inet_ntoa(r->addr.sin_addr) , ntohs(r->addr.sin_port) , (int) r->c->uri.size, r->c->uri.data , r->c->args.size ? "?" : "" , (int) r->c->args.size, r->c->args.data ); break; } /* stop if full timeout is already ticked out */ if (UGH_TIMEOUT_FULL == r->timeout_type && r->timeout < ev_now(loop) - r->response_time) { goto ok; } if (r->upstream && r->upstream_tries <= r->upstream->values_size && (r->c->s->cfg->next_upstream & ft_type)) { strp u_host; if (r->upstream_tries < r->upstream->values_size) { r->upstream_current += 1; /* * XXX MEGA HACK for antmat, if upstream has choose random * directive, we add additional (upstreams_count - 1) to current * upstream to imitate choosing random upstream right after FIRST * failure */ if (r->upstream->choose == UGH_UPSTREAM_CHOOSE_RANDOM && r->upstream_tries == 1) { r->upstream_current += aux_random() % (r->upstream->values_size - 1); } r->upstream_current %= r->upstream->values_size; r->upstream_tries++; r->addr.sin_family = AF_INET; r->addr.sin_port = htons(r->upstream->values[r->upstream_current].port); u_host = &r->upstream->values[r->upstream_current].host; } else if (0 < r->upstream->backup_values_size) { r->upstream->backup_values_curr += 1; r->upstream->backup_values_curr %= r->upstream->backup_values_size; r->upstream_tries++; r->addr.sin_family = AF_INET; r->addr.sin_port = htons(r->upstream->backup_values[r->upstream->backup_values_curr].port); u_host = &r->upstream->backup_values[r->upstream->backup_values_curr].host; } else { goto ok; } r->state = 0; /* XXX maybe here we should reinit the whole subreq structure? */ r->body.data = NULL; r->body.size = 0; r->b_send.rpos = 0; r->b_send.wpos = 0; r->buf_recv.data = r->buf_recv_data; r->buf_recv.size = UGH_SUBREQ_BUF; ugh_subreq_gen(r, u_host); JudyLFreeArray(&r->headers_hash, PJE0); return ugh_resolver_addq(r->c->s->resolver, u_host->data, u_host->size, r->resolver_ctx); } ok: r->ft_type = ft_type; r->response_time = ev_now(loop) - r->response_time; if (r->connection_time == 0) { r->connection_time = r->response_time; } if (/* NULL == r->handle &&*/ (r->flags & UGH_SUBREQ_WAIT)) { r->c->wait--; /* We check is_main_coro here, because we could possibly call * ugh_subreq_del from module coroutine (e.g. when IP-address of * subrequest was definitely mallformed) and in this case we don't need * to call coro_transfer */ if (0 == r->c->wait && is_main_coro) { is_main_coro = 0; coro_transfer(&ctx_main, &r->c->ctx); is_main_coro = 1; } /* coro_transfer(&ctx_main, &r->c->ctx); */ } if ((r->flags & UGH_SUBREQ_PUSH)) { ugh_header_t *h_content_type = ugh_subreq_header_get_nt(r, "Content-Type"); ugh_channel_add_message(r->ch, &r->body, &h_content_type->value, r); } JudyLFreeArray(&r->headers_hash, PJE0); aux_pool_free(r->c->pool); return 0; }