Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/ck/src/ck_ec_timeutil.h
48261 views
1
#ifndef CK_EC_TIMEUTIL_H
2
#define CK_EC_TIMEUTIL_H
3
#include <ck_cc.h>
4
#include <ck_ec.h>
5
#include <ck_limits.h>
6
#include <ck_stdint.h>
7
#include <sys/time.h>
8
9
#define TIME_MAX ((time_t)((1ULL << ((sizeof(time_t) * CHAR_BIT) - 1)) - 1))
10
#define NSEC_MAX ((1000L * 1000 * 1000) - 1)
11
12
/*
13
* Approximates (nsec * multiplier) >> shift. Clamps to UINT32_MAX on
14
* overflow.
15
*/
16
CK_CC_UNUSED static uint32_t
17
wait_time_scale(uint32_t nsec,
18
uint32_t multiplier,
19
unsigned int shift)
20
{
21
uint64_t temp = (uint64_t)nsec * multiplier;
22
uint64_t max = (uint64_t)UINT32_MAX << shift;
23
24
if (temp >= max) {
25
return UINT32_MAX;
26
}
27
28
return temp >> shift;
29
}
30
31
32
/*
33
* Returns ts + ns. ns is clamped to at most 1 second. Clamps the
34
* return value to TIME_MAX, NSEC_MAX on overflow.
35
*
36
*/
37
CK_CC_UNUSED static struct timespec timespec_add_ns(const struct timespec ts,
38
uint32_t ns)
39
{
40
struct timespec ret = {
41
.tv_sec = TIME_MAX,
42
.tv_nsec = NSEC_MAX
43
};
44
time_t sec;
45
uint32_t sum_ns;
46
47
if (ns > (uint32_t)NSEC_MAX) {
48
if (ts.tv_sec >= TIME_MAX) {
49
return ret;
50
}
51
52
ret.tv_sec = ts.tv_sec + 1;
53
ret.tv_nsec = ts.tv_nsec;
54
return ret;
55
}
56
57
sec = ts.tv_sec;
58
sum_ns = ns + ts.tv_nsec;
59
if (sum_ns > NSEC_MAX) {
60
if (sec >= TIME_MAX) {
61
return ret;
62
}
63
64
sec++;
65
sum_ns -= (NSEC_MAX + 1);
66
}
67
68
ret.tv_sec = sec;
69
ret.tv_nsec = sum_ns;
70
return ret;
71
}
72
73
74
/*
75
* Returns ts + inc. If inc is negative, it is normalized to 0.
76
* Clamps the return value to TIME_MAX, NSEC_MAX on overflow.
77
*/
78
CK_CC_UNUSED static struct timespec timespec_add(const struct timespec ts,
79
const struct timespec inc)
80
{
81
/* Initial return value is clamped to infinite future. */
82
struct timespec ret = {
83
.tv_sec = TIME_MAX,
84
.tv_nsec = NSEC_MAX
85
};
86
time_t sec;
87
unsigned long nsec;
88
89
/* Non-positive delta is a no-op. Invalid nsec is another no-op. */
90
if (inc.tv_sec < 0 || inc.tv_nsec < 0 || inc.tv_nsec > NSEC_MAX) {
91
return ts;
92
}
93
94
/* Detect overflow early. */
95
if (inc.tv_sec > TIME_MAX - ts.tv_sec) {
96
return ret;
97
}
98
99
sec = ts.tv_sec + inc.tv_sec;
100
/* This sum can't overflow if the inputs are valid.*/
101
nsec = (unsigned long)ts.tv_nsec + inc.tv_nsec;
102
103
if (nsec > NSEC_MAX) {
104
if (sec >= TIME_MAX) {
105
return ret;
106
}
107
108
sec++;
109
nsec -= (NSEC_MAX + 1);
110
}
111
112
ret.tv_sec = sec;
113
ret.tv_nsec = nsec;
114
return ret;
115
}
116
117
/* Compares two timespecs. Returns -1 if x < y, 0 if x == y, and 1 if x > y. */
118
CK_CC_UNUSED static int timespec_cmp(const struct timespec x,
119
const struct timespec y)
120
{
121
if (x.tv_sec != y.tv_sec) {
122
return (x.tv_sec < y.tv_sec) ? -1 : 1;
123
}
124
125
if (x.tv_nsec != y.tv_nsec) {
126
return (x.tv_nsec < y.tv_nsec) ? -1 : 1;
127
}
128
129
return 0;
130
}
131
132
/*
133
* Overwrites now with the current CLOCK_MONOTONIC time, and returns
134
* true if the current time is greater than or equal to the deadline,
135
* or the clock is somehow broken.
136
*/
137
CK_CC_UNUSED static bool check_deadline(struct timespec *now,
138
const struct ck_ec_ops *ops,
139
const struct timespec deadline)
140
{
141
int r;
142
143
r = ops->gettime(ops, now);
144
if (r != 0) {
145
return true;
146
}
147
148
return timespec_cmp(*now, deadline) >= 0;
149
}
150
#endif /* !CK_EC_TIMEUTIL_H */
151
152