This source file includes following definitions.
- FT_DECLARE
- thread_launch
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
- FT_DECLARE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #ifdef WIN32
25
26 #define _WIN32_WINNT 0x0400
27 #endif
28
29 #include "private/ftdm_core.h"
30 #include "ftdm_threadmutex.h"
31
32 #ifdef WIN32
33 #include <process.h>
34
35 #define FTDM_THREAD_CALLING_CONVENTION __stdcall
36
37 struct ftdm_mutex {
38 CRITICAL_SECTION mutex;
39 };
40
41 #else
42 #include <pthread.h>
43 #include <poll.h>
44
45 #define FTDM_THREAD_CALLING_CONVENTION
46
47 struct ftdm_mutex {
48 pthread_mutex_t mutex;
49 };
50
51 #endif
52
53 struct ftdm_interrupt {
54 ftdm_socket_t device;
55 #ifdef WIN32
56
57 HANDLE event;
58 #else
59
60 int readfd;
61 int writefd;
62 #endif
63 };
64
65 struct ftdm_thread {
66 #ifdef WIN32
67 void *handle;
68 #else
69 pthread_t handle;
70 #endif
71 void *private_data;
72 ftdm_thread_function_t function;
73 ftdm_size_t stack_size;
74 #ifndef WIN32
75 pthread_attr_t attribute;
76 #endif
77 };
78
79 ftdm_size_t thread_default_stacksize = 0;
80
81 FT_DECLARE(void) ftdm_thread_override_default_stacksize(ftdm_size_t size)
82 {
83 thread_default_stacksize = size;
84 }
85
86 static void * FTDM_THREAD_CALLING_CONVENTION thread_launch(void *args)
87 {
88 void *exit_val;
89 ftdm_thread_t *thread = (ftdm_thread_t *)args;
90 exit_val = thread->function(thread, thread->private_data);
91 #ifndef WIN32
92 pthread_attr_destroy(&thread->attribute);
93 #endif
94 ftdm_safe_free(thread);
95
96 return exit_val;
97 }
98
99 FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached(ftdm_thread_function_t func, void *data)
100 {
101 return ftdm_thread_create_detached_ex(func, data, thread_default_stacksize);
102 }
103
104 FT_DECLARE(ftdm_status_t) ftdm_thread_create_detached_ex(ftdm_thread_function_t func, void *data, ftdm_size_t stack_size)
105 {
106 ftdm_thread_t *thread = NULL;
107 ftdm_status_t status = FTDM_FAIL;
108
109 if (!func || !(thread = (ftdm_thread_t *)ftdm_malloc(sizeof(ftdm_thread_t)))) {
110 goto done;
111 }
112
113 thread->private_data = data;
114 thread->function = func;
115 thread->stack_size = stack_size;
116
117 #if defined(WIN32)
118 thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL);
119 if (!thread->handle) {
120 goto fail;
121 }
122 CloseHandle(thread->handle);
123
124 status = FTDM_SUCCESS;
125 goto done;
126 #else
127
128 if (pthread_attr_init(&thread->attribute) != 0) goto fail;
129
130 if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread;
131
132 if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread;
133
134 if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread;
135
136 status = FTDM_SUCCESS;
137 goto done;
138 failpthread:
139 pthread_attr_destroy(&thread->attribute);
140 #endif
141
142 fail:
143 if (thread) {
144 ftdm_safe_free(thread);
145 }
146 done:
147 return status;
148 }
149
150
151 FT_DECLARE(ftdm_status_t) ftdm_mutex_create(ftdm_mutex_t **mutex)
152 {
153 ftdm_status_t status = FTDM_FAIL;
154 #ifndef WIN32
155 pthread_mutexattr_t attr;
156 #endif
157 ftdm_mutex_t *check = NULL;
158
159 check = (ftdm_mutex_t *)ftdm_malloc(sizeof(**mutex));
160 if (!check)
161 goto done;
162 #ifdef WIN32
163 InitializeCriticalSection(&check->mutex);
164 #else
165 if (pthread_mutexattr_init(&attr))
166 goto done;
167
168 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
169 goto fail;
170
171 if (pthread_mutex_init(&check->mutex, &attr))
172 goto fail;
173
174 goto success;
175
176 fail:
177 pthread_mutexattr_destroy(&attr);
178 goto done;
179
180 success:
181 #endif
182 *mutex = check;
183 status = FTDM_SUCCESS;
184
185 done:
186 return status;
187 }
188
189 FT_DECLARE(ftdm_status_t) ftdm_mutex_destroy(ftdm_mutex_t **mutex)
190 {
191 ftdm_mutex_t *mp = *mutex;
192 *mutex = NULL;
193 if (!mp) {
194 return FTDM_FAIL;
195 }
196 #ifdef WIN32
197 DeleteCriticalSection(&mp->mutex);
198 #else
199 if (pthread_mutex_destroy(&mp->mutex))
200 return FTDM_FAIL;
201 #endif
202 ftdm_safe_free(mp);
203 return FTDM_SUCCESS;
204 }
205
206 FT_DECLARE(ftdm_status_t) _ftdm_mutex_lock(ftdm_mutex_t *mutex)
207 {
208 #ifdef WIN32
209 EnterCriticalSection(&mutex->mutex);
210 #else
211 int err;
212 if ((err = pthread_mutex_lock(&mutex->mutex))) {
213 ftdm_log(FTDM_LOG_ERROR, "Failed to lock mutex %d:%s\n", err, strerror(err));
214 return FTDM_FAIL;
215 }
216 #endif
217 return FTDM_SUCCESS;
218 }
219
220 FT_DECLARE(ftdm_status_t) _ftdm_mutex_trylock(ftdm_mutex_t *mutex)
221 {
222 #ifdef WIN32
223 if (!TryEnterCriticalSection(&mutex->mutex))
224 return FTDM_FAIL;
225 #else
226 if (pthread_mutex_trylock(&mutex->mutex))
227 return FTDM_FAIL;
228 #endif
229 return FTDM_SUCCESS;
230 }
231
232 FT_DECLARE(ftdm_status_t) _ftdm_mutex_unlock(ftdm_mutex_t *mutex)
233 {
234 #ifdef WIN32
235 LeaveCriticalSection(&mutex->mutex);
236 #else
237 if (pthread_mutex_unlock(&mutex->mutex))
238 return FTDM_FAIL;
239 #endif
240 return FTDM_SUCCESS;
241 }
242
243
244 FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt, ftdm_socket_t device)
245 {
246 ftdm_interrupt_t *interrupt = NULL;
247 #ifndef WIN32
248 int fds[2];
249 #endif
250
251 ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "interrupt double pointer is null!\n");
252
253 interrupt = ftdm_calloc(1, sizeof(*interrupt));
254 if (!interrupt) {
255 ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt memory\n");
256 return FTDM_FAIL;
257 }
258
259 interrupt->device = device;
260 #ifdef WIN32
261 interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
262 if (!interrupt->event) {
263 ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
264 goto failed;
265 }
266 #else
267 if (pipe(fds)) {
268 ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt pipe: %s\n", strerror(errno));
269 goto failed;
270 }
271 interrupt->readfd = fds[0];
272 interrupt->writefd = fds[1];
273 #endif
274
275 *ininterrupt = interrupt;
276 return FTDM_SUCCESS;
277
278 failed:
279 if (interrupt) {
280 #ifndef WIN32
281 if (interrupt->readfd) {
282 close(interrupt->readfd);
283 close(interrupt->writefd);
284 interrupt->readfd = -1;
285 interrupt->writefd = -1;
286 }
287 #endif
288 ftdm_safe_free(interrupt);
289 }
290 return FTDM_FAIL;
291 }
292
293 #define ONE_BILLION 1000000000
294
295 FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int ms)
296 {
297 int num = 1;
298 #ifdef WIN32
299 DWORD res = 0;
300 HANDLE ints[2];
301 #else
302 int res = 0;
303 struct pollfd ints[2];
304 char pipebuf[255];
305 #endif
306
307 ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Condition is null!\n");
308
309
310
311 #ifdef WIN32
312 ints[0] = interrupt->event;
313 if (interrupt->device != FTDM_INVALID_SOCKET) {
314 num++;
315 ints[1] = interrupt->device;
316 }
317 res = WaitForMultipleObjects(num, ints, FALSE, ms >= 0 ? ms : INFINITE);
318 switch (res) {
319 case WAIT_TIMEOUT:
320 return FTDM_TIMEOUT;
321 case WAIT_FAILED:
322 case WAIT_ABANDONED:
323 return FTDM_FAIL;
324 default:
325 if (res >= (sizeof(ints)/sizeof(ints[0]))) {
326 ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res);
327 return FTDM_FAIL;
328 }
329 return FTDM_SUCCESS;
330 }
331 #else
332 pollagain:
333 ints[0].fd = interrupt->readfd;
334 ints[0].events = POLLIN;
335 ints[0].revents = 0;
336
337 if (interrupt->device != FTDM_INVALID_SOCKET) {
338 num++;
339 ints[1].fd = interrupt->device;
340 ints[1].events = POLLIN;
341 ints[1].revents = 0;
342 }
343
344 res = poll(ints, num, ms);
345
346 if (res == -1) {
347 if (errno == EINTR) {
348 goto pollagain;
349 }
350 ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
351 return FTDM_FAIL;
352 }
353
354 if (res == 0) {
355 return FTDM_TIMEOUT;
356 }
357
358 if (ints[0].revents & POLLIN) {
359 res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
360 if (res == -1) {
361 ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
362 }
363 }
364
365 return FTDM_SUCCESS;
366 #endif
367 }
368
369 FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt)
370 {
371 ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n");
372 #ifdef WIN32
373 if (!SetEvent(interrupt->event)) {
374 ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n");
375 return FTDM_FAIL;
376
377 }
378 #else
379 int err;
380 struct pollfd testpoll;
381 testpoll.revents = 0;
382 testpoll.events = POLLIN;
383 testpoll.fd = interrupt->readfd;
384 err = poll(&testpoll, 1, 0);
385 if (err == 0 && !(testpoll.revents & POLLIN)) {
386
387
388
389 if ((err = write(interrupt->writefd, "w", 1)) != 1) {
390 ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt: %s\n", errno, strerror(errno));
391 return FTDM_FAIL;
392 }
393 }
394 #endif
395 return FTDM_SUCCESS;
396 }
397
398 FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt)
399 {
400 ftdm_interrupt_t *interrupt = NULL;
401 ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n");
402 interrupt = *ininterrupt;
403 #ifdef WIN32
404 CloseHandle(interrupt->event);
405 #else
406 close(interrupt->readfd);
407 close(interrupt->writefd);
408
409 interrupt->readfd = -1;
410 interrupt->writefd = -1;
411 #endif
412 ftdm_safe_free(interrupt);
413 *ininterrupt = NULL;
414 return FTDM_SUCCESS;
415 }
416
417 FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms)
418 {
419 int numdevices = 0;
420 unsigned i;
421
422 #if defined(__WINDOWS__)
423 DWORD res = 0;
424 HANDLE ints[20];
425 if (size > (ftdm_array_len(ints)/2)) {
426
427 ftdm_log(FTDM_LOG_CRIT, "Unsupported size of interrupts: %d, implement me!\n", size);
428 return FTDM_FAIL;
429 }
430
431 for (i = 0; i < size; i++) {
432 ints[i] = interrupts[i]->event;
433 if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
434
435 ints[size+numdevices] = interrupts[i]->device;
436 numdevices++;
437 }
438 }
439
440 res = WaitForMultipleObjects((DWORD)size+numdevices, ints, FALSE, ms >= 0 ? ms : INFINITE);
441
442 switch (res) {
443 case WAIT_TIMEOUT:
444 return FTDM_TIMEOUT;
445 case WAIT_FAILED:
446 case WAIT_ABANDONED:
447 return FTDM_FAIL;
448 default:
449 if (res >= (size+numdevices)) {
450 ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res);
451 return FTDM_FAIL;
452 }
453
454 }
455 #elif defined(__linux__) || defined(__FreeBSD__)
456 int res = 0;
457 char pipebuf[255];
458 struct pollfd ints[size*2];
459
460 memset(&ints, 0, sizeof(ints));
461 pollagain:
462 for (i = 0; i < size; i++) {
463 ints[i].events = POLLIN;
464 ints[i].revents = 0;
465 ints[i].fd = interrupts[i]->readfd;
466 if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
467 ints[size+numdevices].events = POLLIN;
468 ints[size+numdevices].revents = 0;
469 ints[size+numdevices].fd = interrupts[i]->device;
470
471 numdevices++;
472 }
473 }
474
475 res = poll(ints, size + numdevices, ms);
476
477 if (res == -1) {
478 if (errno == EINTR) {
479 goto pollagain;
480 }
481 ftdm_log(FTDM_LOG_CRIT, "interrupt poll failed (%s)\n", strerror(errno));
482 return FTDM_FAIL;
483 }
484
485 if (res == 0) {
486 return FTDM_TIMEOUT;
487 }
488
489
490 for (i = 0; i < size; i++) {
491 if (ints[i].revents & POLLIN) {
492 res = read(ints[i].fd, pipebuf, sizeof(pipebuf));
493 if (res == -1) {
494 ftdm_log(FTDM_LOG_CRIT, "reading interrupt descriptor failed (%s)\n", strerror(errno));
495 }
496 }
497 }
498 #else
499 #endif
500 return FTDM_SUCCESS;
501 }
502
503
504
505
506
507
508
509
510
511
512