1
/* $Id: os_core_unix.c 4359 2013-02-21 11:18:36Z bennylp $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
22
* - Thanks for Zetron, Inc. (Phil Torre, ptorre@zetron.com) for donating
29
#include <pj/assert.h>
33
#include <pj/string.h>
35
#include <pj/except.h>
38
#if defined(PJ_HAS_SEMAPHORE_H) && PJ_HAS_SEMAPHORE_H != 0
39
# include <semaphore.h>
42
#include <unistd.h> // getpid()
43
#include <errno.h> // errno
47
#define THIS_FILE "os_core_unix.c"
49
#define SIGNATURE1 0xDEAFBEEF
50
#define SIGNATURE2 0xDEADC0DE
54
char obj_name[PJ_MAX_OBJ_NAME];
58
pj_uint32_t signature1;
59
pj_uint32_t signature2;
61
pj_mutex_t *suspended_mutex;
63
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
65
pj_uint32_t stk_max_usage;
67
const char *caller_file;
75
pj_atomic_value_t value;
80
pthread_mutex_t mutex;
81
char obj_name[PJ_MAX_OBJ_NAME];
85
char owner_name[PJ_MAX_OBJ_NAME];
89
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
93
char obj_name[PJ_MAX_OBJ_NAME];
95
#endif /* PJ_HAS_SEMAPHORE */
97
#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
109
pj_bool_t auto_reset;
110
unsigned threads_waiting;
111
unsigned threads_to_release;
113
#endif /* PJ_HAS_EVENT_OBJ */
117
* Flag and reference counter for PJLIB instance.
119
static int initialized;
122
static pj_thread_t main_thread;
123
static long thread_tls_id;
124
static pj_mutex_t critical_section;
126
# define MAX_THREADS 32
127
static int tls_flag[MAX_THREADS];
128
static void *tls[MAX_THREADS];
131
static unsigned atexit_count;
132
static void (*atexit_func[32])(void);
134
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
140
PJ_DEF(pj_status_t) pj_init(void)
142
char dummy_guid[PJ_GUID_MAX_LENGTH];
146
/* Check if PJLIB have been initialized */
153
/* Init this thread's TLS. */
154
if ((rc=pj_thread_init()) != 0) {
158
/* Critical section. */
159
if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_RECURSE)) != 0)
167
/* Initialize exception ID for the pool.
168
* Must do so after critical section is configured.
170
rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
171
if (rc != PJ_SUCCESS)
174
/* Init random seed. */
175
/* Or probably not. Let application in charge of this */
176
/* pj_srand( clock() ); */
179
guid.ptr = dummy_guid;
180
pj_generate_unique_string( &guid );
182
/* Startup timestamp */
183
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
185
pj_timestamp dummy_ts;
186
if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
192
/* Flag PJLIB as initialized */
194
pj_assert(initialized == 1);
196
PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
205
PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
207
if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
210
atexit_func[atexit_count++] = func;
217
PJ_DEF(void) pj_shutdown()
221
/* Only perform shutdown operation when 'initialized' reaches zero */
222
pj_assert(initialized > 0);
223
if (--initialized != 0)
226
/* Call atexit() functions */
227
for (i=atexit_count-1; i>=0; --i) {
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;
239
/* Destroy PJLIB critical section */
240
pj_mutex_destroy(&critical_section);
243
if (thread_tls_id != -1) {
244
pj_thread_local_free(thread_tls_id);
248
/* Ticket #1132: Assertion when (re)starting PJLIB on different thread */
249
pj_bzero(&main_thread, sizeof(main_thread));
252
/* Clear static variables */
253
pj_errno_clear_handlers();
260
PJ_DEF(pj_uint32_t) pj_getpid(void)
267
* Check if this thread has been registered to PJLIB.
269
PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
272
return pj_thread_local_get(thread_tls_id) != 0;
274
pj_assert("pj_thread_is_registered() called in non-threading mode!");
281
* Get thread priority value for the thread.
283
PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
286
struct sched_param param;
290
rc = pthread_getschedparam (thread->thread, &policy, ¶m);
294
return param.sched_priority;
296
PJ_UNUSED_ARG(thread);
303
* Set the thread priority.
305
PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread, int prio)
308
struct sched_param param;
312
rc = pthread_getschedparam (thread->thread, &policy, ¶m);
314
return PJ_RETURN_OS_ERROR(rc);
316
param.sched_priority = prio;
318
rc = pthread_setschedparam(thread->thread, policy, ¶m);
320
return PJ_RETURN_OS_ERROR(rc);
324
PJ_UNUSED_ARG(thread);
326
pj_assert("pj_thread_set_prio() called in non-threading mode!");
333
* Get the lowest priority value available on this system.
335
PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
337
struct sched_param param;
341
rc = pthread_getschedparam(thread->thread, &policy, ¶m);
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 */
351
pj_assert("pj_thread_get_prio_min() not supported!");
358
* Get the highest priority value available on this system.
360
PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
362
struct sched_param param;
366
rc = pthread_getschedparam(thread->thread, &policy, ¶m);
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 */
376
pj_assert("pj_thread_get_prio_max() not supported!");
383
* Get native thread handle
385
PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread)
387
PJ_ASSERT_RETURN(thread, NULL);
390
return &thread->thread;
392
pj_assert("pj_thread_is_registered() called in non-threading mode!");
398
* pj_thread_register(..)
400
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
402
pj_thread_t **ptr_thread)
407
pj_thread_t *thread = (pj_thread_t *)desc;
408
pj_str_t thread_name = pj_str((char*)cstr_thread_name);
410
/* Size sanity check. */
411
if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
412
pj_assert(!"Not enough pj_thread_desc size!");
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);
425
PJ_LOG(4,(THIS_FILE, "Info: possibly re-registering existing "
429
/* On the other hand, also warn if the thread descriptor buffer seem to
430
* have been used to register other threads.
432
pj_assert(thread->signature1 != SIGNATURE1 ||
433
thread->signature2 != SIGNATURE2 ||
434
(thread->thread == pthread_self()));
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;
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);
446
pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
447
"thr%p", (void*)thread->thread);
449
rc = pj_thread_local_set(thread_tls_id, thread);
450
if (rc != PJ_SUCCESS) {
451
pj_bzero(desc, sizeof(struct pj_thread_t));
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;
463
*ptr_thread = thread;
466
pj_thread_t *thread = (pj_thread_t*)desc;
467
*ptr_thread = thread;
473
* pj_thread_init(void)
475
pj_status_t pj_thread_init(void)
481
rc = pj_thread_local_alloc(&thread_tls_id );
482
if (rc != PJ_SUCCESS) {
485
return pj_thread_register("thr%p", (long*)&main_thread, &dummy);
487
PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
488
return PJ_EINVALIDOP;
496
* This is the main entry for all threads.
498
static void *thread_main(void *param)
500
pj_thread_t *rec = (pj_thread_t*)param;
504
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
505
rec->stk_start = (char*)&rec;
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?)");
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);
520
PJ_LOG(6,(rec->obj_name, "Thread started"));
522
/* Call user's entry! */
523
result = (void*)(long)(*rec->proc)(rec->arg);
526
PJ_LOG(6,(rec->obj_name, "Thread quitting"));
533
* pj_thread_create(...)
535
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
536
const char *thread_name,
537
pj_thread_proc *proc,
539
pj_size_t stack_size,
541
pj_thread_t **ptr_thread)
545
pthread_attr_t thread_attr;
549
PJ_UNUSED_ARG(stack_addr);
552
PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
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);
560
thread_name = "thr%p";
562
if (strchr(thread_name, '%')) {
563
pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
565
strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
566
rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
569
/* Set default stack size */
571
stack_size = PJ_THREAD_DEFAULT_STACK_SIZE;
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;
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) {
585
pj_mutex_lock(rec->suspended_mutex);
587
pj_assert(rec->suspended_mutex == NULL);
591
/* Init thread attributes */
592
pthread_attr_init(&thread_attr);
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);
598
return PJ_RETURN_OS_ERROR(rc);
599
#endif /* PJ_THREAD_SET_STACK_SIZE */
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);
607
rc = pthread_attr_setstackaddr(&thread_attr, stack_addr);
609
return PJ_RETURN_OS_ERROR(rc);
610
#endif /* PJ_THREAD_ALLOCATE_STACK */
613
/* Create the thread. */
616
rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec);
618
return PJ_RETURN_OS_ERROR(rc);
623
PJ_LOG(6, (rec->obj_name, "Thread created"));
626
pj_assert(!"Threading is disabled!");
627
return PJ_EINVALIDOP;
632
* pj_thread-get_name()
634
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
637
pj_thread_t *rec = (pj_thread_t*)p;
640
PJ_ASSERT_RETURN(p, "");
642
return rec->obj_name;
651
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
656
PJ_ASSERT_RETURN(p, PJ_EINVAL);
658
rc = pj_mutex_unlock(p->suspended_mutex);
666
PJ_DEF(pj_thread_t*) pj_thread_this(void)
669
pj_thread_t *rec = (pj_thread_t*)pj_thread_local_get(thread_tls_id);
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.");
678
* MUST NOT check stack because this function is called
679
* by PJ_CHECK_STACK() itself!!!
685
pj_assert(!"Threading is not enabled!");
693
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
696
pj_thread_t *rec = (pj_thread_t *)p;
702
PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
703
result = pthread_join( rec->thread, &ret);
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>.
712
return result==ESRCH ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(result);
716
pj_assert(!"No multithreading support!");
717
return PJ_EINVALIDOP;
722
* pj_thread_destroy()
724
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
728
/* Destroy mutex used to suspend thread */
729
if (p->suspended_mutex) {
730
pj_mutex_destroy(p->suspended_mutex);
731
p->suspended_mutex = NULL;
740
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
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 };
748
req.tv_sec = msec / 1000;
749
req.tv_nsec = (msec % 1000) * NANOSEC_PER_MSEC;
751
if (nanosleep(&req, NULL) == 0)
754
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
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).
769
* As a workaround, here we check if ETIMEDOUT is returned and
770
* return successfully if it is.
772
if (pj_get_native_os_error() == ETIMEDOUT)
775
return pj_get_os_error();
777
#endif /* PJ_RTEMS */
780
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
782
* pj_thread_check_stack()
783
* Implementation for PJ_CHECK_STACK()
785
PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
789
pj_thread_t *thread = pj_thread_this();
791
/* Calculate current usage. */
792
usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
793
thread->stk_start - &stk_ptr;
795
/* Assert if stack usage is dangerously high. */
796
pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
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;
807
* pj_thread_get_stack_max_usage()
809
PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
811
return thread->stk_max_usage;
815
* pj_thread_get_stack_info()
817
PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
823
*file = thread->caller_file;
824
*line = thread->caller_line;
828
#endif /* PJ_OS_HAS_CHECK_STACK */
830
///////////////////////////////////////////////////////////////////////////////
834
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
835
pj_atomic_value_t initial,
836
pj_atomic_t **ptr_atomic)
839
pj_atomic_t *atomic_var;
841
atomic_var = PJ_POOL_ZALLOC_T(pool, pj_atomic_t);
843
PJ_ASSERT_RETURN(atomic_var, PJ_ENOMEM);
846
rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
847
if (rc != PJ_SUCCESS)
850
atomic_var->value = initial;
852
*ptr_atomic = atomic_var;
857
* pj_atomic_destroy()
859
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
861
PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
863
return pj_mutex_destroy( atomic_var->mutex );
872
PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
877
pj_mutex_lock( atomic_var->mutex );
879
atomic_var->value = value;
881
pj_mutex_unlock( atomic_var->mutex);
888
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
890
pj_atomic_value_t oldval;
895
pj_mutex_lock( atomic_var->mutex );
897
oldval = atomic_var->value;
899
pj_mutex_unlock( atomic_var->mutex);
905
* pj_atomic_inc_and_get()
907
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
909
pj_atomic_value_t new_value;
914
pj_mutex_lock( atomic_var->mutex );
916
new_value = ++atomic_var->value;
918
pj_mutex_unlock( atomic_var->mutex);
926
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
928
pj_atomic_inc_and_get(atomic_var);
932
* pj_atomic_dec_and_get()
934
PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
936
pj_atomic_value_t new_value;
941
pj_mutex_lock( atomic_var->mutex );
943
new_value = --atomic_var->value;
945
pj_mutex_unlock( atomic_var->mutex);
954
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
956
pj_atomic_dec_and_get(atomic_var);
960
* pj_atomic_add_and_get()
962
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
963
pj_atomic_value_t value )
965
pj_atomic_value_t new_value;
968
pj_mutex_lock(atomic_var->mutex);
971
atomic_var->value += value;
972
new_value = atomic_var->value;
975
pj_mutex_unlock(atomic_var->mutex);
984
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
985
pj_atomic_value_t value )
987
pj_atomic_add_and_get(atomic_var, value);
990
///////////////////////////////////////////////////////////////////////////////
992
* pj_thread_local_alloc()
994
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
1000
PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
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);
1010
for (i=0; i<MAX_THREADS; ++i) {
1011
if (tls_flag[i] == 0)
1014
if (i == MAX_THREADS)
1026
* pj_thread_local_free()
1028
PJ_DEF(void) pj_thread_local_free(long index)
1032
pthread_key_delete(index);
1034
tls_flag[index] = 0;
1039
* pj_thread_local_set()
1041
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
1043
//Can't check stack because this function is called in the
1044
//beginning before main thread is initialized.
1047
int rc=pthread_setspecific(index, value);
1048
return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
1050
pj_assert(index >= 0 && index < MAX_THREADS);
1056
PJ_DEF(void*) pj_thread_local_get(long index)
1058
//Can't check stack because this function is called
1059
//by PJ_CHECK_STACK() itself!!!
1062
return pthread_getspecific(index);
1064
pj_assert(index >= 0 && index < MAX_THREADS);
1069
///////////////////////////////////////////////////////////////////////////////
1070
PJ_DEF(void) pj_enter_critical_section(void)
1073
pj_mutex_lock(&critical_section);
1077
PJ_DEF(void) pj_leave_critical_section(void)
1080
pj_mutex_unlock(&critical_section);
1085
///////////////////////////////////////////////////////////////////////////////
1086
#if defined(PJ_LINUX) && PJ_LINUX!=0
1088
PJ_DECL(int) pthread_mutexattr_settype(pthread_mutexattr_t*,int);
1092
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
1095
pthread_mutexattr_t attr;
1100
rc = pthread_mutexattr_init(&attr);
1102
return PJ_RETURN_OS_ERROR(rc);
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 */
1112
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
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.
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)
1131
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1136
return PJ_RETURN_OS_ERROR(rc);
1139
rc = pthread_mutex_init(&mutex->mutex, &attr);
1141
return PJ_RETURN_OS_ERROR(rc);
1144
rc = pthread_mutexattr_destroy(&attr);
1146
pj_status_t status = PJ_RETURN_OS_ERROR(rc);
1147
pthread_mutex_destroy(&mutex->mutex);
1153
mutex->nesting_level = 0;
1154
mutex->owner = NULL;
1161
if (strchr(name, '%')) {
1162
pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
1164
strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
1165
mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1168
PJ_LOG(6, (mutex->obj_name, "Mutex created"));
1170
#else /* PJ_HAS_THREADS */
1178
PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
1181
pj_mutex_t **ptr_mutex)
1187
PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
1189
mutex = PJ_POOL_ALLOC_T(pool, pj_mutex_t);
1190
PJ_ASSERT_RETURN(mutex, PJ_ENOMEM);
1192
if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
1197
#else /* PJ_HAS_THREADS */
1198
*ptr_mutex = (pj_mutex_t*)1;
1204
* pj_mutex_create_simple()
1206
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
1208
pj_mutex_t **mutex )
1210
return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
1214
* pj_mutex_create_recursive()
1216
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
1218
pj_mutex_t **mutex )
1220
return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
1226
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
1232
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
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));
1239
PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting",
1240
pj_thread_this()->obj_name));
1243
status = pthread_mutex_lock( &mutex->mutex );
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;
1253
PJ_LOG(6,(mutex->obj_name,
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));
1260
PJ_LOG(6,(mutex->obj_name,
1261
(status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
1262
pj_thread_this()->obj_name));
1268
return PJ_RETURN_OS_ERROR(status);
1269
#else /* PJ_HAS_THREADS */
1270
pj_assert( mutex == (pj_mutex_t*)1 );
1278
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
1284
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1287
pj_assert(mutex->owner == pj_thread_this());
1288
if (--mutex->nesting_level == 0) {
1289
mutex->owner = NULL;
1290
mutex->owner_name[0] = '\0';
1293
PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s (level=%d)",
1294
pj_thread_this()->obj_name,
1295
mutex->nesting_level));
1297
PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s",
1298
pj_thread_this()->obj_name));
1301
status = pthread_mutex_unlock( &mutex->mutex );
1305
return PJ_RETURN_OS_ERROR(status);
1307
#else /* PJ_HAS_THREADS */
1308
pj_assert( mutex == (pj_mutex_t*)1 );
1314
* pj_mutex_trylock()
1316
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
1322
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1324
PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is trying",
1325
pj_thread_this()->obj_name));
1327
status = pthread_mutex_trylock( &mutex->mutex );
1331
mutex->owner = pj_thread_this();
1332
pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name);
1333
++mutex->nesting_level;
1335
PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s (level=%d)",
1336
pj_thread_this()->obj_name,
1337
mutex->nesting_level));
1339
PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s",
1340
pj_thread_this()->obj_name));
1343
PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s's trylock() failed",
1344
pj_thread_this()->obj_name));
1350
return PJ_RETURN_OS_ERROR(status);
1351
#else /* PJ_HAS_THREADS */
1352
pj_assert( mutex == (pj_mutex_t*)1);
1358
* pj_mutex_destroy()
1360
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
1367
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1370
PJ_LOG(6,(mutex->obj_name, "Mutex destroyed by thread %s",
1371
pj_thread_this()->obj_name));
1373
for (retry=0; retry<RETRY; ++retry) {
1374
status = pthread_mutex_destroy( &mutex->mutex );
1375
if (status == PJ_SUCCESS)
1377
else if (retry<RETRY-1 && status == EBUSY)
1378
pthread_mutex_unlock(&mutex->mutex);
1384
return PJ_RETURN_OS_ERROR(status);
1387
pj_assert( mutex == (pj_mutex_t*)1 );
1388
status = PJ_SUCCESS;
1394
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
1397
return mutex->owner == pj_thread_this();
1404
///////////////////////////////////////////////////////////////////////////////
1406
* Include Read/Write mutex emulation for POSIX platforms that lack it (e.g.
1407
* RTEMS). Otherwise use POSIX rwlock.
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"
1414
# include "os_rwmutex.c"
1418
pthread_rwlock_t rwlock;
1421
PJ_DEF(pj_status_t) pj_rwmutex_create(pj_pool_t *pool, const char *name,
1422
pj_rwmutex_t **p_mutex)
1427
PJ_UNUSED_ARG(name);
1429
rwm = PJ_POOL_ALLOC_T(pool, pj_rwmutex_t);
1430
PJ_ASSERT_RETURN(rwm, PJ_ENOMEM);
1432
status = pthread_rwlock_init(&rwm->rwlock, NULL);
1434
return PJ_RETURN_OS_ERROR(status);
1441
* Lock the mutex for reading.
1444
PJ_DEF(pj_status_t) pj_rwmutex_lock_read(pj_rwmutex_t *mutex)
1448
status = pthread_rwlock_rdlock(&mutex->rwlock);
1450
return PJ_RETURN_OS_ERROR(status);
1456
* Lock the mutex for writing.
1459
PJ_DEF(pj_status_t) pj_rwmutex_lock_write(pj_rwmutex_t *mutex)
1463
status = pthread_rwlock_wrlock(&mutex->rwlock);
1465
return PJ_RETURN_OS_ERROR(status);
1471
* Release read lock.
1474
PJ_DEF(pj_status_t) pj_rwmutex_unlock_read(pj_rwmutex_t *mutex)
1476
return pj_rwmutex_unlock_write(mutex);
1480
* Release write lock.
1483
PJ_DEF(pj_status_t) pj_rwmutex_unlock_write(pj_rwmutex_t *mutex)
1487
status = pthread_rwlock_unlock(&mutex->rwlock);
1489
return PJ_RETURN_OS_ERROR(status);
1495
* Destroy reader/writer mutex.
1498
PJ_DEF(pj_status_t) pj_rwmutex_destroy(pj_rwmutex_t *mutex)
1502
status = pthread_rwlock_destroy(&mutex->rwlock);
1504
return PJ_RETURN_OS_ERROR(status);
1509
#endif /* PJ_EMULATE_RWMUTEX */
1512
///////////////////////////////////////////////////////////////////////////////
1513
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
1518
PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
1528
PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
1530
sem = PJ_POOL_ALLOC_T(pool, pj_sem_t);
1531
PJ_ASSERT_RETURN(sem, PJ_ENOMEM);
1533
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
1534
/* MacOS X doesn't support anonymous semaphore */
1536
char sem_name[PJ_GUID_MAX_LENGTH+1];
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.
1543
# define MAX_SEM_NAME_LEN 23
1545
/* Create a unique name for the semaphore. */
1546
if (PJ_GUID_STRING_LENGTH <= MAX_SEM_NAME_LEN) {
1548
pj_generate_unique_string(&nam);
1549
sem_name[nam.slen] = '\0';
1551
pj_create_random_string(sem_name, MAX_SEM_NAME_LEN);
1552
sem_name[MAX_SEM_NAME_LEN] = '\0';
1555
/* Create semaphore */
1556
sem->sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR,
1558
if (sem->sem == SEM_FAILED)
1559
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1561
/* And immediately release the name as we don't need it */
1562
sem_unlink(sem_name);
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());
1574
if (strchr(name, '%')) {
1575
pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
1577
strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
1578
sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1581
PJ_LOG(6, (sem->obj_name, "Semaphore created"));
1586
*ptr_sem = (pj_sem_t*)1;
1594
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
1600
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1602
PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting",
1603
pj_thread_this()->obj_name));
1605
result = sem_wait( sem->sem );
1608
PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
1609
pj_thread_this()->obj_name));
1611
PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire",
1612
pj_thread_this()->obj_name));
1618
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1620
pj_assert( sem == (pj_sem_t*) 1 );
1628
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
1634
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1636
result = sem_trywait( sem->sem );
1639
PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s",
1640
pj_thread_this()->obj_name));
1645
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1647
pj_assert( sem == (pj_sem_t*)1 );
1655
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
1659
PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
1660
pj_thread_this()->obj_name));
1661
result = sem_post( sem->sem );
1666
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1668
pj_assert( sem == (pj_sem_t*) 1);
1676
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
1682
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
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 );
1689
result = sem_destroy( sem->sem );
1695
return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
1697
pj_assert( sem == (pj_sem_t*) 1 );
1702
#endif /* PJ_HAS_SEMAPHORE */
1704
///////////////////////////////////////////////////////////////////////////////
1705
#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
1710
PJ_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)
1716
event = PJ_POOL_ALLOC_T(pool, pj_event_t);
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;
1724
event->state = EV_STATE_SET;
1725
event->threads_to_release = 1;
1727
event->state = EV_STATE_OFF;
1728
event->threads_to_release = 0;
1735
static void event_on_one_release(pj_event_t *event)
1737
if (event->state == EV_STATE_SET) {
1738
if (event->auto_reset) {
1739
event->threads_to_release = 0;
1740
event->state = EV_STATE_OFF;
1742
/* Manual reset remains on */
1745
if (event->auto_reset) {
1746
/* Only release one */
1747
event->threads_to_release = 0;
1748
event->state = EV_STATE_OFF;
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;
1761
PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
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);
1774
* pj_event_trywait()
1776
PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
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);
1785
pthread_mutex_unlock(&event->mutex.mutex);
1793
PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
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);
1801
pthread_cond_broadcast(&event->cond);
1802
pthread_mutex_unlock(&event->mutex.mutex);
1809
PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
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);
1819
pthread_cond_broadcast(&event->cond);
1821
pthread_mutex_unlock(&event->mutex.mutex);
1828
PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
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);
1838
* pj_event_destroy()
1840
PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
1842
pj_mutex_destroy(&event->mutex);
1843
pthread_cond_destroy(&event->cond);
1847
#endif /* PJ_HAS_EVENT_OBJ */
1849
///////////////////////////////////////////////////////////////////////////////
1850
#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
1856
* Set terminal color.
1858
PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
1860
/* put bright prefix to ansi_color */
1861
char ansi_color[12] = "\033[01;3";
1863
if (color & PJ_TERM_COLOR_BRIGHT) {
1864
color ^= PJ_TERM_COLOR_BRIGHT;
1866
strcpy(ansi_color, "\033[00;3");
1872
strcat(ansi_color, "0m");
1874
case PJ_TERM_COLOR_R:
1876
strcat(ansi_color, "1m");
1878
case PJ_TERM_COLOR_G:
1880
strcat(ansi_color, "2m");
1882
case PJ_TERM_COLOR_B:
1884
strcat(ansi_color, "4m");
1886
case PJ_TERM_COLOR_R | PJ_TERM_COLOR_G:
1888
strcat(ansi_color, "3m");
1890
case PJ_TERM_COLOR_R | PJ_TERM_COLOR_B:
1892
strcat(ansi_color, "5m");
1894
case PJ_TERM_COLOR_G | PJ_TERM_COLOR_B:
1896
strcat(ansi_color, "6m");
1898
case PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B:
1900
strcat(ansi_color, "7m");
1903
/* default console color */
1904
strcpy(ansi_color, "\033[00m");
1908
fputs(ansi_color, stdout);
1914
* Get current terminal foreground color.
1916
PJ_DEF(pj_color_t) pj_term_get_color(void)
1921
#endif /* PJ_TERM_HAS_COLOR */
1923
#if !defined(PJ_DARWINOS) || PJ_DARWINOS == 0
1927
PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
1930
return (*main_func)(argc, argv);