Path: blob/main/sys/contrib/ck/src/ck_ec_timeutil.h
48261 views
#ifndef CK_EC_TIMEUTIL_H1#define CK_EC_TIMEUTIL_H2#include <ck_cc.h>3#include <ck_ec.h>4#include <ck_limits.h>5#include <ck_stdint.h>6#include <sys/time.h>78#define TIME_MAX ((time_t)((1ULL << ((sizeof(time_t) * CHAR_BIT) - 1)) - 1))9#define NSEC_MAX ((1000L * 1000 * 1000) - 1)1011/*12* Approximates (nsec * multiplier) >> shift. Clamps to UINT32_MAX on13* overflow.14*/15CK_CC_UNUSED static uint32_t16wait_time_scale(uint32_t nsec,17uint32_t multiplier,18unsigned int shift)19{20uint64_t temp = (uint64_t)nsec * multiplier;21uint64_t max = (uint64_t)UINT32_MAX << shift;2223if (temp >= max) {24return UINT32_MAX;25}2627return temp >> shift;28}293031/*32* Returns ts + ns. ns is clamped to at most 1 second. Clamps the33* return value to TIME_MAX, NSEC_MAX on overflow.34*35*/36CK_CC_UNUSED static struct timespec timespec_add_ns(const struct timespec ts,37uint32_t ns)38{39struct timespec ret = {40.tv_sec = TIME_MAX,41.tv_nsec = NSEC_MAX42};43time_t sec;44uint32_t sum_ns;4546if (ns > (uint32_t)NSEC_MAX) {47if (ts.tv_sec >= TIME_MAX) {48return ret;49}5051ret.tv_sec = ts.tv_sec + 1;52ret.tv_nsec = ts.tv_nsec;53return ret;54}5556sec = ts.tv_sec;57sum_ns = ns + ts.tv_nsec;58if (sum_ns > NSEC_MAX) {59if (sec >= TIME_MAX) {60return ret;61}6263sec++;64sum_ns -= (NSEC_MAX + 1);65}6667ret.tv_sec = sec;68ret.tv_nsec = sum_ns;69return ret;70}717273/*74* Returns ts + inc. If inc is negative, it is normalized to 0.75* Clamps the return value to TIME_MAX, NSEC_MAX on overflow.76*/77CK_CC_UNUSED static struct timespec timespec_add(const struct timespec ts,78const struct timespec inc)79{80/* Initial return value is clamped to infinite future. */81struct timespec ret = {82.tv_sec = TIME_MAX,83.tv_nsec = NSEC_MAX84};85time_t sec;86unsigned long nsec;8788/* Non-positive delta is a no-op. Invalid nsec is another no-op. */89if (inc.tv_sec < 0 || inc.tv_nsec < 0 || inc.tv_nsec > NSEC_MAX) {90return ts;91}9293/* Detect overflow early. */94if (inc.tv_sec > TIME_MAX - ts.tv_sec) {95return ret;96}9798sec = ts.tv_sec + inc.tv_sec;99/* This sum can't overflow if the inputs are valid.*/100nsec = (unsigned long)ts.tv_nsec + inc.tv_nsec;101102if (nsec > NSEC_MAX) {103if (sec >= TIME_MAX) {104return ret;105}106107sec++;108nsec -= (NSEC_MAX + 1);109}110111ret.tv_sec = sec;112ret.tv_nsec = nsec;113return ret;114}115116/* Compares two timespecs. Returns -1 if x < y, 0 if x == y, and 1 if x > y. */117CK_CC_UNUSED static int timespec_cmp(const struct timespec x,118const struct timespec y)119{120if (x.tv_sec != y.tv_sec) {121return (x.tv_sec < y.tv_sec) ? -1 : 1;122}123124if (x.tv_nsec != y.tv_nsec) {125return (x.tv_nsec < y.tv_nsec) ? -1 : 1;126}127128return 0;129}130131/*132* Overwrites now with the current CLOCK_MONOTONIC time, and returns133* true if the current time is greater than or equal to the deadline,134* or the clock is somehow broken.135*/136CK_CC_UNUSED static bool check_deadline(struct timespec *now,137const struct ck_ec_ops *ops,138const struct timespec deadline)139{140int r;141142r = ops->gettime(ops, now);143if (r != 0) {144return true;145}146147return timespec_cmp(*now, deadline) >= 0;148}149#endif /* !CK_EC_TIMEUTIL_H */150151152