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_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
57 timer->flags |= IOTIMERFLAG_ACTIVE;
58 if(!(timer->flags & IOTIMERFLAG_IN_LIST))
59 _trigger_timer(timer);
62 void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) {
63 struct _IOTimerDescriptor *timer = descriptor->iotimer;
65 iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
69 timer->flags |= IOTIMERFLAG_PERIODIC;
70 timer->autoreload = *autoreload;
72 if(!(timer->flags & IOTIMERFLAG_IN_LIST)) {
74 gettimeofday(&now, NULL);
76 _autoreload_timer(timer);
79 timer->flags &= ~IOTIMERFLAG_PERIODIC;
83 void iotimer_set_timeout(struct IOTimerDescriptor *descriptor, struct timeval *timeout) {
84 struct _IOTimerDescriptor *timer = descriptor->iotimer;
86 iolog_trigger(IOLOG_WARNING, "called iotimer_set_timeout for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
90 iolog_trigger(IOLOG_WARNING, "called iotimer_set_timeout without timeout given in %s:%d", __FILE__, __LINE__);
93 timer->timeout = *timeout;
94 _rearrange_timer(timer);
97 void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) {
98 descriptor->callback = callback;
101 void iotimer_destroy(struct IOTimerDescriptor *descriptor) {
102 struct _IOTimerDescriptor *timer = descriptor->iotimer;
104 iolog_trigger(IOLOG_WARNING, "called iotimer_destroy for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
107 descriptor->iotimer = NULL;
108 _destroy_timer(timer);
110 iogc_add(descriptor);
113 /* internal functions */
114 void _init_timers() {
118 struct _IOTimerDescriptor *_create_timer(struct timeval *timeout) {
119 struct _IOTimerDescriptor *timer = calloc(1, sizeof(*timer));
121 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
125 timer->timeout = *timeout;
126 _rearrange_timer(timer);
131 static void _rearrange_timer(struct _IOTimerDescriptor *timer) {
132 if((timer->flags & IOTIMERFLAG_IN_LIST)) {
133 if(timer->prev == NULL)
134 iotimer_sorted_descriptors = timer->next;
136 timer->prev->next = timer->next;
137 if(timer->next != NULL)
138 timer->next->prev = timer->prev;
140 struct _IOTimerDescriptor *ctimer;
141 for(ctimer = iotimer_sorted_descriptors; ctimer; ctimer = ctimer->next) {
142 if(timeval_is_bigger(ctimer->timeout, timer->timeout)) {
143 timer->next = ctimer;
144 timer->prev = ctimer->prev;
146 ctimer->prev->next = timer;
148 iotimer_sorted_descriptors = timer;
149 ctimer->prev = timer;
152 else if(ctimer->next == NULL) {
153 ctimer->next = timer;
154 timer->prev = ctimer;
159 iotimer_sorted_descriptors = timer;
160 timer->flags |= IOTIMERFLAG_IN_LIST;
163 void _destroy_timer(struct _IOTimerDescriptor *timer) {
164 if((timer->flags & IOTIMERFLAG_IN_LIST)) {
165 if(timer->prev == NULL)
166 iotimer_sorted_descriptors = timer->next;
168 timer->prev->next = timer->next;
169 if(timer->next != NULL)
170 timer->next->prev = timer->prev;
175 static void _autoreload_timer(struct _IOTimerDescriptor *timer) {
176 timer->timeout.tv_usec += timer->autoreload.tv_usec;
177 timer->timeout.tv_sec += timer->autoreload.tv_sec;
178 if(timer->timeout.tv_usec > 1000000) {
179 timer->timeout.tv_sec += (timer->timeout.tv_usec / 1000000);
180 timer->timeout.tv_usec %= 1000000;
182 _rearrange_timer(timer);
185 void _trigger_timer() {
187 _trigger_timer_start:
188 gettimeofday(&now, NULL);
190 struct _IOTimerDescriptor *timer = iotimer_sorted_descriptors;
191 if(!timer || timeval_is_bigger(timer->timeout, now)) {
194 iotimer_sorted_descriptors = timer->next;
195 if(timer->next != NULL)
196 timer->next->prev = timer->prev;
197 timer->flags &= ~IOTIMERFLAG_IN_LIST;
199 if((timer->flags & IOTIMERFLAG_PERIODIC))
200 _autoreload_timer(timer);
202 if(timer->flags & IOTIMERFLAG_PARENT_PUBLIC) {
203 struct IOTimerDescriptor *descriptor = timer->parent;
204 if(descriptor->callback)
205 descriptor->callback(descriptor);
206 if(!(timer->flags & IOTIMERFLAG_PERIODIC))
207 iotimer_destroy(descriptor);
209 if(!(timer->flags & IOTIMERFLAG_PERIODIC))
210 _destroy_timer(timer);
213 goto _trigger_timer_start;