blob: b4be600566fea8edc43c5753e9d0d8c3b853cafc [file] [log] [blame]
#pragma once
#include "rd.h"
typedef struct rd_interval_s {
rd_ts_t ri_ts_last; /* last interval timestamp */
rd_ts_t ri_fixed; /* fixed interval if provided interval is 0 */
int ri_backoff; /* back off the next interval by this much */
} rd_interval_t;
static RD_INLINE RD_UNUSED void rd_interval_init (rd_interval_t *ri) {
memset(ri, 0, sizeof(*ri));
}
/**
* Returns the number of microseconds the interval has been over-shot.
* If the return value is >0 (i.e., time for next intervalled something) then
* the time interval is updated for the next inteval.
*
* A current time can be provided in 'now', if set to 0 the time will be
* gathered automatically.
*
* If 'interval_us' is set to 0 the fixed interval will be used, see
* 'rd_interval_fixed()'.
*
* If this is the first time rd_interval() is called after an _init() or
* _reset() and the \p immediate parameter is true, then a positive value
* will be returned immediately even though the initial interval has not passed.
*/
#define rd_interval(ri,interval_us,now) rd_interval0(ri,interval_us,now,0)
#define rd_interval_immediate(ri,interval_us,now) \
rd_interval0(ri,interval_us,now,1)
static RD_INLINE RD_UNUSED rd_ts_t rd_interval0 (rd_interval_t *ri,
rd_ts_t interval_us,
rd_ts_t now,
int immediate) {
rd_ts_t diff;
if (!now)
now = rd_clock();
if (!interval_us)
interval_us = ri->ri_fixed;
if (ri->ri_ts_last || !immediate) {
diff = now - (ri->ri_ts_last + interval_us + ri->ri_backoff);
} else
diff = 1;
if (unlikely(diff > 0)) {
ri->ri_ts_last = now;
ri->ri_backoff = 0;
}
return diff;
}
/**
* Reset the interval to zero, i.e., the next call to rd_interval()
* will be immediate.
*/
static RD_INLINE RD_UNUSED void rd_interval_reset (rd_interval_t *ri) {
ri->ri_ts_last = 0;
ri->ri_backoff = 0;
}
/**
* Back off the next interval by `backoff_us` microseconds.
*/
static RD_INLINE RD_UNUSED void rd_interval_backoff (rd_interval_t *ri,
int backoff_us) {
ri->ri_backoff = backoff_us;
}
/**
* Expedite (speed up) the next interval by `expedite_us` microseconds.
* If `expedite_us` is 0 the interval will be set to trigger
* immedately on the next rd_interval() call.
*/
static RD_INLINE RD_UNUSED void rd_interval_expedite (rd_interval_t *ri,
int expedite_us) {
if (!expedite_us)
ri->ri_ts_last = 0;
else
ri->ri_backoff = -expedite_us;
}
/**
* Specifies a fixed interval to use if rd_interval() is called with
* `interval_us` set to 0.
*/
static RD_INLINE RD_UNUSED void rd_interval_fixed (rd_interval_t *ri,
rd_ts_t fixed_us) {
ri->ri_fixed = fixed_us;
}
/**
* Disables the interval (until rd_interval_init()/reset() is called).
* A disabled interval will never return a positive value from
* rd_interval().
*/
static RD_INLINE RD_UNUSED void rd_interval_disable (rd_interval_t *ri) {
/* Set last beat to a large value a long time in the future. */
ri->ri_ts_last = 6000000000000000000LL; /* in about 190000 years */
}
/**
* Returns true if the interval is disabled.
*/
static RD_INLINE RD_UNUSED int rd_interval_disabled (const rd_interval_t *ri) {
return ri->ri_ts_last == 6000000000000000000LL;
}