6 #include <linux/kernel.h>
7 #include <linux/kthread.h>
8 #include <linux/timer.h>
11 * timespec_add_ns - Adds nanoseconds to a timespec
12 * @a: pointer to timespec to be incremented
13 * @ns: unsigned nanoseconds value to be added
15 * This must always be inlined because its used from the x86-64 vdso,
16 * which cannot call other kernel functions.
18 static struct timespec timespec_add_ns(struct timespec a, u64 ns)
21 a.tv_sec += a.tv_nsec / NSEC_PER_SEC;
22 a.tv_nsec %= NSEC_PER_SEC;
26 #define DECLARE_HEAP(type) \
32 #define heap_init(heap, _size) \
36 (heap)->size = (_size); \
37 _bytes = (heap)->size * sizeof(*(heap)->data); \
38 (heap)->data = malloc(_bytes); \
42 #define heap_free(heap) \
44 kvfree((heap)->data); \
45 (heap)->data = NULL; \
48 #define heap_swap(h, i, j) swap((h)->data[i], (h)->data[j])
50 #define heap_sift(h, i, cmp) \
54 for (; _j * 2 + 1 < (h)->used; _j = _r) { \
56 if (_r + 1 < (h)->used && \
57 cmp((h)->data[_r], (h)->data[_r + 1])) \
60 if (cmp((h)->data[_r], (h)->data[_j])) \
62 heap_swap(h, _r, _j); \
66 #define heap_sift_down(h, i, cmp) \
69 size_t p = (i - 1) / 2; \
70 if (cmp((h)->data[i], (h)->data[p])) \
77 #define heap_add(h, d, cmp) \
79 bool _r = !heap_full(h); \
81 size_t _i = (h)->used++; \
84 heap_sift_down(h, _i, cmp); \
85 heap_sift(h, _i, cmp); \
90 #define heap_del(h, i, cmp) \
94 BUG_ON(_i >= (h)->used); \
96 heap_swap(h, _i, (h)->used); \
97 heap_sift_down(h, _i, cmp); \
98 heap_sift(h, _i, cmp); \
101 #define heap_pop(h, d, cmp) \
103 bool _r = (h)->used; \
105 (d) = (h)->data[0]; \
106 heap_del(h, 0, cmp); \
111 #define heap_peek(h) ((h)->used ? &(h)->data[0] : NULL)
112 #define heap_full(h) ((h)->used == (h)->size)
113 #define heap_empty(h) ((h)->used == 0)
115 #define heap_resort(heap, cmp) \
118 for (_i = (ssize_t) (heap)->used / 2 - 1; _i >= 0; --_i) \
119 heap_sift(heap, _i, cmp); \
122 struct pending_timer {
123 struct timer_list *timer;
124 unsigned long expires;
127 static inline bool pending_timer_cmp(struct pending_timer a,
128 struct pending_timer b)
130 return a.expires < b.expires;
133 static DECLARE_HEAP(struct pending_timer) pending_timers;
135 static pthread_mutex_t timer_lock = PTHREAD_MUTEX_INITIALIZER;
136 static pthread_cond_t timer_cond = PTHREAD_COND_INITIALIZER;
137 static pthread_cond_t timer_running_cond = PTHREAD_COND_INITIALIZER;
138 static unsigned long timer_seq;
140 static inline bool timer_running(void)
142 return timer_seq & 1;
145 static size_t timer_idx(struct timer_list *timer)
149 for (i = 0; i < pending_timers.size; i++)
150 if (pending_timers.data[i].timer == timer)
155 int del_timer(struct timer_list *timer)
159 pthread_mutex_lock(&timer_lock);
160 pending = timer_pending(timer);
161 timer->pending = false;
164 heap_del(&pending_timers, timer_idx(timer), pending_timer_cmp);
166 pthread_mutex_unlock(&timer_lock);
171 void flush_timers(void)
175 pthread_mutex_lock(&timer_lock);
177 while (timer_running() && seq == timer_seq)
178 pthread_cond_wait(&timer_running_cond, &timer_lock);
180 pthread_mutex_unlock(&timer_lock);
183 int del_timer_sync(struct timer_list *timer)
188 pthread_mutex_lock(&timer_lock);
189 pending = timer_pending(timer);
190 timer->pending = false;
193 heap_del(&pending_timers, timer_idx(timer), pending_timer_cmp);
196 while (timer_running() && seq == timer_seq)
197 pthread_cond_wait(&timer_running_cond, &timer_lock);
199 pthread_mutex_unlock(&timer_lock);
204 int mod_timer(struct timer_list *timer, unsigned long expires)
209 pthread_mutex_lock(&timer_lock);
210 pending = timer_pending(timer);
212 if (pending && timer->expires == expires)
215 timer->expires = expires;
216 timer->pending = true;
219 i = timer_idx(timer);
220 pending_timers.data[i].expires = expires;
222 heap_sift_down(&pending_timers, i, pending_timer_cmp);
223 heap_sift(&pending_timers, i, pending_timer_cmp);
225 if (heap_full(&pending_timers)) {
226 pending_timers.size *= 2;
227 pending_timers.data =
228 realloc(pending_timers.data,
229 pending_timers.size *
230 sizeof(struct pending_timer));
232 BUG_ON(!pending_timers.data);
235 heap_add(&pending_timers,
236 ((struct pending_timer) {
243 pthread_cond_signal(&timer_cond);
245 pthread_mutex_unlock(&timer_lock);
250 static int timer_thread(void *arg)
252 struct pending_timer *p;
257 pthread_mutex_lock(&timer_lock);
261 p = heap_peek(&pending_timers);
264 pthread_cond_wait(&timer_cond, &timer_lock);
268 if (time_after_eq(now, p->expires)) {
269 struct timer_list *timer = p->timer;
271 heap_del(&pending_timers, 0, pending_timer_cmp);
272 BUG_ON(!timer_pending(timer));
273 timer->pending = false;
276 BUG_ON(!timer_running());
278 pthread_mutex_unlock(&timer_lock);
279 timer->function(timer->data);
280 pthread_mutex_lock(&timer_lock);
283 pthread_cond_broadcast(&timer_running_cond);
288 ret = clock_gettime(CLOCK_REALTIME, &ts);
291 ts = timespec_add_ns(ts, jiffies_to_nsecs(p->expires - now));
293 pthread_cond_timedwait(&timer_cond, &timer_lock, &ts);
296 pthread_mutex_unlock(&timer_lock);
301 __attribute__((constructor(103)))
302 static void timers_init(void)
304 struct task_struct *p;
306 heap_init(&pending_timers, 64);
307 BUG_ON(!pending_timers.data);
309 p = kthread_run(timer_thread, NULL, "timers");