time-util: add triple timestamp object
We already have a double timestamp object that we use whenever we need both a MONOTONIC and a REALTIME timestamp taken and stored. With this change we also add a triple timestamp object that in addition stores a BOOTTIME timestamp, which is useful for a few usecases. Note that we keep dual_timestamp around, as it is useful in many cases where triple_timestamp is not, in particular because retrieving the monotonic and realtime timestamps is much cheaper on Linux that getting the boottime timestamp.
This commit is contained in:
parent
b2bb19bbda
commit
fe624c4c07
|
@ -87,6 +87,16 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
|
|||
return ts;
|
||||
}
|
||||
|
||||
triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
|
||||
assert(ts);
|
||||
|
||||
ts->realtime = now(CLOCK_REALTIME);
|
||||
ts->monotonic = now(CLOCK_MONOTONIC);
|
||||
ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
assert(ts);
|
||||
|
@ -104,6 +114,24 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
|
|||
return ts;
|
||||
}
|
||||
|
||||
triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
|
||||
assert(ts);
|
||||
|
||||
if (u == USEC_INFINITY || u <= 0) {
|
||||
ts->realtime = ts->monotonic = ts->boottime = u;
|
||||
return ts;
|
||||
}
|
||||
|
||||
ts->realtime = u;
|
||||
delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
|
||||
ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
|
||||
ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
assert(ts);
|
||||
|
@ -136,6 +164,26 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
|
|||
return ts;
|
||||
}
|
||||
|
||||
usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
|
||||
|
||||
switch (clock) {
|
||||
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_REALTIME_ALARM:
|
||||
return ts->realtime;
|
||||
|
||||
case CLOCK_MONOTONIC:
|
||||
return ts->monotonic;
|
||||
|
||||
case CLOCK_BOOTTIME:
|
||||
case CLOCK_BOOTTIME_ALARM:
|
||||
return ts->boottime;
|
||||
|
||||
default:
|
||||
return USEC_INFINITY;
|
||||
}
|
||||
}
|
||||
|
||||
usec_t timespec_load(const struct timespec *ts) {
|
||||
assert(ts);
|
||||
|
||||
|
@ -1107,6 +1155,30 @@ clockid_t clock_boottime_or_monotonic(void) {
|
|||
return CLOCK_MONOTONIC;
|
||||
}
|
||||
|
||||
bool clock_supported(clockid_t clock) {
|
||||
struct timespec ts;
|
||||
|
||||
switch (clock) {
|
||||
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_REALTIME:
|
||||
return true;
|
||||
|
||||
case CLOCK_BOOTTIME:
|
||||
return clock_boottime_supported();
|
||||
|
||||
case CLOCK_BOOTTIME_ALARM:
|
||||
if (!clock_boottime_supported())
|
||||
return false;
|
||||
|
||||
/* fall through, after checking the cached value for CLOCK_BOOTTIME. */
|
||||
|
||||
default:
|
||||
/* For everything else, check properly */
|
||||
return clock_gettime(clock, &ts) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
int get_timezone(char **tz) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
const char *e;
|
||||
|
|
|
@ -39,6 +39,12 @@ typedef struct dual_timestamp {
|
|||
usec_t monotonic;
|
||||
} dual_timestamp;
|
||||
|
||||
typedef struct triple_timestamp {
|
||||
usec_t realtime;
|
||||
usec_t monotonic;
|
||||
usec_t boottime;
|
||||
} triple_timestamp;
|
||||
|
||||
#define USEC_INFINITY ((usec_t) -1)
|
||||
#define NSEC_INFINITY ((nsec_t) -1)
|
||||
|
||||
|
@ -69,7 +75,8 @@ typedef struct dual_timestamp {
|
|||
|
||||
#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
|
||||
|
||||
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
|
||||
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {})
|
||||
#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {})
|
||||
|
||||
usec_t now(clockid_t clock);
|
||||
nsec_t now_nsec(clockid_t clock);
|
||||
|
@ -79,11 +86,28 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
|
|||
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
|
||||
dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u);
|
||||
|
||||
triple_timestamp* triple_timestamp_get(triple_timestamp *ts);
|
||||
triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u);
|
||||
|
||||
#define DUAL_TIMESTAMP_HAS_CLOCK(clock) \
|
||||
IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC)
|
||||
|
||||
#define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \
|
||||
IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM)
|
||||
|
||||
static inline bool dual_timestamp_is_set(dual_timestamp *ts) {
|
||||
return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
|
||||
(ts->monotonic > 0 && ts->monotonic != USEC_INFINITY));
|
||||
}
|
||||
|
||||
static inline bool triple_timestamp_is_set(triple_timestamp *ts) {
|
||||
return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
|
||||
(ts->monotonic > 0 && ts->monotonic != USEC_INFINITY) ||
|
||||
(ts->boottime > 0 && ts->boottime != USEC_INFINITY));
|
||||
}
|
||||
|
||||
usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock);
|
||||
|
||||
usec_t timespec_load(const struct timespec *ts) _pure_;
|
||||
struct timespec *timespec_store(struct timespec *ts, usec_t u);
|
||||
|
||||
|
@ -113,6 +137,7 @@ int get_timezones(char ***l);
|
|||
bool timezone_is_valid(const char *name);
|
||||
|
||||
bool clock_boottime_supported(void);
|
||||
bool clock_supported(clockid_t clock);
|
||||
clockid_t clock_boottime_or_monotonic(void);
|
||||
|
||||
#define xstrftime(buf, fmt, tm) \
|
||||
|
|
Loading…
Reference in a new issue