]>
Dogcows Code - chaz/tint2/blob - timer.c
6bb757837861e187d7007466bd4584b4f03789c8
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 timeval next_timeout
;
26 void add_timeout_intern(int value_msec
, int interval_msec
, void(*_callback
)(void*), void* arg
, 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.
39 * If a single shot timer is installed it will be automatically deleted. I.e. the returned value
40 * of add_timeout will not be valid anymore. You do not need to call stop_timeout for these timeouts,
41 * however it's save to call it.
44 const struct timeout
* add_timeout(int value_msec
, int interval_msec
, void (*_callback
)(void*), void* arg
)
46 struct timeout
* t
= malloc(sizeof(struct timeout
));
47 add_timeout_intern(value_msec
, interval_msec
, _callback
, arg
, t
);
52 void change_timeout(const struct timeout
*t
, int value_msec
, int interval_msec
, void(*_callback
)(), void* arg
)
54 if ( g_slist_find(timeout_list
, t
) == 0 )
55 printf("timeout already deleted...");
57 timeout_list
= g_slist_remove(timeout_list
, t
);
58 add_timeout_intern(value_msec
, interval_msec
, _callback
, arg
, (struct timeout
*)t
);
63 void update_next_timeout()
66 struct timeout
* t
= timeout_list
->data
;
67 struct timespec cur_time
;
68 struct timespec next_timeout2
= { .tv_sec
=next_timeout
.tv_sec
, .tv_nsec
=next_timeout
.tv_usec
*1000 };
69 clock_gettime(CLOCK_MONOTONIC
, &cur_time
);
70 if (timespec_subtract(&next_timeout2
, &t
->timeout_expires
, &cur_time
)) {
71 next_timeout
.tv_sec
= 0;
72 next_timeout
.tv_usec
= 0;
75 next_timeout
.tv_sec
= next_timeout2
.tv_sec
;
76 next_timeout
.tv_usec
= next_timeout2
.tv_nsec
/1000;
80 next_timeout
.tv_sec
= -1;
84 void callback_timeout_expired()
86 struct timespec cur_time
;
88 while (timeout_list
) {
89 clock_gettime(CLOCK_MONOTONIC
, &cur_time
);
90 t
= timeout_list
->data
;
91 if (compare_timespecs(&t
->timeout_expires
, &cur_time
) <= 0) {
92 // it's time for the callback function
94 if (g_slist_find(timeout_list
, t
)) {
95 // if _callback() calls stop_timeout(t) the timeout 't' was freed and is not in the timeout_list
96 timeout_list
= g_slist_remove(timeout_list
, t
);
97 if (t
->interval_msec
> 0)
98 add_timeout_intern(t
->interval_msec
, t
->interval_msec
, t
->_callback
, t
->arg
, t
);
109 void stop_timeout(const struct timeout
* t
)
111 // if not in the list, it was deleted in callback_timeout_expired
112 if (g_slist_find(timeout_list
, t
)) {
113 timeout_list
= g_slist_remove(timeout_list
, t
);
119 void stop_all_timeouts()
121 while (timeout_list
) {
122 free(timeout_list
->data
);
123 timeout_list
= g_slist_remove(timeout_list
, timeout_list
->data
);
128 void add_timeout_intern(int value_msec
, int interval_msec
, void(*_callback
)(), void* arg
, struct timeout
*t
)
130 t
->interval_msec
= interval_msec
;
131 t
->_callback
= _callback
;
133 struct timespec expire
;
134 clock_gettime(CLOCK_MONOTONIC
, &expire
);
135 expire
.tv_sec
+= value_msec
/ 1000;
136 expire
.tv_nsec
+= (value_msec
% 1000)*1000000;
137 if (expire
.tv_nsec
>= 1000000000) { // 10^9
139 expire
.tv_nsec
-= 1000000000;
141 t
->timeout_expires
= expire
;
142 timeout_list
= g_slist_insert_sorted(timeout_list
, t
, compare_timeouts
);
146 gint
compare_timeouts(gconstpointer t1
, gconstpointer t2
)
148 return compare_timespecs(&((const struct timeout
*)t1
)->timeout_expires
,
149 &((const struct timeout
*)t2
)->timeout_expires
);
153 gint
compare_timespecs(const struct timespec
* t1
, const struct timespec
* t2
)
155 if (t1
->tv_sec
< t2
->tv_sec
)
157 else if (t1
->tv_sec
== t2
->tv_sec
) {
158 if (t1
->tv_nsec
< t2
->tv_nsec
)
160 else if (t1
->tv_nsec
== t2
->tv_nsec
)
169 int timespec_subtract(struct timespec
* result
, struct timespec
* x
, struct timespec
* y
)
171 /* Perform the carry for the later subtraction by updating y. */
172 if (x
->tv_nsec
< y
->tv_nsec
) {
173 int nsec
= (y
->tv_nsec
- x
->tv_nsec
) / 1000000000 + 1;
174 y
->tv_nsec
-= 1000000000 * nsec
;
177 if (x
->tv_nsec
- y
->tv_nsec
> 1000000000) {
178 int nsec
= (x
->tv_nsec
- y
->tv_nsec
) / 1000000000;
179 y
->tv_nsec
+= 1000000000 * nsec
;
183 /* Compute the time remaining to wait. tv_nsec is certainly positive. */
184 result
->tv_sec
= x
->tv_sec
- y
->tv_sec
;
185 result
->tv_nsec
= x
->tv_nsec
- y
->tv_nsec
;
187 /* Return 1 if result is negative. */
188 return x
->tv_sec
< y
->tv_sec
;
This page took 0.039278 seconds and 3 git commands to generate.