summaryrefslogtreecommitdiff
path: root/toxcore/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore/event.c')
-rwxr-xr-xtoxcore/event.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/toxcore/event.c b/toxcore/event.c
new file mode 100755
index 00000000..17e68c87
--- /dev/null
+++ b/toxcore/event.c
@@ -0,0 +1,335 @@
1/** event.c
2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 *
5 * This file is part of Tox.
6 *
7 * Tox is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Tox is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *
21 * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
22 * my email: eniz_vukovic@hotmail.com
23 */
24
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif /* HAVE_CONFIG_H */
29
30#include <stdlib.h>
31#include "event.h"
32
33#include "util.h"
34
35#define _GNU_SOURCE
36
37#include <assert.h>
38#include <unistd.h>
39#include <stddef.h>
40#include <inttypes.h>
41#include <pthread.h>
42
43#define RUN_IN_THREAD(func, args) { pthread_t _tid; \
44 pthread_create(&_tid, NULL, func, args); assert( pthread_detach(_tid) == 0 ); }
45
46#define LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex)
47#define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex)
48
49#define FREQUENCY 10000
50
51#define inline__ inline __attribute__((always_inline))
52
53
54typedef struct _EventContainer {
55 void* (*func)(void*);
56 void* func_args;
57 unsigned timeout;
58 long long id;
59
60} EventContainer;
61
62typedef struct _EventHandler {
63 EventContainer* timed_events;
64 size_t timed_events_count;
65
66 int running;
67
68 pthread_mutex_t mutex;
69
70} EventHandler;
71
72int throw_event( void* (func)(void*), void* arg );
73int reset_timer_event ( int id, uint32_t timeout );
74int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout);
75int cancel_timer_event ( int id );
76int execute_timer_event ( int id );
77
78struct _Event event =
79{
80 throw_event,
81 /* reset_timer_event */ NULL,
82 throw_timer_event,
83 cancel_timer_event,
84 /*execute_timer_event*/ NULL
85};
86
87/*
88 * Random functions used by this file
89 */
90void clear_events (EventContainer** event_container, size_t* counter)
91{
92 free(*event_container );
93
94 *event_container = NULL;
95 *counter = 0;
96}
97
98int pop_id ( EventContainer** event_container, size_t* counter, int id )
99{
100 if ( !*event_container || !*counter || !id )
101 return -1;
102
103 EventContainer* _it = *event_container;
104 int i;
105
106 for ( i = *counter; i; -- i ){
107 if ( _it->id == id ) { /* Hit! */
108 break;
109 }
110 ++_it;
111 }
112
113 if ( i ) {
114 for ( ; i; -- i ){ *_it = *(_it + 1); ++_it; }
115 -- (*counter );
116 *event_container = realloc(*event_container, sizeof(EventContainer) * (*counter )); /* resize */
117
118 return 0;
119
120 }
121
122 /* not found here */
123
124 return -1;
125}
126
127void push_event ( EventContainer** container, size_t* counter, void* (func)(void*), void* arg )
128{
129 (*container ) = realloc((*container ), sizeof(EventContainer) * ((*counter ) + 1));
130 assert((*container ) != NULL);
131
132 (*container )[*counter].func = func;
133 (*container )[*counter].func_args = arg;
134 (*container )[*counter].timeout = 0;
135 (*container )[*counter].id = 0;
136
137 (*counter )++;
138}
139
140void reorder_events ( size_t counter, EventContainer* container, unsigned timeout )
141{
142 if ( counter > 1 ) {
143
144 int i = counter - 1;
145
146 /* start from behind excluding last added member */
147 EventContainer* _it = &container[i - 1];
148
149 EventContainer _last_added = container[i];
150
151 for ( ; i; --i ) {
152 if ( _it->timeout > timeout ){
153 *(_it + 1) = *_it;
154 *_it = _last_added; -- _it;
155 }
156 }
157
158 }
159}
160
161/* ============================================= */
162
163/* main poll for event execution */
164void* event_poll( void* arg )
165{
166 EventHandler* _event_handler = arg;
167
168 while ( _event_handler->running )
169 {
170
171 LOCK( _event_handler );
172
173 if ( _event_handler->timed_events ){
174
175 uint32_t _time = ((uint32_t)(current_time() / 1000));
176
177 if ( _event_handler->timed_events[0].timeout < _time ) {
178
179 RUN_IN_THREAD ( _event_handler->timed_events[0].func,
180 _event_handler->timed_events[0].func_args );
181
182 pop_id(&_event_handler->timed_events,
183 &_event_handler->timed_events_count,
184 _event_handler->timed_events[0].id);
185
186 }
187
188 }
189
190 UNLOCK( _event_handler );
191
192 usleep(FREQUENCY);
193 }
194
195LOCK( _event_handler );
196
197 clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count);
198
199UNLOCK( _event_handler );
200
201 _event_handler->running = -1;
202 pthread_exit(NULL);
203}
204
205int throw_event( void* (func)(void*), void* arg )
206{
207 pthread_t _tid;
208 int _rc =
209 pthread_create(&_tid, NULL, func, arg );
210
211 return (0 != _rc ) ? _rc : pthread_detach(_tid);
212}
213
214EventHandler event_handler;
215
216/* Place and order array of timers */
217int throw_timer_event ( void* (func)(void*), void* arg, unsigned timeout)
218{
219 static int _unique_id = 1;
220
221 push_event(&event_handler.timed_events, &(event_handler.timed_events_count), func, arg );
222
223 size_t _counter = event_handler.timed_events_count;
224
225 event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)(current_time() / 1000));
226 event_handler.timed_events[_counter - 1].id = _unique_id; ++_unique_id;
227
228
229 /* reorder */
230
231 reorder_events(_counter, event_handler.timed_events, timeout );
232
233 return _unique_id - 1;
234}
235
236int execute_timer_event ( int id )
237{
238 int _status;
239
240LOCK((&event_handler));
241 EventContainer* _it = event_handler.timed_events;
242
243 int _i = event_handler.timed_events_count;
244
245 /* Find it and execute */
246 for ( ; _i; _i-- ) {
247 if ( _it->id == id ) {
248 RUN_IN_THREAD ( _it->func, _it->func_args );
249 break;
250 }
251 ++_it;
252 }
253
254 /* Now remove it from the queue */
255
256 if ( _i ) {
257 for ( ; _i; -- _i ){ *_it = *(_it + 1); ++_it; }
258 -- event_handler.timed_events_count;
259
260 event_handler.timed_events = realloc
261 (event_handler.timed_events, sizeof(EventContainer) * event_handler.timed_events_count); /* resize */
262
263 _status = 0;
264
265 }
266 else _status = -1;
267
268UNLOCK((&event_handler));
269
270 return _status;
271}
272
273int reset_timer_event ( int id, uint32_t timeout )
274{
275 int _status;
276
277LOCK((&event_handler));
278
279 EventContainer* _it = event_handler.timed_events;
280
281 int _i = event_handler.timed_events_count;
282
283 /* Find it and change */
284 for ( ; _i; _i-- ) {
285 if ( _it->id == id ) {
286 _it->timeout = timeout + ((uint32_t)(current_time() / 1000));
287 break;
288 }
289 ++_it;
290 }
291
292 _status = _i ? -1 : 0;
293
294UNLOCK((&event_handler));
295
296 return _status;
297}
298
299/* Remove timer from array */
300inline__ int cancel_timer_event ( int id )
301{
302 return pop_id (&event_handler.timed_events, &event_handler.timed_events_count, id );
303}
304
305
306/* Initialization and termination of event polls
307 * This will be run at the beginning and the end of the program execution.
308 * I think that's the best way to do it.
309 */
310
311void __attribute__((constructor)) init_event_poll ()
312{
313 event_handler.timed_events = NULL;
314 event_handler.timed_events_count = 0;
315
316 event_handler.running = 1;
317
318 pthread_mutex_init(&event_handler.mutex, NULL);
319
320 RUN_IN_THREAD(event_poll, &event_handler);
321}
322
323void __attribute__((destructor)) terminate_event_poll()
324{
325 /* Exit thread */
326 event_handler.running = 0;
327
328 /* Keep the global until thread exits */
329 while (event_handler.running > -1) {
330 event_handler.running;
331 usleep(FREQUENCY*2);
332 }
333
334 pthread_mutex_destroy( &event_handler.mutex );
335}