]> Dogcows Code - chaz/tint2/blob - src/util/timer.c
*fix* use another timer implementation, coz *BSD does not support timerfd :(
[chaz/tint2] / src / util / timer.c
1 /**************************************************************************
2 *
3 * Copyright (C) 2009 Andreas.Fink (Andreas.Fink85@gmail.com)
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 **************************************************************************/
17
18 #include <time.h>
19 #include <stdlib.h>
20
21 #include "timer.h"
22
23 GSList* timeout_list = 0;
24 struct timespec next_timeout;
25
26 void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), struct timeout* t);
27 gint compare_timeouts(gconstpointer t1, gconstpointer t2);
28 gint compare_timespecs(const struct timespec* t1, const struct timespec* t2);
29 int timespec_subtract(struct timespec* result, struct timespec* x, struct timespec* y);
30
31
32 const struct timeout* add_timeout(int value_msec, int interval_msec, void (*_callback)())
33 {
34 struct timeout* t = malloc(sizeof(struct timeout));
35 add_timeout_intern(value_msec, interval_msec, _callback, t);
36 return t;
37 }
38
39
40 void change_timeout(const struct timeout *t, int value_msec, int interval_msec, void(*_callback)())
41 {
42 timeout_list = g_slist_remove(timeout_list, t);
43 add_timeout_intern(value_msec, interval_msec, _callback, (struct timeout*)t);
44 }
45
46
47 void update_next_timeout()
48 {
49 if (timeout_list) {
50 struct timeout* t = timeout_list->data;
51 struct timespec cur_time;
52 clock_gettime(CLOCK_MONOTONIC, &cur_time);
53 if (timespec_subtract(&next_timeout, &t->timeout_expires, &cur_time)) {
54 next_timeout.tv_sec = 0;
55 next_timeout.tv_nsec = 0;
56 }
57 }
58 else
59 next_timeout.tv_sec = -1;
60 }
61
62
63 void callback_timeout_expired()
64 {
65 struct timespec cur_time;
66 struct timeout* t;
67 while (timeout_list) {
68 clock_gettime(CLOCK_MONOTONIC, &cur_time);
69 t = timeout_list->data;
70 if (compare_timespecs(&t->timeout_expires, &cur_time) <= 0) {
71 // it's time for the callback function
72 t->_callback();
73 if (g_slist_find(timeout_list, t)) {
74 // if _callback() calls stop_timeout(t) the timeout 't' does not exist anymore
75 timeout_list = g_slist_remove(timeout_list, t);
76 if (t->interval_msec > 0)
77 add_timeout_intern(t->interval_msec, t->interval_msec, t->_callback, t);
78 else
79 free(t);
80 }
81 }
82 else
83 return;
84 }
85 }
86
87
88 void stop_timeout(const struct timeout* t)
89 {
90 if (g_slist_find(timeout_list, t)) {
91 timeout_list = g_slist_remove(timeout_list, t);
92 free((void*)t);
93 }
94 }
95
96
97 void stop_all_timeouts()
98 {
99 while (timeout_list) {
100 free(timeout_list->data);
101 timeout_list = g_slist_remove(timeout_list, timeout_list->data);
102 }
103 }
104
105
106 void add_timeout_intern(int value_msec, int interval_msec, void(*_callback)(), struct timeout *t)
107 {
108 t->interval_msec = interval_msec;
109 t->_callback = _callback;
110 struct timespec expire;
111 clock_gettime(CLOCK_MONOTONIC, &expire);
112 expire.tv_sec += value_msec / 1000;
113 expire.tv_nsec += (value_msec % 1000)*1000000;
114 if (expire.tv_nsec >= 1000000000) { // 10^9
115 expire.tv_sec++;
116 expire.tv_nsec -= 1000000000;
117 }
118 t->timeout_expires = expire;
119 timeout_list = g_slist_insert_sorted(timeout_list, t, compare_timeouts);
120 }
121
122
123 gint compare_timeouts(gconstpointer t1, gconstpointer t2)
124 {
125 return compare_timespecs(&((const struct timeout*)t1)->timeout_expires,
126 &((const struct timeout*)t2)->timeout_expires);
127 }
128
129
130 gint compare_timespecs(const struct timespec* t1, const struct timespec* t2)
131 {
132 if (t1->tv_sec < t2->tv_sec)
133 return -1;
134 else if (t1->tv_sec == t2->tv_sec) {
135 if (t1->tv_nsec < t2->tv_nsec)
136 return -1;
137 else if (t1->tv_nsec == t2->tv_nsec)
138 return 0;
139 else
140 return 1;
141 }
142 else
143 return 1;
144 }
145
146 int timespec_subtract(struct timespec* result, struct timespec* x, struct timespec* y)
147 {
148 /* Perform the carry for the later subtraction by updating y. */
149 if (x->tv_nsec < y->tv_nsec) {
150 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
151 y->tv_nsec -= 1000000000 * nsec;
152 y->tv_sec += nsec;
153 }
154 if (x->tv_nsec - y->tv_nsec > 1000000000) {
155 int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
156 y->tv_nsec += 1000000000 * nsec;
157 y->tv_sec -= nsec;
158 }
159
160 /* Compute the time remaining to wait. tv_nsec is certainly positive. */
161 result->tv_sec = x->tv_sec - y->tv_sec;
162 result->tv_nsec = x->tv_nsec - y->tv_nsec;
163
164 /* Return 1 if result is negative. */
165 return x->tv_sec < y->tv_sec;
166 }
This page took 0.044035 seconds and 5 git commands to generate.