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