1 /* ==========================================================================
2  * timeout.h - Tickless hierarchical timing wheel.
3  * --------------------------------------------------------------------------
4  * Copyright (c) 2013, 2014  William Ahern
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to permit
11  * persons to whom the Software is furnished to do so, subject to the
12  * following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
20  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  * ==========================================================================
25  */
26 #ifndef TIMEOUT_H
27 #define TIMEOUT_H
28 
29 #include <stdbool.h>    /* bool */
30 #include <stdio.h>      /* FILE */
31 
32 #include <inttypes.h>   /* PRIu64 PRIx64 PRIX64 uint64_t */
33 
34 #include "ext/tor_queue.h"  /* TAILQ(3) */
35 
36 
37 /*
38  * V E R S I O N  I N T E R F A C E S
39  *
40  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41 
42 #if !defined TIMEOUT_PUBLIC
43 #define TIMEOUT_PUBLIC
44 #endif
45 
46 #define TIMEOUT_VERSION TIMEOUT_V_REL
47 #define TIMEOUT_VENDOR  "william@25thandClement.com"
48 
49 #define TIMEOUT_V_REL 0x20160226
50 #define TIMEOUT_V_ABI 0x20160224
51 #define TIMEOUT_V_API 0x20160226
52 
53 TIMEOUT_PUBLIC int timeout_version(void);
54 
55 TIMEOUT_PUBLIC const char *timeout_vendor(void);
56 
57 TIMEOUT_PUBLIC int timeout_v_rel(void);
58 
59 TIMEOUT_PUBLIC int timeout_v_abi(void);
60 
61 TIMEOUT_PUBLIC int timeout_v_api(void);
62 
63 
64 /*
65  * I N T E G E R  T Y P E  I N T E R F A C E S
66  *
67  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
68 
69 #define TIMEOUT_C(n) UINT64_C(n)
70 #define TIMEOUT_PRIu PRIu64
71 #define TIMEOUT_PRIx PRIx64
72 #define TIMEOUT_PRIX PRIX64
73 
74 #define TIMEOUT_mHZ TIMEOUT_C(1000)
75 #define TIMEOUT_uHZ TIMEOUT_C(1000000)
76 #define TIMEOUT_nHZ TIMEOUT_C(1000000000)
77 
78 typedef uint64_t timeout_t;
79 
80 #define timeout_error_t int /* for documentation purposes */
81 
82 
83 /*
84  * C A L L B A C K  I N T E R F A C E
85  *
86  * Callback function parameters unspecified to make embedding into existing
87  * applications easier.
88  *
89  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90 
91 #ifndef TIMEOUT_CB_OVERRIDE
92 struct timeout_cb_t {
93 	void (*fn)(void);
94 	void *arg;
95 }; /* struct timeout_cb_t */
96 #endif
97 
98 /*
99  * T I M E O U T  I N T E R F A C E S
100  *
101  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
102 
103 #ifndef TIMEOUT_DISABLE_INTERVALS
104 #define TIMEOUT_INT 0x01 /* interval (repeating) timeout */
105 #endif
106 #define TIMEOUT_ABS 0x02 /* treat timeout values as absolute */
107 
108 #define TIMEOUT_INITIALIZER(flags) { (flags) }
109 
110 #define timeout_setcb(to, fn, arg) do { \
111 	(to)->callback.fn = (fn);       \
112 	(to)->callback.arg = (arg);     \
113 } while (0)
114 
115 struct timeout {
116 	int flags;
117 
118 	timeout_t expires;
119 	/* absolute expiration time */
120 
121 	struct timeout_list *pending;
122 	/* timeout list if pending on wheel or expiry queue */
123 
124 	TOR_TAILQ_ENTRY(timeout) tqe;
125 	/* entry member for struct timeout_list lists */
126 
127 #ifndef TIMEOUT_DISABLE_CALLBACKS
128 	struct timeout_cb_t callback;
129 	/* optional callback information */
130 #endif
131 
132 #ifndef TIMEOUT_DISABLE_INTERVALS
133 	timeout_t interval;
134 	/* timeout interval if periodic */
135 #endif
136 
137 #ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
138 	struct timeouts *timeouts;
139 	/* timeouts collection if member of */
140 #endif
141 }; /* struct timeout */
142 
143 
144 TIMEOUT_PUBLIC struct timeout *timeout_init(struct timeout *, int);
145 /* initialize timeout structure (same as TIMEOUT_INITIALIZER) */
146 
147 #ifndef TIMEOUT_DISABLE_RELATIVE_ACCESS
148 TIMEOUT_PUBLIC bool timeout_pending(struct timeout *);
149 /* true if on timing wheel, false otherwise */
150 
151 TIMEOUT_PUBLIC bool timeout_expired(struct timeout *);
152 /* true if on expired queue, false otherwise */
153 
154 TIMEOUT_PUBLIC void timeout_del(struct timeout *);
155 /* remove timeout from any timing wheel (okay if not member of any) */
156 #endif
157 
158 /*
159  * T I M I N G  W H E E L  I N T E R F A C E S
160  *
161  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
162 
163 struct timeouts;
164 
165 TIMEOUT_PUBLIC struct timeouts *timeouts_open(timeout_t, timeout_error_t *);
166 /* open a new timing wheel, setting optional HZ (for float conversions) */
167 
168 TIMEOUT_PUBLIC void timeouts_close(struct timeouts *);
169 /* destroy timing wheel */
170 
171 TIMEOUT_PUBLIC timeout_t timeouts_hz(struct timeouts *);
172 /* return HZ setting (for float conversions) */
173 
174 TIMEOUT_PUBLIC void timeouts_update(struct timeouts *, timeout_t);
175 /* update timing wheel with current absolute time */
176 
177 TIMEOUT_PUBLIC void timeouts_step(struct timeouts *, timeout_t);
178 /* step timing wheel by relative time */
179 
180 TIMEOUT_PUBLIC timeout_t timeouts_get_curtime(struct timeouts *);
181 /* Return the current tick. */
182 
183 TIMEOUT_PUBLIC timeout_t timeouts_timeout(struct timeouts *);
184 /* return interval to next required update */
185 
186 TIMEOUT_PUBLIC void timeouts_add(struct timeouts *, struct timeout *, timeout_t);
187 /* add timeout to timing wheel */
188 
189 TIMEOUT_PUBLIC void timeouts_del(struct timeouts *, struct timeout *);
190 /* remove timeout from any timing wheel or expired queue (okay if on neither) */
191 
192 TIMEOUT_PUBLIC struct timeout *timeouts_get(struct timeouts *);
193 /* return any expired timeout (caller should loop until NULL-return) */
194 
195 TIMEOUT_PUBLIC bool timeouts_pending(struct timeouts *);
196 /* return true if any timeouts pending on timing wheel */
197 
198 TIMEOUT_PUBLIC bool timeouts_expired(struct timeouts *);
199 /* return true if any timeouts on expired queue */
200 
201 TIMEOUT_PUBLIC bool timeouts_check(struct timeouts *, FILE *);
202 /* return true if invariants hold. describes failures to optional file handle. */
203 
204 #define TIMEOUTS_PENDING 0x10
205 #define TIMEOUTS_EXPIRED 0x20
206 #define TIMEOUTS_ALL     (TIMEOUTS_PENDING|TIMEOUTS_EXPIRED)
207 #define TIMEOUTS_CLEAR   0x40
208 
209 #define TIMEOUTS_IT_INITIALIZER(flags) { (flags), 0, 0, 0, 0 }
210 
211 #define TIMEOUTS_IT_INIT(cur, _flags) do {                              \
212 	(cur)->flags = (_flags);                                        \
213 	(cur)->pc = 0;                                                  \
214 } while (0)
215 
216 struct timeouts_it {
217 	int flags;
218 	unsigned pc, i, j;
219 	struct timeout *to;
220 }; /* struct timeouts_it */
221 
222 TIMEOUT_PUBLIC struct timeout *timeouts_next(struct timeouts *, struct timeouts_it *);
223 /* return next timeout in pending wheel or expired queue. caller can delete
224  * the returned timeout, but should not otherwise manipulate the timing
225  * wheel. in particular, caller SHOULD NOT delete any other timeout as that
226  * could invalidate cursor state and trigger a use-after-free.
227  */
228 
229 #define TIMEOUTS_FOREACH(var, T, flags)                                 \
230 	struct timeouts_it _it = TIMEOUTS_IT_INITIALIZER((flags));      \
231 	while (((var) = timeouts_next((T), &_it)))
232 
233 
234 /*
235  * B O N U S  W H E E L  I N T E R F A C E S
236  *
237  * I usually use floating point timeouts in all my code, but it's cleaner to
238  * separate it to keep the core algorithmic code simple.
239  *
240  * Using macros instead of static inline routines where <math.h> routines
241  * might be used to keep -lm linking optional.
242  *
243  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
244 
245 #include <math.h> /* ceil(3) */
246 
247 #define timeouts_f2i(T, f) \
248 	((timeout_t)ceil((f) * timeouts_hz((T)))) /* prefer late expiration over early */
249 
250 #define timeouts_i2f(T, i) \
251 	((double)(i) / timeouts_hz((T)))
252 
253 #define timeouts_addf(T, to, timeout) \
254 	timeouts_add((T), (to), timeouts_f2i((T), (timeout)))
255 
256 #endif /* TIMEOUT_H */
257