Exemple #1
0
int dill_wait(void)  {
    struct dill_ctx_cr *ctx = &dill_getctx->cr;
    /* Store the context of the current coroutine, if any. */
    if(dill_setjmp(ctx->r->ctx)) {
        /* We get here once the coroutine is resumed. */
        dill_slist_init(&ctx->r->clauses);
        errno = ctx->r->err;
        return ctx->r->id;
    }
    /* For performance reasons, we want to avoid excessive checking of current
       time, so we cache the value here. It will be recomputed only after
       a blocking call. */
    int64_t nw = dill_now();
    /*  Wait for timeouts and external events. However, if there are ready
       coroutines there's no need to poll for external events every time.
       Still, we'll do it at least once a second. The external signal may
       very well be a deadline or a user-issued command that cancels the CPU
       intensive operation. */
    if(dill_qlist_empty(&ctx->ready) || nw > ctx->last_poll + 1000) {
        int block = dill_qlist_empty(&ctx->ready);
        while(1) {
            /* Compute the timeout for the subsequent poll. */
            int timeout = 0;
            if(block) {
                if(dill_rbtree_empty(&ctx->timers))
                    timeout = -1;
                else {
                    int64_t deadline = dill_cont(
                        dill_rbtree_first(&ctx->timers),
                        struct dill_tmclause, item)->item.val;
                    timeout = (int) (nw >= deadline ? 0 : deadline - nw);
                }
            }
            /* Wait for events. */
            int fired = dill_pollset_poll(timeout);
            if(timeout != 0) nw = dill_now();
            if(dill_slow(fired < 0)) continue;
            /* Fire all expired timers. */
            if(!dill_rbtree_empty(&ctx->timers)) {
                while(!dill_rbtree_empty(&ctx->timers)) {
                    struct dill_tmclause *tmcl = dill_cont(
                        dill_rbtree_first(&ctx->timers),
                        struct dill_tmclause, item);
                    if(tmcl->item.val > nw)
                        break;
                    dill_trigger(&tmcl->cl, ETIMEDOUT);
                    fired = 1;
                }
            }
            /* Never retry the poll when in non-blocking mode. */
            if(!block || fired)
                break;
            /* If the timeout was hit but there were no expired timers,
               do the poll again. It can happen if the timers were canceled
               in the meantime. */
        }
        ctx->last_poll = nw;
    }
Exemple #2
0
int dill_ctx_cr_init(struct dill_ctx_cr *ctx) {
    /* This function is definitely called from the main coroutine, given that
       it's called only once and you can't even create a different coroutine
       without calling it. */
    ctx->r = &ctx->main;
    dill_qlist_init(&ctx->ready);
    dill_rbtree_init(&ctx->timers);
    /* We can't use now() here as the context is still being intialized. */
    ctx->last_poll = dill_mnow();
    /* Initialize the main coroutine. */
    memset(&ctx->main, 0, sizeof(ctx->main));
    ctx->main.ready.next = NULL;
    dill_slist_init(&ctx->main.clauses);
#if defined DILL_CENSUS
    dill_slist_init(&ctx->census);
#endif
    return 0;
}
Exemple #3
0
/* The initial part of go(). Allocates a new stack and bundle. */
int dill_prologue(sigjmp_buf **jb, void **ptr, size_t len, int bndl,
      const char *file, int line) {
    int err;
    struct dill_ctx_cr *ctx = &dill_getctx->cr;
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) {err = ECANCELED; goto error1;}
    /* If bundle is not supplied by the user create one. If user supplied a
       memory to use put the bundle at the beginning of the block. */
    int new_bundle = bndl < 0;
    if(new_bundle) {
        if(*ptr) {
            bndl = dill_bundle_mem(*ptr);
            *ptr = ((uint8_t*)*ptr) + sizeof(struct dill_bundle_storage);
            len -= sizeof(struct dill_bundle_storage);
        }
        else {
            bndl = dill_bundle();
        }
        if(dill_slow(bndl < 0)) {err = errno; goto error1;}
    }
    struct dill_bundle *bundle = dill_hquery(bndl, dill_bundle_type);
    if(dill_slow(!bundle)) {err = errno; goto error2;}
    /* Allocate a stack. */
    struct dill_cr *cr;
    size_t stacksz;
    if(!*ptr) {
        cr = (struct dill_cr*)dill_allocstack(&stacksz);
        if(dill_slow(!cr)) {err = errno; goto error2;}
    }
    else {
        /* The stack is supplied by the user.
           Align the top of the stack to a 16-byte boundary. */
        uintptr_t top = (uintptr_t)*ptr;
        top += len;
        top &= ~(uintptr_t)15;
        stacksz = top - (uintptr_t)*ptr;
        cr = (struct dill_cr*)top;
        if(dill_slow(stacksz < sizeof(struct dill_cr))) {
            err = ENOMEM; goto error2;}
    }
#if defined DILL_CENSUS
    /* Mark the bytes in the stack as unused. */
    uint8_t *bottom = ((char*)cr) - stacksz;
    int i;
    for(i = 0; i != stacksz; ++i)
        bottom[i] = 0xa0 + (i % 13);
#endif
    --cr;
    cr->vfs.query = dill_cr_query;
    cr->vfs.close = dill_cr_close;
    dill_list_insert(&cr->bundle, &bundle->crs);
    cr->ready.next = NULL;
    dill_slist_init(&cr->clauses);
    cr->closer = NULL;
    cr->no_blocking1 = 0;
    cr->no_blocking2 = 0;
    cr->done = 0;
    cr->mem = *ptr ? 1 : 0;
#if defined DILL_VALGRIND
    cr->sid = VALGRIND_STACK_REGISTER((char*)(cr + 1) - stacksz, cr);
#endif
#if defined DILL_CENSUS
    /* Find the appropriate census item if it exists. It's O(n) but meh. */
    cr->census = NULL;
    struct dill_slist *it;
    for(it = dill_slist_next(&ctx->census); it != &ctx->census;
          it = dill_slist_next(it)) {
        cr->census = dill_cont(it, struct dill_census_item, crs);
        if(cr->census->line == line && strcmp(cr->census->file, file) == 0)
            break;
    }
    /* Allocate it if it does not exist. */
    if(it == &ctx->census) {
        cr->census = malloc(sizeof(struct dill_census_item));
        dill_assert(cr->census);
        dill_slist_push(&ctx->census, &cr->census->crs);
        cr->census->file = file;
        cr->census->line = line;
        cr->census->max_stack = 0;
    }
    cr->stacksz = stacksz - sizeof(struct dill_cr);
#endif
    /* Return the context of the parent coroutine to the caller so that it can
       store its current state. It can't be done here because we are at the
       wrong stack frame here. */
    *jb = &ctx->r->ctx;
    /* Add parent coroutine to the list of coroutines ready for execution. */
    dill_resume(ctx->r, 0, 0);
    /* Mark the new coroutine as running. */
    *ptr = ctx->r = cr;
    /* In case of success go() returns the handle, bundle_go() returns 0. */
    return new_bundle ? bndl : 0;
error2:
    if(new_bundle) {
        rc = dill_hclose(bndl);
        dill_assert(rc == 0);
    }
error1:
    errno = err;
    return -1;
}
Exemple #4
0
int dill_ctx_stack_init(struct dill_ctx_stack *ctx) {
    ctx->count = 0;
    dill_slist_init(&ctx->cache);
    return 0;
}