/** * Dispatch timers. * Will block up to 'timeout' microseconds before returning. */ void rd_kafka_timers_run (rd_kafka_timers_t *rkts, int timeout_us) { rd_ts_t now = rd_clock(); rd_ts_t end = now + timeout_us; rd_kafka_timers_lock(rkts); while (!rd_atomic32_get(&rkts->rkts_rk->rk_terminate) && now <= end) { int64_t sleeptime; rd_kafka_timer_t *rtmr; if (timeout_us != RD_POLL_NOWAIT) { sleeptime = rd_kafka_timers_next(rkts, timeout_us, 0/*no-lock*/); if (sleeptime > 0) { cnd_timedwait_ms(&rkts->rkts_cond, &rkts->rkts_lock, (int)(sleeptime / 1000)); } } now = rd_clock(); while ((rtmr = TAILQ_FIRST(&rkts->rkts_timers)) && rtmr->rtmr_next <= now) { rd_kafka_timer_unschedule(rkts, rtmr); rd_kafka_timers_unlock(rkts); rtmr->rtmr_callback(rkts, rtmr->rtmr_arg); rd_kafka_timers_lock(rkts); /* Restart timer, unless it has been stopped, or * already reschedueld (start()ed) from callback. */ if (rd_kafka_timer_started(rtmr) && !rd_kafka_timer_scheduled(rtmr)) rd_kafka_timer_schedule(rkts, rtmr, 0); } if (timeout_us == RD_POLL_NOWAIT) { /* Only iterate once, even if rd_clock doesn't change */ break; } } rd_kafka_timers_unlock(rkts); }
/** * Delay the next timer invocation by 'backoff_us' */ void rd_kafka_timer_backoff (rd_kafka_timers_t *rkts, rd_kafka_timer_t *rtmr, int backoff_us) { rd_kafka_timers_lock(rkts); if (rd_kafka_timer_scheduled(rtmr)) rd_kafka_timer_unschedule(rkts, rtmr); rd_kafka_timer_schedule(rkts, rtmr, backoff_us); rd_kafka_timers_unlock(rkts); }
void rd_kafka_timers_destroy (rd_kafka_timers_t *rkts) { rd_kafka_timer_t *rtmr; rd_kafka_timers_lock(rkts); rkts->rkts_enabled = 0; while ((rtmr = TAILQ_FIRST(&rkts->rkts_timers))) rd_kafka_timer_stop(rkts, rtmr, 0); rd_kafka_assert(rkts->rkts_rk, TAILQ_EMPTY(&rkts->rkts_timers)); rd_kafka_timers_unlock(rkts); cnd_destroy(&rkts->rkts_cond); mtx_destroy(&rkts->rkts_lock); }
/** * Start the provided timer with the given interval. * Upon expiration of the interval (us) the callback will be called in the * main rdkafka thread, after callback return the timer will be restarted. * * Use rd_kafka_timer_stop() to stop a timer. */ void rd_kafka_timer_start (rd_kafka_timers_t *rkts, rd_kafka_timer_t *rtmr, int interval, void (*callback) (rd_kafka_timers_t *rkts, void *arg), void *arg) { rd_kafka_timers_lock(rkts); rd_kafka_timer_stop(rkts, rtmr, 0/*!lock*/); rtmr->rtmr_interval = interval; rtmr->rtmr_callback = callback; rtmr->rtmr_arg = arg; rd_kafka_timer_schedule(rkts, rtmr, 0); rd_kafka_timers_unlock(rkts); }
/** * Stop a timer that may be started. * If called from inside a timer callback 'lock' must be 0, else 1. */ void rd_kafka_timer_stop (rd_kafka_timers_t *rkts, rd_kafka_timer_t *rtmr, int lock) { if (lock) rd_kafka_timers_lock(rkts); if (!rd_kafka_timer_started(rtmr)) { if (lock) rd_kafka_timers_unlock(rkts); return; } if (rd_kafka_timer_scheduled(rtmr)) rd_kafka_timer_unschedule(rkts, rtmr); rtmr->rtmr_interval = 0; if (lock) rd_kafka_timers_unlock(rkts); }
/** * @returns the delta time to the next time (>=0) this timer fires, or -1 * if timer is stopped. */ rd_ts_t rd_kafka_timer_next (rd_kafka_timers_t *rkts, rd_kafka_timer_t *rtmr, int do_lock) { rd_ts_t now = rd_clock(); rd_ts_t delta = -1; if (do_lock) rd_kafka_timers_lock(rkts); if (rd_kafka_timer_scheduled(rtmr)) { delta = rtmr->rtmr_next - now; if (delta < 0) delta = 0; } if (do_lock) rd_kafka_timers_unlock(rkts); return delta; }
/** * Returns the delta time to the next timer to fire, capped by 'timeout_ms'. */ rd_ts_t rd_kafka_timers_next (rd_kafka_timers_t *rkts, int timeout_us, int do_lock) { rd_ts_t now = rd_clock(); rd_ts_t sleeptime = 0; rd_kafka_timer_t *rtmr; if (do_lock) rd_kafka_timers_lock(rkts); if (likely((rtmr = TAILQ_FIRST(&rkts->rkts_timers)) != NULL)) { sleeptime = rtmr->rtmr_next - now; if (sleeptime < 0) sleeptime = 0; else if (sleeptime > (rd_ts_t)timeout_us) sleeptime = (rd_ts_t)timeout_us; } else sleeptime = (rd_ts_t)timeout_us; if (do_lock) rd_kafka_timers_unlock(rkts); return sleeptime; }
/** * Interrupt rd_kafka_timers_run(). * Used for termination. */ void rd_kafka_timers_interrupt (rd_kafka_timers_t *rkts) { rd_kafka_timers_lock(rkts); cnd_signal(&rkts->rkts_cond); rd_kafka_timers_unlock(rkts); }