blob: 252f7fcc5ec3c69920cbcadc34f251fcb7c1f5db [file] [log] [blame]
Alexandre Lision67916dd2014-01-24 13:33:04 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20/*
21 * Contributors:
22 * - Thanks for Zetron, Inc. (Phil Torre, ptorre@zetron.com) for donating
23 * the RTEMS port.
24 */
25#ifndef _GNU_SOURCE
26# define _GNU_SOURCE
27#endif
28#include <pj/os.h>
29#include <pj/assert.h>
30#include <pj/pool.h>
31#include <pj/log.h>
32#include <pj/rand.h>
33#include <pj/string.h>
34#include <pj/guid.h>
35#include <pj/except.h>
36#include <pj/errno.h>
37
38#if defined(PJ_HAS_SEMAPHORE_H) && PJ_HAS_SEMAPHORE_H != 0
39# include <semaphore.h>
40#endif
41
42#include <unistd.h> // getpid()
43#include <errno.h> // errno
44
45#include <pthread.h>
46
47#define THIS_FILE "os_core_unix.c"
48
49#define SIGNATURE1 0xDEAFBEEF
50#define SIGNATURE2 0xDEADC0DE
51
52struct pj_thread_t
53{
54 char obj_name[PJ_MAX_OBJ_NAME];
55 pthread_t thread;
56 pj_thread_proc *proc;
57 void *arg;
58 pj_uint32_t signature1;
59 pj_uint32_t signature2;
60
61 pj_mutex_t *suspended_mutex;
62
63#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
64 pj_uint32_t stk_size;
65 pj_uint32_t stk_max_usage;
66 char *stk_start;
67 const char *caller_file;
68 int caller_line;
69#endif
70};
71
72struct pj_atomic_t
73{
74 pj_mutex_t *mutex;
75 pj_atomic_value_t value;
76};
77
78struct pj_mutex_t
79{
80 pthread_mutex_t mutex;
81 char obj_name[PJ_MAX_OBJ_NAME];
82#if PJ_DEBUG
83 int nesting_level;
84 pj_thread_t *owner;
85 char owner_name[PJ_MAX_OBJ_NAME];
86#endif
87};
88
89#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
90struct pj_sem_t
91{
92 sem_t *sem;
93 char obj_name[PJ_MAX_OBJ_NAME];
94};
95#endif /* PJ_HAS_SEMAPHORE */
96
97#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
98struct pj_event_t
99{
100 enum event_state {
101 EV_STATE_OFF,
102 EV_STATE_SET,
103 EV_STATE_PULSED
104 } state;
105
106 pj_mutex_t mutex;
107 pthread_cond_t cond;
108
109 pj_bool_t auto_reset;
110 unsigned threads_waiting;
111 unsigned threads_to_release;
112};
113#endif /* PJ_HAS_EVENT_OBJ */
114
115
116/*
117 * Flag and reference counter for PJLIB instance.
118 */
119static int initialized;
120
121#if PJ_HAS_THREADS
122 static pj_thread_t main_thread;
123 static long thread_tls_id;
124 static pj_mutex_t critical_section;
125#else
126# define MAX_THREADS 32
127 static int tls_flag[MAX_THREADS];
128 static void *tls[MAX_THREADS];
129#endif
130
131static unsigned atexit_count;
132static void (*atexit_func[32])(void);
133
134static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
135
136/*
137 * pj_init(void).
138 * Init PJLIB!
139 */
140PJ_DEF(pj_status_t) pj_init(void)
141{
142 char dummy_guid[PJ_GUID_MAX_LENGTH];
143 pj_str_t guid;
144 pj_status_t rc;
145
146 /* Check if PJLIB have been initialized */
147 if (initialized) {
148 ++initialized;
149 return PJ_SUCCESS;
150 }
151
152#if PJ_HAS_THREADS
153 /* Init this thread's TLS. */
154 if ((rc=pj_thread_init()) != 0) {
155 return rc;
156 }
157
158 /* Critical section. */
159 if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_RECURSE)) != 0)
160 return rc;
161
162#endif
163
164 /* Init logging */
165 pj_log_init();
166
167 /* Initialize exception ID for the pool.
168 * Must do so after critical section is configured.
169 */
170 rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
171 if (rc != PJ_SUCCESS)
172 return rc;
173
174 /* Init random seed. */
175 /* Or probably not. Let application in charge of this */
176 /* pj_srand( clock() ); */
177
178 /* Startup GUID. */
179 guid.ptr = dummy_guid;
180 pj_generate_unique_string( &guid );
181
182 /* Startup timestamp */
183#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
184 {
185 pj_timestamp dummy_ts;
186 if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
187 return rc;
188 }
189 }
190#endif
191
192 /* Flag PJLIB as initialized */
193 ++initialized;
194 pj_assert(initialized == 1);
195
196 PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
197 PJ_VERSION));
198
199 return PJ_SUCCESS;
200}
201
202/*
203 * pj_atexit()
204 */
205PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
206{
207 if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
208 return PJ_ETOOMANY;
209
210 atexit_func[atexit_count++] = func;
211 return PJ_SUCCESS;
212}
213
214/*
215 * pj_shutdown(void)
216 */
217PJ_DEF(void) pj_shutdown()
218{
219 int i;
220
221 /* Only perform shutdown operation when 'initialized' reaches zero */
222 pj_assert(initialized > 0);
223 if (--initialized != 0)
224 return;
225
226 /* Call atexit() functions */
227 for (i=atexit_count-1; i>=0; --i) {
228 (*atexit_func[i])();
229 }
230 atexit_count = 0;
231
232 /* Free exception ID */
233 if (PJ_NO_MEMORY_EXCEPTION != -1) {
234 pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
235 PJ_NO_MEMORY_EXCEPTION = -1;
236 }
237
238#if PJ_HAS_THREADS
239 /* Destroy PJLIB critical section */
240 pj_mutex_destroy(&critical_section);
241
242 /* Free PJLIB TLS */
243 if (thread_tls_id != -1) {
244 pj_thread_local_free(thread_tls_id);
245 thread_tls_id = -1;
246 }
247
248 /* Ticket #1132: Assertion when (re)starting PJLIB on different thread */
249 pj_bzero(&main_thread, sizeof(main_thread));
250#endif
251
252 /* Clear static variables */
253 pj_errno_clear_handlers();
254}
255
256
257/*
258 * pj_getpid(void)
259 */
260PJ_DEF(pj_uint32_t) pj_getpid(void)
261{
262 PJ_CHECK_STACK();
263 return getpid();
264}
265
266/*
267 * Check if this thread has been registered to PJLIB.
268 */
269PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
270{
271#if PJ_HAS_THREADS
272 return pj_thread_local_get(thread_tls_id) != 0;
273#else
274 pj_assert("pj_thread_is_registered() called in non-threading mode!");
275 return PJ_TRUE;
276#endif
277}
278
279
280/*
281 * Get thread priority value for the thread.
282 */
283PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
284{
285#if PJ_HAS_THREADS
286 struct sched_param param;
287 int policy;
288 int rc;
289
290 rc = pthread_getschedparam (thread->thread, &policy, &param);
291 if (rc != 0)
292 return -1;
293
294 return param.sched_priority;
295#else
296 PJ_UNUSED_ARG(thread);
297 return 1;
298#endif
299}
300
301
302/*
303 * Set the thread priority.
304 */
305PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread, int prio)
306{
307#if PJ_HAS_THREADS
308 struct sched_param param;
309 int policy;
310 int rc;
311
312 rc = pthread_getschedparam (thread->thread, &policy, &param);
313 if (rc != 0)
314 return PJ_RETURN_OS_ERROR(rc);
315
316 param.sched_priority = prio;
317
318 rc = pthread_setschedparam(thread->thread, policy, &param);
319 if (rc != 0)
320 return PJ_RETURN_OS_ERROR(rc);
321
322 return PJ_SUCCESS;
323#else
324 PJ_UNUSED_ARG(thread);
325 PJ_UNUSED_ARG(prio);
326 pj_assert("pj_thread_set_prio() called in non-threading mode!");
327 return 1;
328#endif
329}
330
331
332/*
333 * Get the lowest priority value available on this system.
334 */
335PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
336{
337 struct sched_param param;
338 int policy;
339 int rc;
340
341 rc = pthread_getschedparam(thread->thread, &policy, &param);
342 if (rc != 0)
343 return -1;
344
345#if defined(_POSIX_PRIORITY_SCHEDULING)
346 return sched_get_priority_min(policy);
347#elif defined __OpenBSD__
348 /* Thread prio min/max are declared in OpenBSD private hdr */
349 return 0;
350#else
351 pj_assert("pj_thread_get_prio_min() not supported!");
352 return 0;
353#endif
354}
355
356
357/*
358 * Get the highest priority value available on this system.
359 */
360PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
361{
362 struct sched_param param;
363 int policy;
364 int rc;
365
366 rc = pthread_getschedparam(thread->thread, &policy, &param);
367 if (rc != 0)
368 return -1;
369
370#if defined(_POSIX_PRIORITY_SCHEDULING)
371 return sched_get_priority_max(policy);
372#elif defined __OpenBSD__
373 /* Thread prio min/max are declared in OpenBSD private hdr */
374 return 31;
375#else
376 pj_assert("pj_thread_get_prio_max() not supported!");
377 return 0;
378#endif
379}
380
381
382/*
383 * Get native thread handle
384 */
385PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread)
386{
387 PJ_ASSERT_RETURN(thread, NULL);
388
389#if PJ_HAS_THREADS
390 return &thread->thread;
391#else
392 pj_assert("pj_thread_is_registered() called in non-threading mode!");
393 return NULL;
394#endif
395}
396
397/*
398 * pj_thread_register(..)
399 */
400PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
401 pj_thread_desc desc,
402 pj_thread_t **ptr_thread)
403{
404#if PJ_HAS_THREADS
405 char stack_ptr;
406 pj_status_t rc;
407 pj_thread_t *thread = (pj_thread_t *)desc;
408 pj_str_t thread_name = pj_str((char*)cstr_thread_name);
409
410 /* Size sanity check. */
411 if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
412 pj_assert(!"Not enough pj_thread_desc size!");
413 return PJ_EBUG;
414 }
415
416 /* Warn if this thread has been registered before */
417 if (pj_thread_local_get (thread_tls_id) != 0) {
418 // 2006-02-26 bennylp:
419 // This wouldn't work in all cases!.
420 // If thread is created by external module (e.g. sound thread),
421 // thread may be reused while the pool used for the thread descriptor
422 // has been deleted by application.
423 //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
424 //return PJ_SUCCESS;
425 PJ_LOG(4,(THIS_FILE, "Info: possibly re-registering existing "
426 "thread"));
427 }
428
429 /* On the other hand, also warn if the thread descriptor buffer seem to
430 * have been used to register other threads.
431 */
432 pj_assert(thread->signature1 != SIGNATURE1 ||
433 thread->signature2 != SIGNATURE2 ||
434 (thread->thread == pthread_self()));
435
436 /* Initialize and set the thread entry. */
437 pj_bzero(desc, sizeof(struct pj_thread_t));
438 thread->thread = pthread_self();
439 thread->signature1 = SIGNATURE1;
440 thread->signature2 = SIGNATURE2;
441
442 if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
443 pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
444 cstr_thread_name, thread->thread);
445 else
446 pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
447 "thr%p", (void*)thread->thread);
448
449 rc = pj_thread_local_set(thread_tls_id, thread);
450 if (rc != PJ_SUCCESS) {
451 pj_bzero(desc, sizeof(struct pj_thread_t));
452 return rc;
453 }
454
455#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
456 thread->stk_start = &stack_ptr;
457 thread->stk_size = 0xFFFFFFFFUL;
458 thread->stk_max_usage = 0;
459#else
460 stack_ptr = '\0';
461#endif
462
463 *ptr_thread = thread;
464 return PJ_SUCCESS;
465#else
466 pj_thread_t *thread = (pj_thread_t*)desc;
467 *ptr_thread = thread;
468 return PJ_SUCCESS;
469#endif
470}
471
472/*
473 * pj_thread_init(void)
474 */
475pj_status_t pj_thread_init(void)
476{
477#if PJ_HAS_THREADS
478 pj_status_t rc;
479 pj_thread_t *dummy;
480
481 rc = pj_thread_local_alloc(&thread_tls_id );
482 if (rc != PJ_SUCCESS) {
483 return rc;
484 }
485 return pj_thread_register("thr%p", (long*)&main_thread, &dummy);
486#else
487 PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
488 return PJ_EINVALIDOP;
489#endif
490}
491
492#if PJ_HAS_THREADS
493/*
494 * thread_main()
495 *
496 * This is the main entry for all threads.
497 */
498static void *thread_main(void *param)
499{
500 pj_thread_t *rec = (pj_thread_t*)param;
501 void *result;
502 pj_status_t rc;
503
504#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
505 rec->stk_start = (char*)&rec;
506#endif
507
508 /* Set current thread id. */
509 rc = pj_thread_local_set(thread_tls_id, rec);
510 if (rc != PJ_SUCCESS) {
511 pj_assert(!"Thread TLS ID is not set (pj_init() error?)");
512 }
513
514 /* Check if suspension is required. */
515 if (rec->suspended_mutex) {
516 pj_mutex_lock(rec->suspended_mutex);
517 pj_mutex_unlock(rec->suspended_mutex);
518 }
519
520 PJ_LOG(6,(rec->obj_name, "Thread started"));
521
522 /* Call user's entry! */
523 result = (void*)(long)(*rec->proc)(rec->arg);
524
525 /* Done. */
526 PJ_LOG(6,(rec->obj_name, "Thread quitting"));
527
528 return result;
529}
530#endif
531
532/*
533 * pj_thread_create(...)
534 */
535PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
536 const char *thread_name,
537 pj_thread_proc *proc,
538 void *arg,
539 pj_size_t stack_size,
540 unsigned flags,
541 pj_thread_t **ptr_thread)
542{
543#if PJ_HAS_THREADS
544 pj_thread_t *rec;
545 pthread_attr_t thread_attr;
546 void *stack_addr;
547 int rc;
548
549 PJ_UNUSED_ARG(stack_addr);
550
551 PJ_CHECK_STACK();
552 PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
553
554 /* Create thread record and assign name for the thread */
555 rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
556 PJ_ASSERT_RETURN(rec, PJ_ENOMEM);
557
558 /* Set name. */
559 if (!thread_name)
560 thread_name = "thr%p";
561
562 if (strchr(thread_name, '%')) {
563 pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
564 } else {
565 strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
566 rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
567 }
568
569 /* Set default stack size */
570 if (stack_size == 0)
571 stack_size = PJ_THREAD_DEFAULT_STACK_SIZE;
572
573#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
574 rec->stk_size = stack_size;
575 rec->stk_max_usage = 0;
576#endif
577
578 /* Emulate suspended thread with mutex. */
579 if (flags & PJ_THREAD_SUSPENDED) {
580 rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
581 if (rc != PJ_SUCCESS) {
582 return rc;
583 }
584
585 pj_mutex_lock(rec->suspended_mutex);
586 } else {
587 pj_assert(rec->suspended_mutex == NULL);
588 }
589
590
591 /* Init thread attributes */
592 pthread_attr_init(&thread_attr);
593
594#if defined(PJ_THREAD_SET_STACK_SIZE) && PJ_THREAD_SET_STACK_SIZE!=0
595 /* Set thread's stack size */
596 rc = pthread_attr_setstacksize(&thread_attr, stack_size);
597 if (rc != 0)
598 return PJ_RETURN_OS_ERROR(rc);
599#endif /* PJ_THREAD_SET_STACK_SIZE */
600
601
602#if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0
603 /* Allocate memory for the stack */
604 stack_addr = pj_pool_alloc(pool, stack_size);
605 PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM);
606
607 rc = pthread_attr_setstackaddr(&thread_attr, stack_addr);
608 if (rc != 0)
609 return PJ_RETURN_OS_ERROR(rc);
610#endif /* PJ_THREAD_ALLOCATE_STACK */
611
612
613 /* Create the thread. */
614 rec->proc = proc;
615 rec->arg = arg;
616 rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec);
617 if (rc != 0) {
618 return PJ_RETURN_OS_ERROR(rc);
619 }
620
621 *ptr_thread = rec;
622
623 PJ_LOG(6, (rec->obj_name, "Thread created"));
624 return PJ_SUCCESS;
625#else
626 pj_assert(!"Threading is disabled!");
627 return PJ_EINVALIDOP;
628#endif
629}
630
631/*
632 * pj_thread-get_name()
633 */
634PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
635{
636#if PJ_HAS_THREADS
637 pj_thread_t *rec = (pj_thread_t*)p;
638
639 PJ_CHECK_STACK();
640 PJ_ASSERT_RETURN(p, "");
641
642 return rec->obj_name;
643#else
644 return "";
645#endif
646}
647
648/*
649 * pj_thread_resume()
650 */
651PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
652{
653 pj_status_t rc;
654
655 PJ_CHECK_STACK();
656 PJ_ASSERT_RETURN(p, PJ_EINVAL);
657
658 rc = pj_mutex_unlock(p->suspended_mutex);
659
660 return rc;
661}
662
663/*
664 * pj_thread_this()
665 */
666PJ_DEF(pj_thread_t*) pj_thread_this(void)
667{
668#if PJ_HAS_THREADS
669 pj_thread_t *rec = (pj_thread_t*)pj_thread_local_get(thread_tls_id);
670
671 if (rec == NULL) {
672 pj_assert(!"Calling pjlib from unknown/external thread. You must "
673 "register external threads with pj_thread_register() "
674 "before calling any pjlib functions.");
675 }
676
677 /*
678 * MUST NOT check stack because this function is called
679 * by PJ_CHECK_STACK() itself!!!
680 *
681 */
682
683 return rec;
684#else
685 pj_assert(!"Threading is not enabled!");
686 return NULL;
687#endif
688}
689
690/*
691 * pj_thread_join()
692 */
693PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
694{
695#if PJ_HAS_THREADS
696 pj_thread_t *rec = (pj_thread_t *)p;
697 void *ret;
698 int result;
699
700 PJ_CHECK_STACK();
701
702 PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
703 result = pthread_join( rec->thread, &ret);
704
705 if (result == 0)
706 return PJ_SUCCESS;
707 else {
708 /* Calling pthread_join() on a thread that no longer exists and
709 * getting back ESRCH isn't an error (in this context).
710 * Thanks Phil Torre <ptorre@zetron.com>.
711 */
712 return result==ESRCH ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(result);
713 }
714#else
715 PJ_CHECK_STACK();
716 pj_assert(!"No multithreading support!");
717 return PJ_EINVALIDOP;
718#endif
719}
720
721/*
722 * pj_thread_destroy()
723 */
724PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
725{
726 PJ_CHECK_STACK();
727
728 /* Destroy mutex used to suspend thread */
729 if (p->suspended_mutex) {
730 pj_mutex_destroy(p->suspended_mutex);
731 p->suspended_mutex = NULL;
732 }
733
734 return PJ_SUCCESS;
735}
736
737/*
738 * pj_thread_sleep()
739 */
740PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
741{
742/* TODO: should change this to something like PJ_OS_HAS_NANOSLEEP */
743#if defined(PJ_RTEMS) && PJ_RTEMS!=0
744 enum { NANOSEC_PER_MSEC = 1000000 };
745 struct timespec req;
746
747 PJ_CHECK_STACK();
748 req.tv_sec = msec / 1000;
749 req.tv_nsec = (msec % 1000) * NANOSEC_PER_MSEC;
750
751 if (nanosleep(&req, NULL) == 0)
752 return PJ_SUCCESS;
753
754 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
755#else
756 PJ_CHECK_STACK();
757
758 pj_set_os_error(0);
759
760 usleep(msec * 1000);
761
762 /* MacOS X (reported on 10.5) seems to always set errno to ETIMEDOUT.
763 * It does so because usleep() is declared to return int, and we're
764 * supposed to check for errno only when usleep() returns non-zero.
765 * Unfortunately, usleep() is declared to return void in other platforms
766 * so it's not possible to always check for the return value (unless
767 * we add a detection routine in autoconf).
768 *
769 * As a workaround, here we check if ETIMEDOUT is returned and
770 * return successfully if it is.
771 */
772 if (pj_get_native_os_error() == ETIMEDOUT)
773 return PJ_SUCCESS;
774
775 return pj_get_os_error();
776
777#endif /* PJ_RTEMS */
778}
779
780#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
781/*
782 * pj_thread_check_stack()
783 * Implementation for PJ_CHECK_STACK()
784 */
785PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
786{
787 char stk_ptr;
788 pj_uint32_t usage;
789 pj_thread_t *thread = pj_thread_this();
790
791 /* Calculate current usage. */
792 usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
793 thread->stk_start - &stk_ptr;
794
795 /* Assert if stack usage is dangerously high. */
796 pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
797
798 /* Keep statistic. */
799 if (usage > thread->stk_max_usage) {
800 thread->stk_max_usage = usage;
801 thread->caller_file = file;
802 thread->caller_line = line;
803 }
804}
805
806/*
807 * pj_thread_get_stack_max_usage()
808 */
809PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
810{
811 return thread->stk_max_usage;
812}
813
814/*
815 * pj_thread_get_stack_info()
816 */
817PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
818 const char **file,
819 int *line )
820{
821 pj_assert(thread);
822
823 *file = thread->caller_file;
824 *line = thread->caller_line;
825 return 0;
826}
827
828#endif /* PJ_OS_HAS_CHECK_STACK */
829
830///////////////////////////////////////////////////////////////////////////////
831/*
832 * pj_atomic_create()
833 */
834PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
835 pj_atomic_value_t initial,
836 pj_atomic_t **ptr_atomic)
837{
838 pj_status_t rc;
839 pj_atomic_t *atomic_var;
840
841 atomic_var = PJ_POOL_ZALLOC_T(pool, pj_atomic_t);
842
843 PJ_ASSERT_RETURN(atomic_var, PJ_ENOMEM);
844
845#if PJ_HAS_THREADS
846 rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
847 if (rc != PJ_SUCCESS)
848 return rc;
849#endif
850 atomic_var->value = initial;
851
852 *ptr_atomic = atomic_var;
853 return PJ_SUCCESS;
854}
855
856/*
857 * pj_atomic_destroy()
858 */
859PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
860{
861 PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
862#if PJ_HAS_THREADS
863 return pj_mutex_destroy( atomic_var->mutex );
864#else
865 return 0;
866#endif
867}
868
869/*
870 * pj_atomic_set()
871 */
872PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
873{
874 PJ_CHECK_STACK();
875
876#if PJ_HAS_THREADS
877 pj_mutex_lock( atomic_var->mutex );
878#endif
879 atomic_var->value = value;
880#if PJ_HAS_THREADS
881 pj_mutex_unlock( atomic_var->mutex);
882#endif
883}
884
885/*
886 * pj_atomic_get()
887 */
888PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
889{
890 pj_atomic_value_t oldval;
891
892 PJ_CHECK_STACK();
893
894#if PJ_HAS_THREADS
895 pj_mutex_lock( atomic_var->mutex );
896#endif
897 oldval = atomic_var->value;
898#if PJ_HAS_THREADS
899 pj_mutex_unlock( atomic_var->mutex);
900#endif
901 return oldval;
902}
903
904/*
905 * pj_atomic_inc_and_get()
906 */
907PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
908{
909 pj_atomic_value_t new_value;
910
911 PJ_CHECK_STACK();
912
913#if PJ_HAS_THREADS
914 pj_mutex_lock( atomic_var->mutex );
915#endif
916 new_value = ++atomic_var->value;
917#if PJ_HAS_THREADS
918 pj_mutex_unlock( atomic_var->mutex);
919#endif
920
921 return new_value;
922}
923/*
924 * pj_atomic_inc()
925 */
926PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
927{
928 pj_atomic_inc_and_get(atomic_var);
929}
930
931/*
932 * pj_atomic_dec_and_get()
933 */
934PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
935{
936 pj_atomic_value_t new_value;
937
938 PJ_CHECK_STACK();
939
940#if PJ_HAS_THREADS
941 pj_mutex_lock( atomic_var->mutex );
942#endif
943 new_value = --atomic_var->value;
944#if PJ_HAS_THREADS
945 pj_mutex_unlock( atomic_var->mutex);
946#endif
947
948 return new_value;
949}
950
951/*
952 * pj_atomic_dec()
953 */
954PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
955{
956 pj_atomic_dec_and_get(atomic_var);
957}
958
959/*
960 * pj_atomic_add_and_get()
961 */
962PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
963 pj_atomic_value_t value )
964{
965 pj_atomic_value_t new_value;
966
967#if PJ_HAS_THREADS
968 pj_mutex_lock(atomic_var->mutex);
969#endif
970
971 atomic_var->value += value;
972 new_value = atomic_var->value;
973
974#if PJ_HAS_THREADS
975 pj_mutex_unlock(atomic_var->mutex);
976#endif
977
978 return new_value;
979}
980
981/*
982 * pj_atomic_add()
983 */
984PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
985 pj_atomic_value_t value )
986{
987 pj_atomic_add_and_get(atomic_var, value);
988}
989
990///////////////////////////////////////////////////////////////////////////////
991/*
992 * pj_thread_local_alloc()
993 */
994PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
995{
996#if PJ_HAS_THREADS
997 pthread_key_t key;
998 int rc;
999
1000 PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
1001
1002 pj_assert( sizeof(pthread_key_t) <= sizeof(long));
1003 if ((rc=pthread_key_create(&key, NULL)) != 0)
1004 return PJ_RETURN_OS_ERROR(rc);
1005
1006 *p_index = key;
1007 return PJ_SUCCESS;
1008#else
1009 int i;
1010 for (i=0; i<MAX_THREADS; ++i) {
1011 if (tls_flag[i] == 0)
1012 break;
1013 }
1014 if (i == MAX_THREADS)
1015 return PJ_ETOOMANY;
1016
1017 tls_flag[i] = 1;
1018 tls[i] = NULL;
1019
1020 *p_index = i;
1021 return PJ_SUCCESS;
1022#endif
1023}
1024
1025/*
1026 * pj_thread_local_free()
1027 */
1028PJ_DEF(void) pj_thread_local_free(long index)
1029{
1030 PJ_CHECK_STACK();
1031#if PJ_HAS_THREADS
1032 pthread_key_delete(index);
1033#else
1034 tls_flag[index] = 0;
1035#endif
1036}
1037
1038/*
1039 * pj_thread_local_set()
1040 */
1041PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
1042{
1043 //Can't check stack because this function is called in the
1044 //beginning before main thread is initialized.
1045 //PJ_CHECK_STACK();
1046#if PJ_HAS_THREADS
1047 int rc=pthread_setspecific(index, value);
1048 return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
1049#else
1050 pj_assert(index >= 0 && index < MAX_THREADS);
1051 tls[index] = value;
1052 return PJ_SUCCESS;
1053#endif
1054}
1055
1056PJ_DEF(void*) pj_thread_local_get(long index)
1057{
1058 //Can't check stack because this function is called
1059 //by PJ_CHECK_STACK() itself!!!
1060 //PJ_CHECK_STACK();
1061#if PJ_HAS_THREADS
1062 return pthread_getspecific(index);
1063#else
1064 pj_assert(index >= 0 && index < MAX_THREADS);
1065 return tls[index];
1066#endif
1067}
1068
1069///////////////////////////////////////////////////////////////////////////////
1070PJ_DEF(void) pj_enter_critical_section(void)
1071{
1072#if PJ_HAS_THREADS
1073 pj_mutex_lock(&critical_section);
1074#endif
1075}
1076
1077PJ_DEF(void) pj_leave_critical_section(void)
1078{
1079#if PJ_HAS_THREADS
1080 pj_mutex_unlock(&critical_section);
1081#endif
1082}
1083
1084
1085///////////////////////////////////////////////////////////////////////////////
1086#if defined(PJ_LINUX) && PJ_LINUX!=0
1087PJ_BEGIN_DECL
1088PJ_DECL(int) pthread_mutexattr_settype(pthread_mutexattr_t*,int);
1089PJ_END_DECL
1090#endif
1091
1092static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
1093{
1094#if PJ_HAS_THREADS
1095 pthread_mutexattr_t attr;
1096 int rc;
1097
1098 PJ_CHECK_STACK();
1099
1100 rc = pthread_mutexattr_init(&attr);
1101 if (rc != 0)
1102 return PJ_RETURN_OS_ERROR(rc);
1103
1104 if (type == PJ_MUTEX_SIMPLE) {
1105#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
1106 defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
1107 rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
1108#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
1109 defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
1110 /* Nothing to do, default is simple */
1111#else
1112 rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
1113#endif
1114 } else {
1115#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \
1116 defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE)
1117 rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
1118#elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \
1119 defined(PJ_PTHREAD_MUTEXATTR_T_HAS_RECURSIVE)
1120 // Phil Torre <ptorre@zetron.com>:
1121 // The RTEMS implementation of POSIX mutexes doesn't include
1122 // pthread_mutexattr_settype(), so what follows is a hack
1123 // until I get RTEMS patched to support the set/get functions.
1124 //
1125 // More info:
1126 // newlib's pthread also lacks pthread_mutexattr_settype(),
1127 // but it seems to have mutexattr.recursive.
1128 PJ_TODO(FIX_RTEMS_RECURSIVE_MUTEX_TYPE)
1129 attr.recursive = 1;
1130#else
1131 rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1132#endif
1133 }
1134
1135 if (rc != 0) {
1136 return PJ_RETURN_OS_ERROR(rc);
1137 }
1138
1139 rc = pthread_mutex_init(&mutex->mutex, &attr);
1140 if (rc != 0) {
1141 return PJ_RETURN_OS_ERROR(rc);
1142 }
1143
1144 rc = pthread_mutexattr_destroy(&attr);
1145 if (rc != 0) {
1146 pj_status_t status = PJ_RETURN_OS_ERROR(rc);
1147 pthread_mutex_destroy(&mutex->mutex);
1148 return status;
1149 }
1150
1151#if PJ_DEBUG
1152 /* Set owner. */
1153 mutex->nesting_level = 0;
1154 mutex->owner = NULL;
1155#endif
1156
1157 /* Set name. */
1158 if (!name) {
1159 name = "mtx%p";
1160 }
1161 if (strchr(name, '%')) {
1162 pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
1163 } else {
1164 strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
1165 mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1166 }
1167
1168 PJ_LOG(6, (mutex->obj_name, "Mutex created"));
1169 return PJ_SUCCESS;
1170#else /* PJ_HAS_THREADS */
1171 return PJ_SUCCESS;
1172#endif
1173}
1174
1175/*
1176 * pj_mutex_create()
1177 */
1178PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
1179 const char *name,
1180 int type,
1181 pj_mutex_t **ptr_mutex)
1182{
1183#if PJ_HAS_THREADS
1184 pj_status_t rc;
1185 pj_mutex_t *mutex;
1186
1187 PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
1188
1189 mutex = PJ_POOL_ALLOC_T(pool, pj_mutex_t);
1190 PJ_ASSERT_RETURN(mutex, PJ_ENOMEM);
1191
1192 if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
1193 return rc;
1194
1195 *ptr_mutex = mutex;
1196 return PJ_SUCCESS;
1197#else /* PJ_HAS_THREADS */
1198 *ptr_mutex = (pj_mutex_t*)1;
1199 return PJ_SUCCESS;
1200#endif
1201}
1202
1203/*
1204 * pj_mutex_create_simple()
1205 */
1206PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
1207 const char *name,
1208 pj_mutex_t **mutex )
1209{
1210 return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
1211}
1212
1213/*
1214 * pj_mutex_create_recursive()
1215 */
1216PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
1217 const char *name,
1218 pj_mutex_t **mutex )
1219{
1220 return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
1221}
1222
1223/*
1224 * pj_mutex_lock()
1225 */
1226PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
1227{
1228#if PJ_HAS_THREADS
1229 pj_status_t status;
1230
1231 PJ_CHECK_STACK();
1232 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1233
1234#if PJ_DEBUG
1235 PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting (mutex owner=%s)",
1236 pj_thread_this()->obj_name,
1237 mutex->owner_name));
1238#else
1239 PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting",
1240 pj_thread_this()->obj_name));
1241#endif
1242
1243 status = pthread_mutex_lock( &mutex->mutex );
1244
1245
1246#if PJ_DEBUG
1247 if (status == PJ_SUCCESS) {
1248 mutex->owner = pj_thread_this();
1249 pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name);
1250 ++mutex->nesting_level;
1251 }
1252
1253 PJ_LOG(6,(mutex->obj_name,
1254 (status==0 ?
1255 "Mutex acquired by thread %s (level=%d)" :
1256 "Mutex acquisition FAILED by %s (level=%d)"),
1257 pj_thread_this()->obj_name,
1258 mutex->nesting_level));
1259#else
1260 PJ_LOG(6,(mutex->obj_name,
1261 (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
1262 pj_thread_this()->obj_name));
1263#endif
1264
1265 if (status == 0)
1266 return PJ_SUCCESS;
1267 else
1268 return PJ_RETURN_OS_ERROR(status);
1269#else /* PJ_HAS_THREADS */
1270 pj_assert( mutex == (pj_mutex_t*)1 );
1271 return PJ_SUCCESS;
1272#endif
1273}
1274
1275/*
1276 * pj_mutex_unlock()
1277 */
1278PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
1279{
1280#if PJ_HAS_THREADS
1281 pj_status_t status;
1282
1283 PJ_CHECK_STACK();
1284 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1285
1286#if PJ_DEBUG
1287 pj_assert(mutex->owner == pj_thread_this());
1288 if (--mutex->nesting_level == 0) {
1289 mutex->owner = NULL;
1290 mutex->owner_name[0] = '\0';
1291 }
1292
1293 PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s (level=%d)",
1294 pj_thread_this()->obj_name,
1295 mutex->nesting_level));
1296#else
1297 PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s",
1298 pj_thread_this()->obj_name));
1299#endif
1300
1301 status = pthread_mutex_unlock( &mutex->mutex );
1302 if (status == 0)
1303 return PJ_SUCCESS;
1304 else
1305 return PJ_RETURN_OS_ERROR(status);
1306
1307#else /* PJ_HAS_THREADS */
1308 pj_assert( mutex == (pj_mutex_t*)1 );
1309 return PJ_SUCCESS;
1310#endif
1311}
1312
1313/*
1314 * pj_mutex_trylock()
1315 */
1316PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
1317{
1318#if PJ_HAS_THREADS
1319 int status;
1320
1321 PJ_CHECK_STACK();
1322 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1323
1324 PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is trying",
1325 pj_thread_this()->obj_name));
1326
1327 status = pthread_mutex_trylock( &mutex->mutex );
1328
1329 if (status==0) {
1330#if PJ_DEBUG
1331 mutex->owner = pj_thread_this();
1332 pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name);
1333 ++mutex->nesting_level;
1334
1335 PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s (level=%d)",
1336 pj_thread_this()->obj_name,
1337 mutex->nesting_level));
1338#else
1339 PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s",
1340 pj_thread_this()->obj_name));
1341#endif
1342 } else {
1343 PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s's trylock() failed",
1344 pj_thread_this()->obj_name));
1345 }
1346
1347 if (status==0)
1348 return PJ_SUCCESS;
1349 else
1350 return PJ_RETURN_OS_ERROR(status);
1351#else /* PJ_HAS_THREADS */
1352 pj_assert( mutex == (pj_mutex_t*)1);
1353 return PJ_SUCCESS;
1354#endif
1355}
1356
1357/*
1358 * pj_mutex_destroy()
1359 */
1360PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
1361{
1362 enum { RETRY = 4 };
1363 int status = 0;
1364 unsigned retry;
1365
1366 PJ_CHECK_STACK();
1367 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1368
1369#if PJ_HAS_THREADS
1370 PJ_LOG(6,(mutex->obj_name, "Mutex destroyed by thread %s",
1371 pj_thread_this()->obj_name));
1372
1373 for (retry=0; retry<RETRY; ++retry) {
1374 status = pthread_mutex_destroy( &mutex->mutex );
1375 if (status == PJ_SUCCESS)
1376 break;
1377 else if (retry<RETRY-1 && status == EBUSY)
1378 pthread_mutex_unlock(&mutex->mutex);
1379 }
1380
1381 if (status == 0)
1382 return PJ_SUCCESS;
1383 else {
1384 return PJ_RETURN_OS_ERROR(status);
1385 }
1386#else
1387 pj_assert( mutex == (pj_mutex_t*)1 );
1388 status = PJ_SUCCESS;
1389 return status;
1390#endif
1391}
1392
1393#if PJ_DEBUG
1394PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
1395{
1396#if PJ_HAS_THREADS
1397 return mutex->owner == pj_thread_this();
1398#else
1399 return 1;
1400#endif
1401}
1402#endif
1403
1404///////////////////////////////////////////////////////////////////////////////
1405/*
1406 * Include Read/Write mutex emulation for POSIX platforms that lack it (e.g.
1407 * RTEMS). Otherwise use POSIX rwlock.
1408 */
1409#if defined(PJ_EMULATE_RWMUTEX) && PJ_EMULATE_RWMUTEX!=0
1410 /* We need semaphore functionality to emulate rwmutex */
1411# if !defined(PJ_HAS_SEMAPHORE) || PJ_HAS_SEMAPHORE==0
1412# error "Semaphore support needs to be enabled to emulate rwmutex"
1413# endif
1414# include "os_rwmutex.c"
1415#else
1416struct pj_rwmutex_t
1417{
1418 pthread_rwlock_t rwlock;
1419};
1420
1421PJ_DEF(pj_status_t) pj_rwmutex_create(pj_pool_t *pool, const char *name,
1422 pj_rwmutex_t **p_mutex)
1423{
1424 pj_rwmutex_t *rwm;
1425 pj_status_t status;
1426
1427 PJ_UNUSED_ARG(name);
1428
1429 rwm = PJ_POOL_ALLOC_T(pool, pj_rwmutex_t);
1430 PJ_ASSERT_RETURN(rwm, PJ_ENOMEM);
1431
1432 status = pthread_rwlock_init(&rwm->rwlock, NULL);
1433 if (status != 0)
1434 return PJ_RETURN_OS_ERROR(status);
1435
1436 *p_mutex = rwm;
1437 return PJ_SUCCESS;
1438}
1439
1440/*
1441 * Lock the mutex for reading.
1442 *
1443 */
1444PJ_DEF(pj_status_t) pj_rwmutex_lock_read(pj_rwmutex_t *mutex)
1445{
1446 pj_status_t status;
1447
1448 status = pthread_rwlock_rdlock(&mutex->rwlock);
1449 if (status != 0)
1450 return PJ_RETURN_OS_ERROR(status);
1451
1452 return PJ_SUCCESS;
1453}
1454
1455/*
1456 * Lock the mutex for writing.
1457 *
1458 */
1459PJ_DEF(pj_status_t) pj_rwmutex_lock_write(pj_rwmutex_t *mutex)
1460{
1461 pj_status_t status;
1462
1463 status = pthread_rwlock_wrlock(&mutex->rwlock);
1464 if (status != 0)
1465 return PJ_RETURN_OS_ERROR(status);
1466
1467 return PJ_SUCCESS;
1468}
1469
1470/*
1471 * Release read lock.
1472 *
1473 */
1474PJ_DEF(pj_status_t) pj_rwmutex_unlock_read(pj_rwmutex_t *mutex)
1475{
1476 return pj_rwmutex_unlock_write(mutex);
1477}
1478
1479/*
1480 * Release write lock.
1481 *
1482 */
1483PJ_DEF(pj_status_t) pj_rwmutex_unlock_write(pj_rwmutex_t *mutex)
1484{
1485 pj_status_t status;
1486
1487 status = pthread_rwlock_unlock(&mutex->rwlock);
1488 if (status != 0)
1489 return PJ_RETURN_OS_ERROR(status);
1490
1491 return PJ_SUCCESS;
1492}
1493
1494/*
1495 * Destroy reader/writer mutex.
1496 *
1497 */
1498PJ_DEF(pj_status_t) pj_rwmutex_destroy(pj_rwmutex_t *mutex)
1499{
1500 pj_status_t status;
1501
1502 status = pthread_rwlock_destroy(&mutex->rwlock);
1503 if (status != 0)
1504 return PJ_RETURN_OS_ERROR(status);
1505
1506 return PJ_SUCCESS;
1507}
1508
1509#endif /* PJ_EMULATE_RWMUTEX */
1510
1511
1512///////////////////////////////////////////////////////////////////////////////
1513#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
1514
1515/*
1516 * pj_sem_create()
1517 */
1518PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
1519 const char *name,
1520 unsigned initial,
1521 unsigned max,
1522 pj_sem_t **ptr_sem)
1523{
1524#if PJ_HAS_THREADS
1525 pj_sem_t *sem;
1526
1527 PJ_CHECK_STACK();
1528 PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
1529
1530 sem = PJ_POOL_ALLOC_T(pool, pj_sem_t);
1531 PJ_ASSERT_RETURN(sem, PJ_ENOMEM);
1532
1533#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
1534 /* MacOS X doesn't support anonymous semaphore */
1535 {
1536 char sem_name[PJ_GUID_MAX_LENGTH+1];
1537 pj_str_t nam;
1538
1539 /* We should use SEM_NAME_LEN, but this doesn't seem to be
1540 * declared anywhere? The value here is just from trial and error
1541 * to get the longest name supported.
1542 */
1543# define MAX_SEM_NAME_LEN 23
1544
1545 /* Create a unique name for the semaphore. */
1546 if (PJ_GUID_STRING_LENGTH <= MAX_SEM_NAME_LEN) {
1547 nam.ptr = sem_name;
1548 pj_generate_unique_string(&nam);
1549 sem_name[nam.slen] = '\0';
1550 } else {
1551 pj_create_random_string(sem_name, MAX_SEM_NAME_LEN);
1552 sem_name[MAX_SEM_NAME_LEN] = '\0';
1553 }
1554
1555 /* Create semaphore */
1556 sem->sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR,
1557 initial);
1558 if (sem->sem == SEM_FAILED)
1559 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1560
1561 /* And immediately release the name as we don't need it */
1562 sem_unlink(sem_name);
1563 }
1564#else
1565 sem->sem = PJ_POOL_ALLOC_T(pool, sem_t);
1566 if (sem_init( sem->sem, 0, initial) != 0)
1567 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1568#endif
1569
1570 /* Set name. */
1571 if (!name) {
1572 name = "sem%p";
1573 }
1574 if (strchr(name, '%')) {
1575 pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
1576 } else {
1577 strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
1578 sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1579 }
1580
1581 PJ_LOG(6, (sem->obj_name, "Semaphore created"));
1582
1583 *ptr_sem = sem;
1584 return PJ_SUCCESS;
1585#else
1586 *ptr_sem = (pj_sem_t*)1;
1587 return PJ_SUCCESS;
1588#endif
1589}
1590
1591/*
1592 * pj_sem_wait()
1593 */
1594PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
1595{
1596#if PJ_HAS_THREADS
1597 int result;
1598
1599 PJ_CHECK_STACK();
1600 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1601
1602 PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting",
1603 pj_thread_this()->obj_name));
1604
1605 result = sem_wait( sem->sem );
1606
1607 if (result == 0) {
1608 PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
1609 pj_thread_this()->obj_name));
1610 } else {
1611 PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire",
1612 pj_thread_this()->obj_name));
1613 }
1614
1615 if (result == 0)
1616 return PJ_SUCCESS;
1617 else
1618 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1619#else
1620 pj_assert( sem == (pj_sem_t*) 1 );
1621 return PJ_SUCCESS;
1622#endif
1623}
1624
1625/*
1626 * pj_sem_trywait()
1627 */
1628PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
1629{
1630#if PJ_HAS_THREADS
1631 int result;
1632
1633 PJ_CHECK_STACK();
1634 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1635
1636 result = sem_trywait( sem->sem );
1637
1638 if (result == 0) {
1639 PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
1640 pj_thread_this()->obj_name));
1641 }
1642 if (result == 0)
1643 return PJ_SUCCESS;
1644 else
1645 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1646#else
1647 pj_assert( sem == (pj_sem_t*)1 );
1648 return PJ_SUCCESS;
1649#endif
1650}
1651
1652/*
1653 * pj_sem_post()
1654 */
1655PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
1656{
1657#if PJ_HAS_THREADS
1658 int result;
1659 PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
1660 pj_thread_this()->obj_name));
1661 result = sem_post( sem->sem );
1662
1663 if (result == 0)
1664 return PJ_SUCCESS;
1665 else
1666 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1667#else
1668 pj_assert( sem == (pj_sem_t*) 1);
1669 return PJ_SUCCESS;
1670#endif
1671}
1672
1673/*
1674 * pj_sem_destroy()
1675 */
1676PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
1677{
1678#if PJ_HAS_THREADS
1679 int result;
1680
1681 PJ_CHECK_STACK();
1682 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1683
1684 PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
1685 pj_thread_this()->obj_name));
1686#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
1687 result = sem_close( sem->sem );
1688#else
1689 result = sem_destroy( sem->sem );
1690#endif
1691
1692 if (result == 0)
1693 return PJ_SUCCESS;
1694 else
1695 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1696#else
1697 pj_assert( sem == (pj_sem_t*) 1 );
1698 return PJ_SUCCESS;
1699#endif
1700}
1701
1702#endif /* PJ_HAS_SEMAPHORE */
1703
1704///////////////////////////////////////////////////////////////////////////////
1705#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
1706
1707/*
1708 * pj_event_create()
1709 */
1710PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
1711 pj_bool_t manual_reset, pj_bool_t initial,
1712 pj_event_t **ptr_event)
1713{
1714 pj_event_t *event;
1715
1716 event = PJ_POOL_ALLOC_T(pool, pj_event_t);
1717
1718 init_mutex(&event->mutex, name, PJ_MUTEX_SIMPLE);
1719 pthread_cond_init(&event->cond, 0);
1720 event->auto_reset = !manual_reset;
1721 event->threads_waiting = 0;
1722
1723 if (initial) {
1724 event->state = EV_STATE_SET;
1725 event->threads_to_release = 1;
1726 } else {
1727 event->state = EV_STATE_OFF;
1728 event->threads_to_release = 0;
1729 }
1730
1731 *ptr_event = event;
1732 return PJ_SUCCESS;
1733}
1734
1735static void event_on_one_release(pj_event_t *event)
1736{
1737 if (event->state == EV_STATE_SET) {
1738 if (event->auto_reset) {
1739 event->threads_to_release = 0;
1740 event->state = EV_STATE_OFF;
1741 } else {
1742 /* Manual reset remains on */
1743 }
1744 } else {
1745 if (event->auto_reset) {
1746 /* Only release one */
1747 event->threads_to_release = 0;
1748 event->state = EV_STATE_OFF;
1749 } else {
1750 event->threads_to_release--;
1751 pj_assert(event->threads_to_release >= 0);
1752 if (event->threads_to_release==0)
1753 event->state = EV_STATE_OFF;
1754 }
1755 }
1756}
1757
1758/*
1759 * pj_event_wait()
1760 */
1761PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
1762{
1763 pthread_mutex_lock(&event->mutex.mutex);
1764 event->threads_waiting++;
1765 while (event->state == EV_STATE_OFF)
1766 pthread_cond_wait(&event->cond, &event->mutex.mutex);
1767 event->threads_waiting--;
1768 event_on_one_release(event);
1769 pthread_mutex_unlock(&event->mutex.mutex);
1770 return PJ_SUCCESS;
1771}
1772
1773/*
1774 * pj_event_trywait()
1775 */
1776PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
1777{
1778 pj_status_t status;
1779
1780 pthread_mutex_lock(&event->mutex.mutex);
1781 status = event->state != EV_STATE_OFF ? PJ_SUCCESS : -1;
1782 if (status==PJ_SUCCESS) {
1783 event_on_one_release(event);
1784 }
1785 pthread_mutex_unlock(&event->mutex.mutex);
1786
1787 return status;
1788}
1789
1790/*
1791 * pj_event_set()
1792 */
1793PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
1794{
1795 pthread_mutex_lock(&event->mutex.mutex);
1796 event->threads_to_release = 1;
1797 event->state = EV_STATE_SET;
1798 if (event->auto_reset)
1799 pthread_cond_signal(&event->cond);
1800 else
1801 pthread_cond_broadcast(&event->cond);
1802 pthread_mutex_unlock(&event->mutex.mutex);
1803 return PJ_SUCCESS;
1804}
1805
1806/*
1807 * pj_event_pulse()
1808 */
1809PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
1810{
1811 pthread_mutex_lock(&event->mutex.mutex);
1812 if (event->threads_waiting) {
1813 event->threads_to_release = event->auto_reset ? 1 :
1814 event->threads_waiting;
1815 event->state = EV_STATE_PULSED;
1816 if (event->threads_to_release==1)
1817 pthread_cond_signal(&event->cond);
1818 else
1819 pthread_cond_broadcast(&event->cond);
1820 }
1821 pthread_mutex_unlock(&event->mutex.mutex);
1822 return PJ_SUCCESS;
1823}
1824
1825/*
1826 * pj_event_reset()
1827 */
1828PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
1829{
1830 pthread_mutex_lock(&event->mutex.mutex);
1831 event->state = EV_STATE_OFF;
1832 event->threads_to_release = 0;
1833 pthread_mutex_unlock(&event->mutex.mutex);
1834 return PJ_SUCCESS;
1835}
1836
1837/*
1838 * pj_event_destroy()
1839 */
1840PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
1841{
1842 pj_mutex_destroy(&event->mutex);
1843 pthread_cond_destroy(&event->cond);
1844 return PJ_SUCCESS;
1845}
1846
1847#endif /* PJ_HAS_EVENT_OBJ */
1848
1849///////////////////////////////////////////////////////////////////////////////
1850#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
1851/*
1852 * Terminal
1853 */
1854
1855/**
1856 * Set terminal color.
1857 */
1858PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
1859{
1860 /* put bright prefix to ansi_color */
1861 char ansi_color[12] = "\033[01;3";
1862
1863 if (color & PJ_TERM_COLOR_BRIGHT) {
1864 color ^= PJ_TERM_COLOR_BRIGHT;
1865 } else {
1866 strcpy(ansi_color, "\033[00;3");
1867 }
1868
1869 switch (color) {
1870 case 0:
1871 /* black color */
1872 strcat(ansi_color, "0m");
1873 break;
1874 case PJ_TERM_COLOR_R:
1875 /* red color */
1876 strcat(ansi_color, "1m");
1877 break;
1878 case PJ_TERM_COLOR_G:
1879 /* green color */
1880 strcat(ansi_color, "2m");
1881 break;
1882 case PJ_TERM_COLOR_B:
1883 /* blue color */
1884 strcat(ansi_color, "4m");
1885 break;
1886 case PJ_TERM_COLOR_R | PJ_TERM_COLOR_G:
1887 /* yellow color */
1888 strcat(ansi_color, "3m");
1889 break;
1890 case PJ_TERM_COLOR_R | PJ_TERM_COLOR_B:
1891 /* magenta color */
1892 strcat(ansi_color, "5m");
1893 break;
1894 case PJ_TERM_COLOR_G | PJ_TERM_COLOR_B:
1895 /* cyan color */
1896 strcat(ansi_color, "6m");
1897 break;
1898 case PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B:
1899 /* white color */
1900 strcat(ansi_color, "7m");
1901 break;
1902 default:
1903 /* default console color */
1904 strcpy(ansi_color, "\033[00m");
1905 break;
1906 }
1907
1908 fputs(ansi_color, stdout);
1909
1910 return PJ_SUCCESS;
1911}
1912
1913/**
1914 * Get current terminal foreground color.
1915 */
1916PJ_DEF(pj_color_t) pj_term_get_color(void)
1917{
1918 return 0;
1919}
1920
1921#endif /* PJ_TERM_HAS_COLOR */
1922
1923#if !defined(PJ_DARWINOS) || PJ_DARWINOS == 0
1924/*
1925 * pj_run_app()
1926 */
1927PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
1928 unsigned flags)
1929{
1930 return (*main_func)(argc, argv);
1931}
1932#endif