/* * pj_mutex_trylock() */ PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) { pj_status_t status; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is trying", pj_thread_this()->obj_name)); #if PJ_WIN32_WINNT >= 0x0400 status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN; #else status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? PJ_SUCCESS : PJ_ETIMEDOUT; #endif if (status==PJ_SUCCESS) { LOG_MUTEX((mutex->obj_name, "Mutex acquired by thread %s", pj_thread_this()->obj_name)); #if PJ_DEBUG mutex->owner = pj_thread_this(); ++mutex->nesting_level; #endif } else { LOG_MUTEX((mutex->obj_name, "Mutex: thread %s's trylock() failed", pj_thread_this()->obj_name)); } return status; }
/* * pj_thread_join() */ PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) { #if PJ_HAS_THREADS pj_thread_t *rec = (pj_thread_t *)p; void *ret; int result; PJ_CHECK_STACK(); if(pj_thread_this()->thread == rec->thread){ return PJ_SUCCESS; } PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); result = pthread_join( rec->thread, &ret); if (result == 0) return PJ_SUCCESS; else { /* Calling pthread_join() on a thread that no longer exists and * getting back ESRCH isn't an error (in this context). * Thanks Phil Torre <*****@*****.**>. */ return result==ESRCH ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(result); } #else PJ_CHECK_STACK(); pj_assert(!"No multithreading support!"); return PJ_EINVALIDOP; #endif }
/* * pj_sem_wait() */ PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) { #if PJ_HAS_THREADS int result; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", pj_thread_this()->obj_name)); result = sem_wait( sem->sem ); if (result == 0) { PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", pj_thread_this()->obj_name)); } else { PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", pj_thread_this()->obj_name)); } if (result == 0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); #else pj_assert( sem == (pj_sem_t*) 1 ); return PJ_SUCCESS; #endif }
static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout) { DWORD result; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); LOG_MUTEX((sem->obj_name, "Semaphore: thread %s is waiting", pj_thread_this()->obj_name)); result = WaitForSingleObject(sem->hSemaphore, timeout); if (result == WAIT_OBJECT_0) { LOG_MUTEX((sem->obj_name, "Semaphore acquired by thread %s", pj_thread_this()->obj_name)); } else { LOG_MUTEX((sem->obj_name, "Semaphore: thread %s FAILED to acquire", pj_thread_this()->obj_name)); } if (result==WAIT_OBJECT_0) return PJ_SUCCESS; else if (result==WAIT_TIMEOUT) return PJ_ETIMEDOUT; else return PJ_RETURN_OS_ERROR(GetLastError()); }
/* * pj_sem_wait() */ PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) { #if PJ_HAS_THREADS int result; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", pj_thread_this(sem->inst_id)->obj_name)); #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 result = dispatch_semaphore_wait(sem->sem, DISPATCH_TIME_FOREVER ); #else result = sem_wait( sem->sem); #endif if (result == 0) { PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", pj_thread_this(sem->inst_id)->obj_name)); } else { PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", pj_thread_this(sem->inst_id)->obj_name)); } if (result == 0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); #else pj_assert( sem == (pj_sem_t*) 1 ); return PJ_SUCCESS; #endif }
static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout) { DWORD result; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(event, PJ_EINVAL); PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", pj_thread_this()->obj_name)); result = WaitForSingleObject(event->hEvent, timeout); if (result == WAIT_OBJECT_0) { PJ_LOG(6, (event->obj_name, "Event: thread %s is released", pj_thread_this()->obj_name)); } else { PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", pj_thread_this()->obj_name)); } if (result==WAIT_OBJECT_0) return PJ_SUCCESS; else if (result==WAIT_TIMEOUT) return PJ_ETIMEDOUT; else return PJ_RETURN_OS_ERROR(GetLastError()); }
/* * pj_mutex_unlock() */ PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) { #if PJ_HAS_THREADS pj_status_t status; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); #if PJ_DEBUG pj_assert(mutex->owner == pj_thread_this()); if (--mutex->nesting_level == 0) { mutex->owner = NULL; mutex->owner_name[0] = '\0'; } PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s (level=%d)", pj_thread_this()->obj_name, mutex->nesting_level)); #else PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", pj_thread_this()->obj_name)); #endif status = pthread_mutex_unlock( &mutex->mutex ); if (status == 0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(status); #else /* PJ_HAS_THREADS */ pj_assert( mutex == (pj_mutex_t*)1 ); return PJ_SUCCESS; #endif }
/* * pj_mutex_lock() */ PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) { pj_status_t status; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is waiting", pj_thread_this()->obj_name)); #if PJ_WIN32_WINNT >= 0x0400 EnterCriticalSection(&mutex->crit); status=PJ_SUCCESS; #else if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0) status = PJ_SUCCESS; else status = PJ_STATUS_FROM_OS(GetLastError()); #endif LOG_MUTEX((mutex->obj_name, (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"), pj_thread_this()->obj_name)); #if PJ_DEBUG if (status == PJ_SUCCESS) { mutex->owner = pj_thread_this(); ++mutex->nesting_level; } #endif return status; }
/* * pj_mutex_unlock() */ PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) { pj_status_t status; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); #if PJ_DEBUG pj_assert(mutex->owner == pj_thread_this()); if (--mutex->nesting_level == 0) { mutex->owner = NULL; } #endif LOG_MUTEX((mutex->obj_name, "Mutex released by thread %s", pj_thread_this()->obj_name)); #if PJ_WIN32_WINNT >= 0x0400 LeaveCriticalSection(&mutex->crit); status=PJ_SUCCESS; #else status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : PJ_STATUS_FROM_OS(GetLastError()); #endif return status; }
/* * pj_thread_join() */ PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) { pj_thread_t *rec = (pj_thread_t *)p; DWORD rc; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, PJ_EINVAL); if (p == pj_thread_this()) return PJ_ECANCELLED; PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8 rc = WaitForSingleObjectEx(rec->hthread, INFINITE, FALSE); #else rc = WaitForSingleObject(rec->hthread, INFINITE); #endif if (rc==WAIT_OBJECT_0) return PJ_SUCCESS; else if (rc==WAIT_TIMEOUT) return PJ_ETIMEDOUT; else return PJ_RETURN_OS_ERROR(GetLastError()); }
/* * Clock thread */ static int clock_thread(void *arg) { pj_timestamp now; pjmedia_clock *clock = (pjmedia_clock*) arg; /* Set thread priority to maximum unless not wanted. */ if ((clock->options & PJMEDIA_CLOCK_NO_HIGHEST_PRIO) == 0) { int max = pj_thread_get_prio_max(pj_thread_this()); if (max > 0) pj_thread_set_prio(pj_thread_this(), max); } //printf("%s:------------11--------------\n", THIS_FILE); /* Get the first tick */ pj_get_timestamp(&clock->next_tick); clock->next_tick.u64 += clock->interval.u64; while (!clock->quitting) { pj_get_timestamp(&now); /* Wait for the next tick to happen */ if (now.u64 < clock->next_tick.u64) { unsigned msec; msec = pj_elapsed_msec(&now, &clock->next_tick); pj_thread_sleep(msec); } //printf("%s:------------12--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting)); /* Skip if not running */ if (!clock->running) { /* Calculate next tick */ clock_calc_next_tick(clock, &now); continue; } pj_lock_acquire(clock->lock); //printf("%s:------------13--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting)); /* Call callback, if any */ if (clock->cb) (*clock->cb)(&clock->timestamp, clock->user_data); /* Best effort way to detect if we've been destroyed in the callback */ if (clock->quitting) break; /* Increment timestamp */ clock->timestamp.u64 += clock->timestamp_inc; //printf("%s:------------14--------------, 0x%02x, %d\n", THIS_FILE, clock, (int)(clock->quitting)); /* Calculate next tick */ clock_calc_next_tick(clock, &now); //printf("%s:------------15--------------\n", THIS_FILE); pj_lock_release(clock->lock); } return 0; }
/* * pj_mutex_lock() */ PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) { #if PJ_HAS_THREADS pj_status_t status; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); #if PJ_DEBUG PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting (mutex owner=%s)", pj_thread_this()->obj_name, mutex->owner_name)); #else PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", pj_thread_this()->obj_name)); #endif status = pthread_mutex_lock( &mutex->mutex ); #if PJ_DEBUG if (status == PJ_SUCCESS) { mutex->owner = pj_thread_this(); pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name); ++mutex->nesting_level; } PJ_LOG(6,(mutex->obj_name, (status==0 ? "Mutex acquired by thread %s (level=%d)" : "Mutex acquisition FAILED by %s (level=%d)"), pj_thread_this()->obj_name, mutex->nesting_level)); #else PJ_LOG(6,(mutex->obj_name, (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"), pj_thread_this()->obj_name)); #endif if (status == 0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(status); #else /* PJ_HAS_THREADS */ pj_assert( mutex == (pj_mutex_t*)1 ); return PJ_SUCCESS; #endif }
/* * pj_mutex_destroy() */ PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) { enum { RETRY = 4 }; int status = 0; unsigned retry; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); #if PJ_HAS_THREADS PJ_LOG(6,(mutex->obj_name, "Mutex destroyed by thread %s", pj_thread_this()->obj_name)); for (retry=0; retry<RETRY; ++retry) { status = pthread_mutex_destroy( &mutex->mutex ); if (status == PJ_SUCCESS) break; else if (retry<RETRY-1 && status == EBUSY) pthread_mutex_unlock(&mutex->mutex); } if (status == 0) return PJ_SUCCESS; else { return PJ_RETURN_OS_ERROR(status); } #else pj_assert( mutex == (pj_mutex_t*)1 ); status = PJ_SUCCESS; return status; #endif }
pj_status_t alsa_set_max_relative_thread_priority(int relative) { pj_status_t result; struct sched_param param; pthread_t* thid; thid = (pthread_t*) pj_thread_get_os_handle (pj_thread_this()); #if PJ_LINUX==1 param.__sched_priority = sched_get_priority_max (SCHED_RR)+relative; PJ_LOG (3,(THIS_FILE, "thread(%u): Set thread priority " "to %d.", (unsigned)syscall (SYS_gettid),(int)param.__sched_priority)); #elif PJ_DARWINOS==1 param.sched_priority = sched_get_priority_max (SCHED_RR)+relative; PJ_LOG (3,(THIS_FILE, "thread(%u): Set thread priority " "to %d.", (unsigned)syscall (SYS_gettid),(int)param.sched_priority)); #endif result = pthread_setschedparam (*thid, SCHED_RR, ¶m); if (result) { if (result == EPERM) PJ_LOG (3,(THIS_FILE, "Unable to increase thread priority, " "root access needed.")); else PJ_LOG (3,(THIS_FILE, "Unable to increase thread priority, " "error: %d", result)); } return result; }
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) { if (mutex->recursive) return mutex->owner == pj_thread_this(); else return 1; }
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) { long rc; PJ_ASSERT_RETURN(mutex, PJ_EINVAL); if (mutex->recursive) { pj_thread_t *this_thread = pj_thread_this(); if (mutex->owner == this_thread) { ++mutex->own_count; } else { rc = down_interruptible(&mutex->sem); if (rc != 0) return PJ_RETURN_OS_ERROR(-rc); pj_assert(mutex->own_count == 0); mutex->owner = this_thread; mutex->own_count = 1; } } else { int rc = down_trylock(&mutex->sem); if (rc != 0) return PJ_RETURN_OS_ERROR(-rc); } return PJ_SUCCESS; }
/* * pj_sem_destroy() */ PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) { #if PJ_HAS_THREADS int result; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s", pj_thread_this()->obj_name)); #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; else return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); #else pj_assert( sem == (pj_sem_t*) 1 ); return PJ_SUCCESS; #endif }
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) { #if PJ_HAS_THREADS return mutex->owner == pj_thread_this(); #else return 1; #endif }
/* * pj_mutex_trylock() */ PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) { #if PJ_HAS_THREADS int status; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(mutex, PJ_EINVAL); PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is trying", pj_thread_this()->obj_name)); status = pthread_mutex_trylock( &mutex->mutex ); if (status==0) { #if PJ_DEBUG mutex->owner = pj_thread_this(); pj_ansi_strcpy(mutex->owner_name, mutex->owner->obj_name); ++mutex->nesting_level; PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s (level=%d)", pj_thread_this()->obj_name, mutex->nesting_level)); #else PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", pj_thread_this()->obj_name)); #endif } else { PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s's trylock() failed", pj_thread_this()->obj_name)); } if (status==0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(status); #else /* PJ_HAS_THREADS */ pj_assert( mutex == (pj_mutex_t*)1); return PJ_SUCCESS; #endif }
/* * pj_mutex_is_locked() */ PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) { #if PJ_DEBUG return mutex->owner == pj_thread_this(); #else PJ_UNUSED_ARG(mutex); pj_assert(!"PJ_DEBUG is not set!"); return 1; #endif }
bool SIPPresence::tryLock() { pj_status_t status; status = pj_mutex_trylock(mutex_); if (status == PJ_SUCCESS) { mutex_owner_ = pj_thread_this(); ++mutex_nesting_level_; } return status==PJ_SUCCESS; }
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) { #if PJ_HAS_THREADS pj_thread_t *rec = (pj_thread_t *)p; void *ret; PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); return pthread_join( rec->thread, &ret); #else PJ_LOG(2, (THIS_FILE, "pj_thread_join() unsupported: thread is not enabled!")); return 0; #endif }
/* * pj_sem_destroy() */ PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) { PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); LOG_MUTEX((sem->obj_name, "Semaphore destroyed by thread %s", pj_thread_this()->obj_name)); if (CloseHandle(sem->hSemaphore)) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(GetLastError()); }
/* * pj_sem_post() */ PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) { PJ_CHECK_STACK(); PJ_ASSERT_RETURN(sem, PJ_EINVAL); LOG_MUTEX((sem->obj_name, "Semaphore released by thread %s", pj_thread_this()->obj_name)); if (ReleaseSemaphore(sem->hSemaphore, 1, NULL)) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(GetLastError()); }
/* * pj_sem_post() */ PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) { #if PJ_HAS_THREADS int result; PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", pj_thread_this()->obj_name)); result = sem_post( sem->sem ); if (result == 0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); #else pj_assert( sem == (pj_sem_t*) 1); return PJ_SUCCESS; #endif }
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) { PJ_ASSERT_RETURN(mutex, PJ_EINVAL); if (mutex->recursive) { pj_thread_t *this_thread = pj_thread_this(); if (mutex->owner == this_thread) { ++mutex->own_count; } else { down(&mutex->sem); pj_assert(mutex->own_count == 0); mutex->owner = this_thread; mutex->own_count = 1; } } else { down(&mutex->sem); } return PJ_SUCCESS; }
/* * The thread's entry point. * * Each of the thread mainly will just execute the loop which * increments a variable. */ static void* thread_proc(pj_uint32_t *pcounter) { /* Test that pj_thread_register() works. */ pj_thread_desc desc; pj_thread_t *this_thread; unsigned id; pj_status_t rc; id = *pcounter; PJ_UNUSED_ARG(id); /* Warning about unused var if TRACE__ is disabled */ TRACE__((THIS_FILE, " thread %d running..", id)); pj_bzero(desc, sizeof(desc)); rc = pj_thread_register("thread", desc, &this_thread); if (rc != PJ_SUCCESS) { app_perror("...error in pj_thread_register", rc); return NULL; } /* Test that pj_thread_this() works */ this_thread = pj_thread_this(); if (this_thread == NULL) { PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!")); return NULL; } /* Test that pj_thread_get_name() works */ if (pj_thread_get_name(this_thread) == NULL) { PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!")); return NULL; } /* Main loop */ for (;!quit_flag;) { (*pcounter)++; //Must sleep if platform doesn't do time-slicing. //pj_thread_sleep(0); } TRACE__((THIS_FILE, " thread %d quitting..", id)); return NULL; }
/* * pj_sem_post() */ PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) { #if PJ_HAS_THREADS int result; PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s", pj_thread_this(sem->inst_id)->obj_name)); #if defined(PJ_DARWINOS) && PJ_DARWINOS!=0 result = dispatch_semaphore_signal(sem->sem); #else result = sem_post( sem->sem ); #endif if (result == 0) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(pj_get_native_os_error()); #else pj_assert( sem == (pj_sem_t*) 1); return PJ_SUCCESS; #endif }
/* * pj_thread_check_stack() * Implementation for PJ_CHECK_STACK() */ PJ_DEF(void) pj_thread_check_stack(const char *file, int line) { char stk_ptr; pj_uint32_t usage; pj_thread_t *thread = pj_thread_this(); /* Calculate current usage. */ usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start : thread->stk_start - &stk_ptr; /* Assert if stack usage is dangerously high. */ pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128)); /* Keep statistic. */ if (usage > thread->stk_max_usage) { thread->stk_max_usage = usage; thread->caller_file = file; thread->caller_line = line; } }
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) { pj_highprec_t ticks; pj_thread_t *thread = pj_thread_this(); PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG); /* Use high precision calculation to make sure we don't * crop values: * * ticks = HZ * msec / 1000 */ ticks = HZ; pj_highprec_mul(ticks, msec); pj_highprec_div(ticks, 1000); TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks)); interruptible_sleep_on_timeout( &thread->queue, ticks); return PJ_SUCCESS; }