]>
Dogcows Code - chaz/tint2/blob - src/util/timer.c
1 /**************************************************************************
3 * Copyright (C) 2009 Andreas.Fink (Andreas.Fink85@gmail.com)
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.
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 **************************************************************************/
23 GSList
* timeout_list
= 0;
24 struct timespec next_timeout
;
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
);
32 /** Implementation notes for timeouts: The timeouts are kept in a GSList sorted by their
34 * That means that update_next_timeout() only have to consider the first timeout in the list,
35 * and callback_timeout_expired() only have to consider the timeouts as long as the expiration time
36 * is in the past to the current time.
37 * As time measurement we use clock_gettime(CLOCK_MONOTONIC) because this refers to a timer, which
38 * reference point lies somewhere in the past and cannot be changed, but just queried.
41 const struct timeout
* add_timeout(int value_msec
, int interval_msec
, void (*_callback
)())
43 struct timeout
* t
= malloc(sizeof(struct timeout
));
44 add_timeout_intern(value_msec
, interval_msec
, _callback
, t
);
49 void change_timeout(const struct timeout
*t
, int value_msec
, int interval_msec
, void(*_callback
)())
51 timeout_list
= g_slist_remove(timeout_list
, t
);
52 add_timeout_intern(value_msec
, interval_msec
, _callback
, (struct timeout
*)t
);
56 void update_next_timeout()
59 struct timeout
* t
= timeout_list
->data
;
60 struct timespec cur_time
;
61 clock_gettime(CLOCK_MONOTONIC
, &cur_time
);
62 if (timespec_subtract(&next_timeout
, &t
->timeout_expires
, &cur_time
)) {
63 next_timeout
.tv_sec
= 0;
64 next_timeout
.tv_nsec
= 0;
68 next_timeout
.tv_sec
= -1;
72 void callback_timeout_expired()
74 struct timespec cur_time
;
76 while (timeout_list
) {
77 clock_gettime(CLOCK_MONOTONIC
, &cur_time
);
78 t
= timeout_list
->data
;
79 if (compare_timespecs(&t
->timeout_expires
, &cur_time
) <= 0) {
80 // it's time for the callback function
82 if (g_slist_find(timeout_list
, t
)) {
83 // if _callback() calls stop_timeout(t) the timeout 't' was freed and is not in the timeout_list
84 timeout_list
= g_slist_remove(timeout_list
, t
);
85 if (t
->interval_msec
> 0)
86 add_timeout_intern(t
->interval_msec
, t
->interval_msec
, t
->_callback
, t
);
97 void stop_timeout(const struct timeout
* t
)
99 // if not in the list, it was deleted in callback_timeout_expired
100 if (g_slist_find(timeout_list
, t
)) {
101 timeout_list
= g_slist_remove(timeout_list
, t
);
107 void stop_all_timeouts()
109 while (timeout_list
) {
110 free(timeout_list
->data
);
111 timeout_list
= g_slist_remove(timeout_list
, timeout_list
->data
);
116 void add_timeout_intern(int value_msec
, int interval_msec
, void(*_callback
)(), struct timeout
*t
)
118 t
->interval_msec
= interval_msec
;
119 t
->_callback
= _callback
;
120 struct timespec expire
;
121 clock_gettime(CLOCK_MONOTONIC
, &expire
);
122 expire
.tv_sec
+= value_msec
/ 1000;
123 expire
.tv_nsec
+= (value_msec
% 1000)*1000000;
124 if (expire
.tv_nsec
>= 1000000000) { // 10^9
126 expire
.tv_nsec
-= 1000000000;
128 t
->timeout_expires
= expire
;
129 timeout_list
= g_slist_insert_sorted(timeout_list
, t
, compare_timeouts
);
133 gint
compare_timeouts(gconstpointer t1
, gconstpointer t2
)
135 return compare_timespecs(&((const struct timeout
*)t1
)->timeout_expires
,
136 &((const struct timeout
*)t2
)->timeout_expires
);
140 gint
compare_timespecs(const struct timespec
* t1
, const struct timespec
* t2
)
142 if (t1
->tv_sec
< t2
->tv_sec
)
144 else if (t1
->tv_sec
== t2
->tv_sec
) {
145 if (t1
->tv_nsec
< t2
->tv_nsec
)
147 else if (t1
->tv_nsec
== t2
->tv_nsec
)
156 int timespec_subtract(struct timespec
* result
, struct timespec
* x
, struct timespec
* y
)
158 /* Perform the carry for the later subtraction by updating y. */
159 if (x
->tv_nsec
< y
->tv_nsec
) {
160 int nsec
= (y
->tv_nsec
- x
->tv_nsec
) / 1000000000 + 1;
161 y
->tv_nsec
-= 1000000000 * nsec
;
164 if (x
->tv_nsec
- y
->tv_nsec
> 1000000000) {
165 int nsec
= (x
->tv_nsec
- y
->tv_nsec
) / 1000000000;
166 y
->tv_nsec
+= 1000000000 * nsec
;
170 /* Compute the time remaining to wait. tv_nsec is certainly positive. */
171 result
->tv_sec
= x
->tv_sec
- y
->tv_sec
;
172 result
->tv_nsec
= x
->tv_nsec
- y
->tv_nsec
;
174 /* Return 1 if result is negative. */
175 return x
->tv_sec
< y
->tv_sec
;
This page took 0.039585 seconds and 4 git commands to generate.