From 2f24a0b188d55837e7c11fcbef53153702560699 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 15 Aug 2008 14:53:18 +0000 Subject: Ticket #595: Broken semaphore implementation on MacOS X (thanks Viktor Krikun for the report) git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2217 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/src/pj/os_core_unix.c | 50 ++++++++++++++++++++++++++++++++----- pjlib/src/pjlib-test/mutex.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c index 006f2a0b..9543737f 100644 --- a/pjlib/src/pj/os_core_unix.c +++ b/pjlib/src/pj/os_core_unix.c @@ -88,7 +88,7 @@ struct pj_mutex_t #if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 struct pj_sem_t { - sem_t sem; + sem_t *sem; char obj_name[PJ_MAX_OBJ_NAME]; }; #endif /* PJ_HAS_SEMAPHORE */ @@ -1470,8 +1470,42 @@ PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, sem = PJ_POOL_ALLOC_T(pool, pj_sem_t); PJ_ASSERT_RETURN(sem, PJ_ENOMEM); - if (sem_init( &sem->sem, 0, initial) != 0) +#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 + /* MacOS X doesn't support anonymous semaphore */ + { + char sem_name[PJ_GUID_MAX_LENGTH+1]; + pj_str_t nam; + + /* We should use SEM_NAME_LEN, but this doesn't seem to be + * declared anywhere? The value here is just from trial and error + * to get the longest name supported. + */ +# define MAX_SEM_NAME_LEN 23 + + /* Create a unique name for the semaphore. */ + if (PJ_GUID_STRING_LENGTH <= MAX_SEM_NAME_LEN) { + nam.ptr = sem_name; + pj_generate_unique_string(&nam); + sem_name[nam.slen] = '\0'; + } else { + pj_create_random_string(sem_name, MAX_SEM_NAME_LEN); + sem_name[MAX_SEM_NAME_LEN] = '\0'; + } + + /* Create semaphore */ + sem->sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR, + initial); + if (sem->sem == SEM_FAILED) + return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); + + /* And immediately release the name as we don't need it */ + sem_unlink(sem_name); + } +#else + sem->sem = PJ_POOL_ALLOC_T(pool, sem_t); + if (sem_init( sem->sem, 0, initial) != 0) return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); +#endif /* Set name. */ if (!name) { @@ -1508,7 +1542,7 @@ PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", pj_thread_this()->obj_name)); - result = sem_wait( &sem->sem ); + result = sem_wait( sem->sem ); if (result == 0) { PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", @@ -1539,7 +1573,7 @@ PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); - result = sem_trywait( &sem->sem ); + result = sem_trywait( sem->sem ); if (result == 0) { PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", @@ -1564,7 +1598,7 @@ PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) int result; PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", pj_thread_this()->obj_name)); - result = sem_post( &sem->sem ); + result = sem_post( sem->sem ); if (result == 0) return PJ_SUCCESS; @@ -1589,7 +1623,11 @@ PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s", pj_thread_this()->obj_name)); - result = sem_destroy( &sem->sem ); +#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 + result = sem_close( sem->sem ); +#else + result = sem_destroy( sem->sem ); +#endif if (result == 0) return PJ_SUCCESS; diff --git a/pjlib/src/pjlib-test/mutex.c b/pjlib/src/pjlib-test/mutex.c index 81565c57..0c507609 100644 --- a/pjlib/src/pjlib-test/mutex.c +++ b/pjlib/src/pjlib-test/mutex.c @@ -148,6 +148,59 @@ static int recursive_mutex_test(pj_pool_t *pool) return PJ_SUCCESS; } +#if PJ_HAS_SEMAPHORE +static int semaphore_test(pj_pool_t *pool) +{ + pj_sem_t *sem; + pj_status_t status; + + PJ_LOG(3,("", "...testing semaphore")); + + status = pj_sem_create(pool, NULL, 0, 1, &sem); + if (status != PJ_SUCCESS) { + app_perror("...error: pj_sem_create()", status); + return -151; + } + + status = pj_sem_post(sem); + if (status != PJ_SUCCESS) { + app_perror("...error: pj_sem_post()", status); + pj_sem_destroy(sem); + return -153; + } + + status = pj_sem_trywait(sem); + if (status != PJ_SUCCESS) { + app_perror("...error: pj_sem_trywait()", status); + pj_sem_destroy(sem); + return -156; + } + + status = pj_sem_post(sem); + if (status != PJ_SUCCESS) { + app_perror("...error: pj_sem_post()", status); + pj_sem_destroy(sem); + return -159; + } + + status = pj_sem_wait(sem); + if (status != PJ_SUCCESS) { + app_perror("...error: pj_sem_wait()", status); + pj_sem_destroy(sem); + return -161; + } + + status = pj_sem_destroy(sem); + if (status != PJ_SUCCESS) { + app_perror("...error: pj_sem_destroy()", status); + return -163; + } + + return 0; +} +#endif /* PJ_HAS_SEMAPHORE */ + + int mutex_test(void) { pj_pool_t *pool; @@ -163,6 +216,12 @@ int mutex_test(void) if (rc != 0) return rc; +#if PJ_HAS_SEMAPHORE + rc = semaphore_test(pool); + if (rc != 0) + return rc; +#endif + pj_pool_release(pool); return 0; -- cgit v1.2.3