[IOMultiplexerV2] dev snapshot
[NextIRCd.git] / src / IOTimer.c
1 /* IOTimer.c - IOMultiplexer v2
2  * Copyright (C) 2014  Philipp Kreil (pk910)
3  * 
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.
8  * 
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  * 
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/>. 
16  */
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IOTimer.h"
21 #include "IOLog.h"
22
23 #ifdef HAVE_PTHREAD_H
24 static pthread_mutex_t iotimer_sync;
25 #endif
26
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))
29
30 static void _rearrange_timer(struct IOTimerDescriptor *timer);
31 static void _autoreload_timer(struct IOTimerDescriptor *timer);
32
33 struct _IOTimerDescriptor *iotimer_sorted_descriptors;
34
35 /* public functions */
36
37 struct IOTimerDescriptor iotimer_create(struct timeval *timeout) {
38         struct IOTimerDescriptor *descriptor = calloc(1, sizeof(*descriptor));
39     if(!descriptor) {
40         iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
41         return NULL;
42     }
43         struct _IOTimerDescriptor *timer = _create_timer(timeout);
44         if(!timer) {
45                 free(descriptor);
46                 return NULL;
47         }
48         timer->parent = descriptor;
49         timer->flags |= IOTIMERFLAG_PARENT_PUBLIC;
50         descriptor->iotimer = timer;
51         
52         return descriptor;
53 }
54
55 void iotimer_start(struct IOTimerDescriptor *descriptor) {
56         struct _IOTimerDescriptor *timer = descriptor->iotimer;
57         if(timer == NULL) {
58                 iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
59                 return;
60         }
61         timer->flags |= IOTIMERFLAG_ACTIVE;
62         if(!(timer->flags & IOTIMERFLAG_IN_LIST))
63                 _trigger_timer(timer);
64 }
65
66 void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) {
67         struct _IOTimerDescriptor *timer = descriptor->iotimer;
68         if(timer == NULL) {
69                 iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
70                 return;
71         }
72         if(autoreload) {
73                 timer->flags |= IOTIMERFLAG_PERIODIC;
74                 timer->autoreload = *autoreload;
75                 
76                 if(!(timer->flags & IOTIMERFLAG_IN_LIST)) {
77                         struct timeval ctime;
78                         gettimeofday(&ctime, NULL);
79                         timer->timeout = ctime;
80                         _autoreload_timer(timer);
81                 }
82         } else {
83                 timer->flags &= ~IOTIMERFLAG_PERIODIC;
84         }
85 }
86
87 void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) {
88         descriptor->callback = callback;
89 }
90
91 void iotimer_destroy(struct IOTimerDescriptor *descriptor) {
92         struct _IOTimerDescriptor *timer = descriptor->iotimer;
93         if(timer == NULL) {
94                 iolog_trigger(IOLOG_WARNING, "called iotimer_destroy for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
95                 return;
96         }
97         descriptor->iotimer = NULL;
98         _destroy_timer(timer);
99         
100         iogc_add(descriptor);
101 }
102
103 /* internal functions */
104 void _init_timers() {
105         IOTHREAD_MUTEX_INIT(iotimer_sync);
106 }
107
108 struct _IOTimerDescriptor _create_timer(struct timeval *timeout) {
109         struct _IOTimerDescriptor *timer = calloc(1, sizeof(*timer));
110     if(!timer) {
111         iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
112         return NULL;
113     }
114         if(timeout) {
115                 timer->timeout = *timeout;
116                 _rearrange_timer(timer);
117         }
118         return timer;
119 }
120
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;
126                 else
127                         timer->prev->next = timer->next;
128                 if(timer->next != NULL)
129                         timer->next->prev = timer->prev;
130         }
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;
136                         if(ctimer->prev)
137                                 ctimer->prev->next = timer;
138                         else
139                                 iotimer_sorted_descriptors = timer;
140                         ctimer->prev = timer;
141                         break
142                 }
143                 else if(ctimer->next == NULL) {
144                         ctimer->next = timer;
145                         timer->prev = ctimer;
146                         break;
147                 }
148         }
149         if(ctimer == NULL)
150                 iotimer_sorted_descriptors = timer;
151         timer->flags |= IOTIMERFLAG_IN_LIST;
152         IODESYNCHRONIZE(iotimer_sync);
153 }
154
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;
160                 else
161                         timer->prev->next = timer->next;
162                 if(timer->next != NULL)
163                         timer->next->prev = timer->prev;
164                 IODESYNCHRONIZE(iotimer_sync);
165         }
166         free(timer);
167 }
168
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;
175         }
176         _rearrange_timer(timer);
177 }
178