1 /* IOTimer.c - IOMultiplexer v2
2 * Copyright (C) 2014 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
26 static void _rearrange_timer(struct _IOTimerDescriptor *timer);
27 static void _autoreload_timer(struct _IOTimerDescriptor *timer);
29 struct _IOTimerDescriptor *iotimer_sorted_descriptors;
31 /* public functions */
33 struct IOTimerDescriptor *iotimer_create(struct timeval *timeout) {
34 struct IOTimerDescriptor *descriptor = calloc(1, sizeof(*descriptor));
36 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
39 struct _IOTimerDescriptor *timer = _create_timer(timeout);
44 timer->parent = descriptor;
45 timer->flags |= IOTIMERFLAG_PARENT_PUBLIC;
46 descriptor->iotimer = timer;
51 void iotimer_start(struct IOTimerDescriptor *descriptor) {
52 struct _IOTimerDescriptor *timer = descriptor->iotimer;
54 iolog_trigger(IOLOG_WARNING, "called iotimer_start for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
57 timer->flags |= IOTIMERFLAG_ACTIVE;
58 _rearrange_timer(timer);
61 void iotimer_stop(struct IOTimerDescriptor *descriptor) {
62 struct _IOTimerDescriptor *timer = descriptor->iotimer;
64 iolog_trigger(IOLOG_WARNING, "called iotimer_stop for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
67 timer->flags &= ~IOTIMERFLAG_ACTIVE;
68 if((timer->flags & IOTIMERFLAG_PERSISTENT)) {
69 timer->flags &= ~IOTIMERFLAG_ACTIVE;
70 _rearrange_timer(timer);
72 iotimer_destroy(descriptor);
75 int iotimer_state(struct IOTimerDescriptor *descriptor) {
76 struct _IOTimerDescriptor *timer = descriptor->iotimer;
78 iolog_trigger(IOLOG_WARNING, "called iotimer_state for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
81 if((timer->flags & IOTIMERFLAG_ACTIVE))
87 void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) {
88 struct _IOTimerDescriptor *timer = descriptor->iotimer;
90 iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
94 timer->flags |= IOTIMERFLAG_PERIODIC;
95 timer->autoreload = *autoreload;
97 if(timer->timeout.tv_sec == 0 && timer->timeout.tv_usec == 0) {
99 gettimeofday(&now, NULL);
100 timer->timeout = now;
101 _autoreload_timer(timer);
104 timer->flags &= ~IOTIMERFLAG_PERIODIC;
108 struct timeval iotimer_get_autoreload(struct IOTimerDescriptor *descriptor) {
109 struct _IOTimerDescriptor *timer = descriptor->iotimer;
111 iolog_trigger(IOLOG_WARNING, "called iotimer_get_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
117 if((timer->flags & IOTIMERFLAG_PERIODIC))
118 return timer->autoreload;
127 void iotimer_set_timeout(struct IOTimerDescriptor *descriptor, struct timeval *timeout) {
128 struct _IOTimerDescriptor *timer = descriptor->iotimer;
130 iolog_trigger(IOLOG_WARNING, "called iotimer_set_timeout for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
134 iolog_trigger(IOLOG_WARNING, "called iotimer_set_timeout without timeout given in %s:%d", __FILE__, __LINE__);
137 timer->timeout = *timeout;
138 _rearrange_timer(timer);
141 struct timeval iotimer_get_timeout(struct IOTimerDescriptor *descriptor) {
142 struct _IOTimerDescriptor *timer = descriptor->iotimer;
144 iolog_trigger(IOLOG_WARNING, "called iotimer_get_timeout for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
150 return timer->timeout;
153 void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) {
154 descriptor->callback = callback;
157 void iotimer_set_persistent(struct IOTimerDescriptor *descriptor, int persistent) {
158 struct _IOTimerDescriptor *timer = descriptor->iotimer;
160 iolog_trigger(IOLOG_WARNING, "called iotimer_set_persistent for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
164 timer->flags |= IOTIMERFLAG_PERSISTENT;
166 timer->flags &= ~IOTIMERFLAG_PERSISTENT;
169 void iotimer_destroy(struct IOTimerDescriptor *descriptor) {
170 struct _IOTimerDescriptor *timer = descriptor->iotimer;
172 iolog_trigger(IOLOG_WARNING, "called iotimer_destroy for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
175 descriptor->iotimer = NULL;
176 _destroy_timer(timer);
178 iogc_add(descriptor);
181 /* internal functions */
182 void _init_timers() {
186 struct _IOTimerDescriptor *_create_timer(struct timeval *timeout) {
187 struct _IOTimerDescriptor *timer = calloc(1, sizeof(*timer));
189 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
193 timer->timeout = *timeout;
197 static void _rearrange_timer(struct _IOTimerDescriptor *timer) {
198 if((timer->flags & IOTIMERFLAG_IN_LIST)) {
199 if(timer->prev == NULL)
200 iotimer_sorted_descriptors = timer->next;
202 timer->prev->next = timer->next;
203 if(timer->next != NULL)
204 timer->next->prev = timer->prev;
205 timer->flags &= ~IOTIMERFLAG_IN_LIST;
207 if(!(timer->flags & IOTIMERFLAG_ACTIVE))
209 struct _IOTimerDescriptor *ctimer;
210 for(ctimer = iotimer_sorted_descriptors; ctimer; ctimer = ctimer->next) {
211 if(timeval_is_bigger(ctimer->timeout, timer->timeout)) {
212 timer->next = ctimer;
213 timer->prev = ctimer->prev;
215 ctimer->prev->next = timer;
217 iotimer_sorted_descriptors = timer;
218 ctimer->prev = timer;
221 else if(ctimer->next == NULL) {
222 ctimer->next = timer;
223 timer->prev = ctimer;
228 iotimer_sorted_descriptors = timer;
229 timer->flags |= IOTIMERFLAG_IN_LIST;
232 void _destroy_timer(struct _IOTimerDescriptor *timer) {
233 if((timer->flags & IOTIMERFLAG_IN_LIST)) {
234 if(timer->prev == NULL)
235 iotimer_sorted_descriptors = timer->next;
237 timer->prev->next = timer->next;
238 if(timer->next != NULL)
239 timer->next->prev = timer->prev;
244 static void _autoreload_timer(struct _IOTimerDescriptor *timer) {
245 timer->timeout.tv_usec += timer->autoreload.tv_usec;
246 timer->timeout.tv_sec += timer->autoreload.tv_sec;
247 if(timer->timeout.tv_usec > 1000000) {
248 timer->timeout.tv_sec += (timer->timeout.tv_usec / 1000000);
249 timer->timeout.tv_usec %= 1000000;
251 _rearrange_timer(timer);
254 void _trigger_timer() {
256 struct _IOTimerDescriptor *timer;
257 while(iotimer_sorted_descriptors) {
258 gettimeofday(&now, NULL);
260 timer = iotimer_sorted_descriptors;
261 if(timeval_is_bigger(timer->timeout, now))
264 iotimer_sorted_descriptors = timer->next;
265 if(timer->next != NULL)
266 timer->next->prev = timer->prev;
267 timer->flags &= ~IOTIMERFLAG_IN_LIST;
269 if((timer->flags & IOTIMERFLAG_PERIODIC))
270 _autoreload_timer(timer);
272 if(timer->flags & IOTIMERFLAG_PARENT_PUBLIC) {
273 struct IOTimerDescriptor *descriptor = timer->parent;
274 if(descriptor->callback)
275 descriptor->callback(descriptor);
276 if(!(timer->flags & IOTIMERFLAG_PERIODIC))
277 iotimer_destroy(descriptor);
279 if(!(timer->flags & IOTIMERFLAG_PERIODIC))
280 _destroy_timer(timer);