示例#1
0
文件: timer.c 项目: zbanks/libdill
int64_t now(void) {
#if (defined __GNUC__ || defined __clang__) && \
      (defined __i386__ || defined __x86_64__)
    /* Get the timestamp counter. This is time since startup, expressed in CPU
       cycles. Unlike gettimeofday() or similar function, it's extremely fast -
       it takes only few CPU cycles to evaluate. */
    uint32_t low;
    uint32_t high;
    __asm__ volatile("rdtsc" : "=a" (low), "=d" (high));
    int64_t tsc = (int64_t)((uint64_t)high << 32 | low);
    /* These global variables are used to hold the last seen timestamp counter
       and last seen time measurement. We'll initilise them the first time
       this function is called. */
    static int64_t last_tsc = -1;
    static int64_t last_now = -1;
    if(dill_slow(last_tsc < 0)) {
        last_tsc = tsc;
        last_now = dill_now();
    }   
    /* If TSC haven't jumped back or progressed more than 1/2 ms, we can use
       the cached time value. */
    if(dill_fast(tsc - last_tsc <= (DILL_CLOCK_PRECISION / 2) &&
          tsc >= last_tsc))
        return last_now;
    /* It's more than 1/2 ms since we've last measured the time.
       We'll do a new measurement now. */
    last_tsc = tsc;
    last_now = dill_now();
    return last_now;
#else
    return dill_now();
#endif
}
示例#2
0
文件: cr.c 项目: jimjag/libdill
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;
    }