Esempio n. 1
0
int dill_msleep(int64_t deadline) {
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) return -1;
    /* Actual waiting. */
    struct dill_tmclause tmcl;
    dill_timer(&tmcl, 1, deadline);
    int id = dill_wait();
    if(dill_slow(id < 0)) return -1;
    return 0;
}
Esempio n. 2
0
int dill_msleep(int64_t deadline, const char *where) {
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) return -1;
    /* Trivial case. No waiting, but we do want a context switch. */
    if(dill_slow(deadline == 0)) return yield();
    /* Actual waiting. */
    struct dill_tmcl tmcl;
    if(deadline > 0)
        dill_timer(&tmcl, 1, deadline);
    int id = dill_wait(where);
    if(dill_slow(id < 0)) return -1;
    dill_assert(id == 1);
    return 0;
}
Esempio n. 3
0
int dill_fdout(int fd, int64_t deadline) {
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) return -1;
    /* Start waiting for the fd. */
    struct dill_fdclause fdcl;
    rc = dill_pollset_out(&fdcl, 1, fd);
    if(dill_slow(rc < 0)) return -1;
    /* Optionally, start waiting for a timer. */
    struct dill_tmclause tmcl;
    dill_timer(&tmcl, 2, deadline);
    /* Block. */
    int id = dill_wait();
    if(dill_slow(id < 0)) return -1;
    if(dill_slow(id == 2)) {errno = ETIMEDOUT; return -1;}
    return 0;
}
int dill_proc_prologue(int *hndl) {
    int err;
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) {err = ECANCELED; goto error1;}
    struct dill_proc *proc = malloc(sizeof(struct dill_proc));
    if(dill_slow(!proc)) {err = ENOMEM; goto error1;}
    proc->pid = -1;
    int closepipe[2];
    rc = pipe(closepipe);
    if(dill_slow(rc < 0)) {err = ENOMEM; goto error2;}
    proc->closepipe = closepipe[1];
    int h = handle(dill_proc_type, proc, &dill_proc_vfptrs);
    if(dill_slow(h < 0)) {err = errno; goto error3;}
    pid_t pid = fork();
    if(dill_slow(pid < 0)) {err = ENOMEM; goto error4;}
    /* Child. */
    if(pid == 0) {
        /* We don't need the sending end of the pipe. */
        close(closepipe[1]);
        /* This call will also promote currently running coroutine to the
           position of main coroutine in the process. */
        dill_postfork(closepipe[0]);
        return 1;
    }
    /* Parent. */
    close(closepipe[0]);
    proc->pid = pid;
    *hndl = h;
    return 0;
error4:
    hclose(h);
error3:
    close(closepipe[0]);
    close(closepipe[1]);
error2:
    free(proc);
error1:
    errno = err;
    *hndl = -1;
    return 0;
}
Esempio n. 5
0
File: cr.c Progetto: jimjag/libdill
int dill_bundle_wait(int h, int64_t deadline) {
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) return -1;
    struct dill_bundle *self = dill_hquery(h, dill_bundle_type);
    if(dill_slow(!self)) return -1;
    /* If there are no coroutines in the bundle succeed immediately. */
    if(dill_list_empty(&self->crs)) return 0;
    /* Otherwise wait for all coroutines to finish. */
    struct dill_clause cl;
    self->waiter = &cl;
    dill_waitfor(&cl, 0, NULL);
    struct dill_tmclause tmcl;
    dill_timer(&tmcl, 1, deadline);
    int id = dill_wait();
    self->waiter = NULL;
    if(dill_slow(id < 0)) return -1;
    if(dill_slow(id == 1)) {errno = ETIMEDOUT; return -1;}
    dill_assert(id == 0);
    return 0;
}
Esempio n. 6
0
int dill_fdout(int fd, int64_t deadline, const char *where) {
    /* TODO: deadline == 0? */
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) return -1;
    /* Start waiting for the fd. */
    struct dill_clause fdcl;
    rc = dill_out(&fdcl, 1, fd);
    if(dill_slow(rc < 0)) return -1;
    /* Optionally, start waiting for a timer. */
    struct dill_tmcl tmcl;
    if(deadline > 0)
        dill_timer(&tmcl, 2, deadline);
    /* Block. */
    int id = dill_wait(where);
    if(dill_slow(id < 0)) return -1;
    if(dill_slow(id == 2)) {errno = ETIMEDOUT; return -1;}
    dill_assert(id == 1);
    return 0;
}
Esempio n. 7
0
File: cr.c Progetto: jimjag/libdill
/* 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;
}