]> git.ipfire.org Git - thirdparty/freeswitch.git/blame - libs/libzrtp/src/zrtp_iface_scheduler.c
[mod_http_cache] Fix leaking curl handle in http_get()
[thirdparty/freeswitch.git] / libs / libzrtp / src / zrtp_iface_scheduler.c
CommitLineData
5a61e580
VK
1/*
2 * libZRTP SDK library, implements the ZRTP secure VoIP protocol.
3 * Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved.
4 * Contact: http://philzimmermann.com
5 * For licensing and other legal details, see the file zrtp_legal.c.
6 *
7 * Viktor Krykun <v.krikun at zfoneproject.com>
8 */
9
21c145b1 10#define _POSIX_C_SOURCE 199309L /* for struct timespec */
5a61e580
VK
11#include "zrtp.h"
12
13#if (defined(ZRTP_USE_BUILTIN_SCEHDULER) && (ZRTP_USE_BUILTIN_SCEHDULER ==1))
14#if (ZRTP_PLATFORM!=ZP_SYMBIAN)
15
16#if defined (ZRTP_DEBUG_WITH_PJSIP) && (ZRTP_DEBUG_WITH_PJSIP == 1)
17# include <pjlib.h>
18#endif
19
20/* Windows kernel have it's own realization based on kernel timers */
21#if (ZRTP_PLATFORM != ZP_WIN32_KERNEL)
22
23#define ZRTP_SCHED_QUEUE_SIZE ZRTP_MAX_STREAMS_PER_SESSION * 1000
24#define ZRTP_SCHED_LOOP_QVANT 20
25
26#define ZRTP_SCHED_SLEEP(count) zrtp_sleep(ZRTP_SCHED_LOOP_QVANT*count);
27
28
29/** Schedulling tasks structure */
30typedef struct
31{
32 zrtp_stream_t *ctx; /** ZRTP stream context associated with the task */
33 zrtp_retry_task_t *ztask; /** ZRTP stream associated with the task */
34 uint64_t wake_at; /* Wake time in milliseconds */
35 mlist_t _mlist;
36} zrtp_sched_task_t;
37
38/** Initiation flag. Protection from reinitialization. (1 if initiated) */
39static uint8_t inited = 0;
40
41/** Sorted by wake time tasks list. First task to do at the begining */
42static mlist_t tasks_head;
43
44/** Tasks queue protector againts race conditions on add/remove tasks */
45static zrtp_mutex_t* protector = NULL;
46
47/** Main queue symaphore */
48static zrtp_sem_t* count = NULL;
49
50static uint8_t is_running = 0;
51#if (ZRTP_PLATFORM == ZP_WIN32 || ZRTP_PLATFORM == ZP_WINCE)
52HANDLE scheduler_thread = NULL;
53#else
54static uint8_t is_working = 0;
55#endif
56
57
58/*==========================================================================*/
59/* Platform Dependent Routine */
60/*==========================================================================*/
61
62#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
63#include <Windows.h>
64
65int zrtp_sleep(unsigned int msec)
66{
67 Sleep(msec);
68 return 0;
69}
70
71int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg)
72{
73 DWORD dwThreadId;
74
75 scheduler_thread = CreateThread(NULL, 0, start_routine, 0, 0, &dwThreadId);
76 if (NULL == scheduler_thread) {
77 return -1;
78 }
79
80 return 0;
81}
82
fc97a919 83#elif (ZRTP_PLATFORM == ZP_LINUX) || (ZRTP_PLATFORM == ZP_DARWIN) || (ZRTP_PLATFORM == ZP_BSD) || (ZRTP_PLATFORM == ZP_ANDROID)
21c145b1
PW
84/* POSIX.1-2008 removes usleep, so use nanosleep instead when available */
85#if ZRTP_HAVE_NANOSLEEP
86#include <time.h> /* for nanosleep */
87#elif ZRTP_HAVE_UNISTD_H == 1
5a61e580
VK
88#include <unistd.h>
89#else
90#error "Used environment dosn't have <unistd.h> - zrtp_scheduler can't be build."
91#endif
21c145b1 92
5a61e580
VK
93#if ZRTP_HAVE_PTHREAD_H == 1
94#include <pthread.h>
95#else
96# error "Used environment dosn't have <pthread.h> - zrtp_scheduler can't be build."
97#endif
98
99int zrtp_sleep(unsigned int msec)
100{
21c145b1
PW
101#if ZRTP_HAVE_NANOSLEEP
102 struct timespec delay;
103 delay.tv_sec = msec / 1000;
104 delay.tv_nsec = (msec % 1000) * 1000000;
8d84aa25 105 while (nanosleep(&delay, &delay));
21c145b1 106#else
fc97a919 107 usleep(msec*1000);
21c145b1 108#endif
fc97a919 109 return 0;
5a61e580
VK
110}
111
112int zrtp_thread_create(zrtp_thread_routine_t start_routine, void *arg)
113{
114 pthread_t thread;
326370ba 115 return pthread_create(&thread, NULL, start_routine, arg);
5a61e580
VK
116}
117#endif
118
119
120/*==========================================================================*/
121/* Scheduler Implementation */
122/*==========================================================================*/
123#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WIN64) || (ZRTP_PLATFORM == ZP_WINCE)
124static DWORD WINAPI sched_loop(void* param)
125#elif (ZRTP_PLATFORM == ZP_SYMBIAN)
126static int sched_loop(void* param)
127#else
128static void* sched_loop(void* param)
129#endif
130{
131#if defined (ZRTP_DEBUG_WITH_PJSIP) && (ZRTP_DEBUG_WITH_PJSIP == 1)
132 /*
133 Register current thread if it was created by
134 external system call(not pj_sip call)
135 */
136 pj_thread_desc desc;
137 pj_thread_t *sched_loop_thread;
138
139 if (pj_thread_is_registered()==PJ_FALSE){
140 pj_thread_register("zrtp_sched_loop_thread", desc, &sched_loop_thread);
141 }
142#endif
143
144#if (ZRTP_PLATFORM != ZP_WIN32 && ZRTP_PLATFORM != ZP_WINCE)
145 is_working = 1;
146#endif
147 while (is_running)
148 {
149 zrtp_sched_task_t* task = NULL;
150 zrtp_sched_task_t task2run;
151 int ready_2_run = 0;
152 mlist_t* node = 0;
153
154 /* Wait for tasks in queue */
155 zrtp_sem_wait(count);
156
157 zrtp_mutex_lock(protector);
158
159 node = mlist_get(&tasks_head);
160 if (!node) {
161 zrtp_mutex_unlock(protector);
162 continue;
163 }
164
165 task = mlist_get_struct(zrtp_sched_task_t, _mlist, node);
166 if (task->wake_at <= zrtp_time_now())
167 {
168 task2run.ctx = task->ctx;
169 task2run.ztask = task->ztask;
170 mlist_del(node);
171 zrtp_sys_free(task);
172 ready_2_run = 1;
173 }
174
175 zrtp_mutex_unlock(protector);
176
177 if (ready_2_run) {
178 task2run.ztask->_is_busy = 1;
179 task2run.ztask->callback(task2run.ctx, task2run.ztask);
180 task2run.ztask->_is_busy = 0;
181 } else {
182 zrtp_sem_post(count);
183 }
184
185 ZRTP_SCHED_SLEEP(1);
186 }
187
188#if (ZRTP_PLATFORM != ZP_WIN32)&& (ZRTP_PLATFORM != ZP_WINCE)
189 is_working = 0;
190#endif
191
192#if (ZRTP_PLATFORM != ZP_WIN32) && (ZRTP_PLATFORM != ZP_WIN64) && (ZRTP_PLATFORM != ZP_WINCE)
193 return NULL;
194#else
195 return 0;
196#endif
197}
198
199/*---------------------------------------------------------------------------*/
200zrtp_status_t zrtp_def_scheduler_init(zrtp_global_t* zrtp)
201{
202 zrtp_status_t status = zrtp_status_ok;
203
204 if (inited) {
205 return zrtp_status_ok;
206 }
207
208 do {
209 init_mlist(&tasks_head);
210
211 if (zrtp_status_ok != (status = zrtp_mutex_init(&protector))) {
212 break;
213 }
214 if (zrtp_status_ok != (status = zrtp_sem_init(&count, 0, ZRTP_SCHED_QUEUE_SIZE))) {
215 break;
216 }
217
218 /* Starting processing loop */
219 is_running = 1;
220
221 if (0 != zrtp_thread_create(sched_loop, NULL)) {
222 zrtp_sem_destroy(count);
223 zrtp_mutex_destroy(protector);
224
225 status = zrtp_status_fail;
226 break;
227 }
228
229 inited = 1;
230 } while (0);
231
232 return status;
233}
234
235/*---------------------------------------------------------------------------*/
236void zrtp_def_scheduler_down()
237{
238 mlist_t *node = 0, *tmp = 0;
239
240 if (!inited) {
241 return;
242 }
243
244 /* Stop main thread */
245 is_running = 0;
246 zrtp_sem_post(count);
247#if (ZRTP_PLATFORM == ZP_WIN32) || (ZRTP_PLATFORM == ZP_WINCE)
248 if (NULL != scheduler_thread)
249 {
250 WaitForSingleObject(scheduler_thread, INFINITE);
251 CloseHandle(scheduler_thread);
252 scheduler_thread = NULL;
253 }
254#else
255 while (is_working) {
256 ZRTP_SCHED_SLEEP(1);
257 }
258#endif
259
260 /* Then destroy tasks queue and realease all other resources */
261 zrtp_mutex_lock(protector);
262
263 mlist_for_each_safe(node, tmp, &tasks_head) {
264 zrtp_sched_task_t* task = mlist_get_struct(zrtp_sched_task_t, _mlist, node);
265 zrtp_sys_free(task);
266 }
267 init_mlist(&tasks_head);
268
269 zrtp_mutex_unlock(protector);
270
271 zrtp_mutex_destroy(protector);
272 zrtp_sem_destroy(count);
273
274 inited = 0;
275}
276
277/*---------------------------------------------------------------------------*/
278void zrtp_def_scheduler_call_later(zrtp_stream_t *ctx, zrtp_retry_task_t* ztask)
279{
280 mlist_t *node=0, *tmp=0;
281 mlist_t* last = &tasks_head;
282
283 zrtp_mutex_lock(protector);
284
285 if (!ztask->_is_enabled) {
286 zrtp_mutex_unlock(protector);
287 return;
288 }
289
290 do {
291 zrtp_sched_task_t* new_task = zrtp_sys_alloc(sizeof(zrtp_sched_task_t));
292 if (!new_task) {
293 break;
294 }
295
296 new_task->ctx = ctx;
297 new_task->ztask = ztask;
298 new_task->wake_at = zrtp_time_now() + ztask->timeout;
299
300 /* Try to find element with later wacked time than we have */
301 mlist_for_each_safe(node, tmp, &tasks_head) {
302 zrtp_sched_task_t* tmp_task = mlist_get_struct(zrtp_sched_task_t, _mlist, node);
303 if (tmp_task->wake_at >= new_task->wake_at) {
304 last = node;
305 break;
306 }
307 }
308
309 /*
310 * If packet wasn't inserted (empty queue or all elements are smaller)
311 * Put them to the end of the queue.
312 */
313 mlist_insert(last, &new_task->_mlist);
314
315 zrtp_sem_post(count);
316 } while (0);
317
318 zrtp_mutex_unlock(protector);
319}
320
321/*---------------------------------------------------------------------------*/
322void zrtp_def_scheduler_cancel_call_later(zrtp_stream_t* ctx, zrtp_retry_task_t* ztask)
323{
324 mlist_t *node=0, *tmp=0;
325
326 zrtp_mutex_lock(protector);
327
328 mlist_for_each_safe(node, tmp, &tasks_head) {
329 zrtp_sched_task_t* task = mlist_get_struct(zrtp_sched_task_t, _mlist, node);
330 if ((task->ctx == ctx) && ((task->ztask == ztask) || !ztask)) {
331 mlist_del(&task->_mlist);
332 zrtp_sys_free(task);
333 zrtp_sem_trtwait(count);
334 if (ztask) {
335 break;
336 }
337 }
338 }
339
340 zrtp_mutex_unlock(protector);
341}
342
343void zrtp_def_scheduler_wait_call_later(zrtp_stream_t* ctx)
344{
345 while (ctx->messages.hello_task._is_busy) {
346 ZRTP_SCHED_SLEEP(1);
347 }
348 while (ctx->messages.commit_task._is_busy) {
349 ZRTP_SCHED_SLEEP(1);
350 }
351 while (ctx->messages.dhpart_task._is_busy) {
352 ZRTP_SCHED_SLEEP(1);
353 }
354 while (ctx->messages.confirm_task._is_busy) {
355 ZRTP_SCHED_SLEEP(1);
356 }
357 while (ctx->messages.error_task._is_busy) {
358 ZRTP_SCHED_SLEEP(1);
359 }
360 while (ctx->messages.errorack_task._is_busy) {
361 ZRTP_SCHED_SLEEP(1);
362 }
363 while (ctx->messages.goclear_task._is_busy) {
364 ZRTP_SCHED_SLEEP(1);
365 }
366 while (ctx->messages.dh_task._is_busy) {
367 ZRTP_SCHED_SLEEP(1);
368 }
369}
370
371#endif /* not for windows kernel */
372
373#endif // ZRTP_PLATFORM==ZP_SYMBIAN
374
375#endif /*ZRTP_USE_BUILTIN_SCEHDULER*/