-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathtimeout.c
95 lines (81 loc) · 2.53 KB
/
timeout.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
* Twin - A Tiny Window System
* Copyright (c) 2004 Keith Packard <[email protected]>
* All rights reserved.
*/
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include "twin_private.h"
#define twin_time_compare(a, op, b) (((a) - (b)) op 0)
static twin_time_t twin_now(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static twin_queue_t *head;
static twin_time_t start;
static twin_order_t _twin_timeout_order(twin_queue_t *a, twin_queue_t *b)
{
const twin_timeout_t *at = (twin_timeout_t *) a;
const twin_timeout_t *bt = (twin_timeout_t *) b;
if (twin_time_compare(at->time, <, bt->time))
return TWIN_AFTER;
if (twin_time_compare(at->time, >, bt->time))
return TWIN_BEFORE;
return TWIN_AT;
}
static void _twin_queue_timeout(twin_timeout_t *timeout, twin_time_t time)
{
timeout->time = time;
_twin_queue_remove(&head, &timeout->queue);
_twin_queue_insert(&head, _twin_timeout_order, &timeout->queue);
}
void _twin_run_timeout(void)
{
twin_time_t now = twin_now();
twin_timeout_t *timeout;
twin_time_t delay;
twin_timeout_t *first = (twin_timeout_t *) _twin_queue_set_order(&head);
for (timeout = first; timeout && twin_time_compare(now, >=, timeout->time);
timeout = (twin_timeout_t *) timeout->queue.order) {
delay = (*timeout->proc)(now, timeout->closure);
if (delay >= 0) {
timeout->time = twin_now() + delay;
_twin_queue_reorder(&head, _twin_timeout_order, &timeout->queue);
} else
_twin_queue_delete(&head, &timeout->queue);
}
_twin_queue_review_order(&first->queue);
}
twin_timeout_t *twin_set_timeout(twin_timeout_proc_t timeout_proc,
twin_time_t delay,
void *closure)
{
twin_timeout_t *timeout = malloc(sizeof(twin_timeout_t));
if (!timeout)
return NULL;
if (!start)
start = twin_now();
timeout->delay = delay;
timeout->proc = timeout_proc;
timeout->closure = closure;
_twin_queue_timeout(timeout, twin_now() + delay);
return timeout;
}
void twin_clear_timeout(twin_timeout_t *timeout)
{
_twin_queue_delete(&head, &timeout->queue);
}
twin_time_t _twin_timeout_delay(void)
{
if (head) {
const twin_timeout_t *thead = (twin_timeout_t *) head;
twin_time_t now = twin_now();
if (twin_time_compare(now, >=, thead->time))
return 0;
return thead->time - now;
}
return -1;
}