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"
20 #include "IOHandlerTimer.h"
24 static pthread_mutex_t iotimer_sync;
27 #define timeval_is_bigger(x,y) ((x->tv_sec > y->tv_sec) || (x->tv_sec == y->tv_sec && x->tv_usec > y->tv_usec))
28 #define timeval_is_smaler(x,y) ((x->tv_sec < y->tv_sec) || (x->tv_sec == y->tv_sec && x->tv_usec < y->tv_usec))
30 static void _rearrange_timer(struct IOTimerDescriptor *timer);
31 static void _autoreload_timer(struct IOTimerDescriptor *timer);
33 struct _IOTimerDescriptor *iotimer_sorted_descriptors;
35 /* public functions */
37 struct IOTimerDescriptor iotimer_create(struct timeval *timeout) {
38 struct IOTimerDescriptor *descriptor = calloc(1, sizeof(*descriptor));
40 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
43 struct _IOTimerDescriptor *timer = _create_timer(timeout);
48 timer->parent = descriptor;
49 timer->flags |= IOTIMERFLAG_PARENT_PUBLIC;
50 descriptor->iotimer = timer;
55 void iotimer_start(struct IOTimerDescriptor *descriptor) {
56 struct _IOTimerDescriptor *timer = descriptor->iotimer;
58 iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
61 timer->flags |= IOTIMERFLAG_ACTIVE;
62 if(!(timer->flags & IOTIMERFLAG_IN_LIST))
63 _trigger_timer(timer);
66 void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) {
67 struct _IOTimerDescriptor *timer = descriptor->iotimer;
69 iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
73 timer->flags |= IOTIMERFLAG_PERIODIC;
74 timer->autoreload = *autoreload;
76 if(!(timer->flags & IOTIMERFLAG_IN_LIST)) {
78 gettimeofday(&ctime, NULL);
79 timer->timeout = ctime;
80 _autoreload_timer(timer);
83 timer->flags &= ~IOTIMERFLAG_PERIODIC;
87 void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) {
88 descriptor->callback = callback;
91 void iotimer_destroy(struct IOTimerDescriptor *descriptor) {
92 struct _IOTimerDescriptor *timer = descriptor->iotimer;
94 iolog_trigger(IOLOG_WARNING, "called iotimer_destroy for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
97 descriptor->iotimer = NULL;
98 _destroy_timer(timer);
100 iogc_add(descriptor);
103 /* internal functions */
104 void _init_timers() {
105 IOTHREAD_MUTEX_INIT(iotimer_sync);
108 struct _IOTimerDescriptor _create_timer(struct timeval *timeout) {
109 struct _IOTimerDescriptor *timer = calloc(1, sizeof(*timer));
111 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
115 timer->timeout = *timeout;
116 _rearrange_timer(timer);
121 static void _rearrange_timer(struct IOTimerDescriptor *timer) {
122 IOSYNCHRONIZE(iotimer_sync);
123 if((timer->flags & IOTIMERFLAG_IN_LIST)) {
124 if(timer->prev == NULL)
125 iotimer_sorted_descriptors = timer->next;
127 timer->prev->next = timer->next;
128 if(timer->next != NULL)
129 timer->next->prev = timer->prev;
131 struct _IOTimerDescriptor *ctimer;
132 for(ctimer = iotimer_sorted_descriptors; ctimer;) {
133 if(timeval_is_bigger(&ctimer->timeout, &timer->timeout)) {
134 timer->next = ctimer;
135 timer->prev = ctimer->prev;
137 ctimer->prev->next = timer;
139 iotimer_sorted_descriptors = timer;
140 ctimer->prev = timer;
143 else if(ctimer->next == NULL) {
144 ctimer->next = timer;
145 timer->prev = ctimer;
150 iotimer_sorted_descriptors = timer;
151 timer->flags |= IOTIMERFLAG_IN_LIST;
152 IODESYNCHRONIZE(iotimer_sync);
155 void _destroy_timer(struct _IOTimerDescriptor *timer) {
156 if((timer->flags & IOTIMERFLAG_IN_LIST)) {
157 IOSYNCHRONIZE(iotimer_sync);
158 if(timer->prev == NULL)
159 iotimer_sorted_descriptors = timer->next;
161 timer->prev->next = timer->next;
162 if(timer->next != NULL)
163 timer->next->prev = timer->prev;
164 IODESYNCHRONIZE(iotimer_sync);
169 static void _autoreload_timer(struct IOTimerDescriptor *timer) {
170 timer->timeout.tv_usec += timer->autoreload.tv_usec;
171 timer->timeout.tv_sec += timer->autoreload.tv_sec;
172 if(timer->timeout.tv_usec > 1000000) {
173 timer->timeout.tv_sec += (timer->timeout.tv_usec / 1000000);
174 timer->timeout.tv_usec %= 1000000;
176 _rearrange_timer(timer);