/** * Waits for a condition variable up to a certain date. * This works like vlc_cond_wait(), except for the additional time-out. * * If the variable was initialized with vlc_cond_init(), the timeout has the * same arbitrary origin as mdate(). If the variable was initialized with * vlc_cond_init_daytime(), the timeout is expressed from the Unix epoch. * * @param p_condvar condition variable to wait on * @param p_mutex mutex which is unlocked while waiting, * then locked again when waking up. * @param deadline <b>absolute</b> timeout * * @return 0 if the condition was signaled, an error code in case of timeout. */ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { #if defined(__APPLE__) && !defined(__powerpc__) && !defined( __ppc__ ) && !defined( __ppc64__ ) /* mdate() is the monotonic clock, timedwait origin is gettimeofday() which * isn't monotonic. Use imedwait_relative_np() instead */ mtime_t base = mdate(); deadline -= base; if (deadline < 0) deadline = 0; lldiv_t d = lldiv( deadline, CLOCK_FREQ ); struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) }; int val = pthread_cond_timedwait_relative_np(p_condvar, p_mutex, &ts); if (val != ETIMEDOUT) VLC_THREAD_ASSERT ("timed-waiting on condition"); return val; #else lldiv_t d = lldiv( deadline, CLOCK_FREQ ); struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) }; int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts); if (val != ETIMEDOUT) VLC_THREAD_ASSERT ("timed-waiting on condition"); return val; #endif }
/** * Increments the value of a semaphore. */ int vlc_sem_post (vlc_sem_t *sem) { int val = sem_post (sem); if (val != EOVERFLOW) VLC_THREAD_ASSERT ("unlocking semaphore"); return val; }
/* Destroys a condition variable. No threads shall be waiting or signaling the * condition. * parameter: p_condvar condition variable to destroy */ void vlc_cond_destroy (vlc_cond_t *p_condvar) { int val = pthread_cond_destroy( p_condvar ); /* due to a faulty pthread implementation within Darwin 11 and * later condition variables cannot be destroyed without * terminating the application immediately. * This Darwin kernel issue is still present in version 13 * and might not be resolved prior to Darwin 15. * radar://12496249 * * To work-around this, we are just leaking the condition variable * which is acceptable due to VLC's low number of created variables * and its usually limited runtime. * Ideally, we should implement a re-useable pool. */ if (val != 0) { #ifndef NDEBUG printf("pthread_cond_destroy returned %i\n", val); #endif if (val == EBUSY) return; } VLC_THREAD_ASSERT ("destroying condition"); }
/** * Atomically wait for the semaphore to become non-zero (if needed), * then decrements it. */ void vlc_sem_wait (vlc_sem_t *sem) { int val; do val = sem_wait (sem); while (val == EINTR); VLC_THREAD_ASSERT ("locking semaphore"); }
/** * Acquires a mutex if and only if it is not currently held by another thread. * This function never sleeps and can be used in delay-critical code paths. * This function is not a cancellation-point. * * <b>Beware</b>: If this function fails, then the mutex is held... by another * thread. The calling thread must deal with the error appropriately. That * typically implies postponing the operations that would have required the * mutex. If the thread cannot defer those operations, then it must use * vlc_mutex_lock(). If in doubt, use vlc_mutex_lock() instead. * * @param p_mutex mutex initialized with vlc_mutex_init() or * vlc_mutex_init_recursive() * @return 0 if the mutex could be acquired, an error code otherwise. */ int vlc_mutex_trylock (vlc_mutex_t *p_mutex) { int val = pthread_mutex_trylock( p_mutex ); if (val != EBUSY) VLC_THREAD_ASSERT ("locking mutex"); return val; }
/** * Save the current cancellation state (enabled or disabled), then disable * cancellation for the calling thread. * This function must be called before entering a piece of code that is not * cancellation-safe, unless it can be proven that the calling thread will not * be cancelled. * @return Previous cancellation state (opaque value for vlc_restorecancel()). */ int vlc_savecancel (void) { int state; int val = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state); VLC_THREAD_ASSERT ("saving cancellation"); return state; }
/** * Waits for a condition variable up to a certain date. * This works like vlc_cond_wait(), except for the additional time-out. * * If the variable was initialized with vlc_cond_init(), the timeout has the * same arbitrary origin as mdate(). If the variable was initialized with * vlc_cond_init_daytime(), the timeout is expressed from the Unix epoch. * * @param p_condvar condition variable to wait on * @param p_mutex mutex which is unlocked while waiting, * then locked again when waking up. * @param deadline <b>absolute</b> timeout * * @return 0 if the condition was signaled, an error code in case of timeout. */ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { struct timespec ts = mtime_to_ts (deadline); int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts); if (val != ETIMEDOUT) VLC_THREAD_ASSERT ("timed-waiting on condition"); return val; }
void vlc_join (vlc_thread_t handle, void **result) { vlc_sem_wait (&handle->finished); vlc_sem_destroy (&handle->finished); int val = pthread_join (handle->thread, result); VLC_THREAD_ASSERT ("joining thread"); clean_detached_thread(handle); }
/** * Destroys an initialized timer. If needed, the timer is first disarmed. * This function is undefined if the specified timer is not initialized. * * @warning This function <b>must</b> be called before the timer data can be * freed and before the timer callback function can be unloaded. * * @param timer to destroy */ void vlc_timer_destroy (vlc_timer_t *id) { #ifdef HAVE_POSIX_TIMER int val = timer_delete (id->handle); VLC_THREAD_ASSERT ("deleting timer"); #else timer_not_supported(); #endif }
void vlc_join (vlc_thread_t handle, void **result) { vlc_sem_wait (&handle->finished); vlc_sem_destroy (&handle->finished); int val = pthread_join (handle->thread, result); VLC_THREAD_ASSERT ("joining thread"); vlc_mutex_destroy(&handle->lock); free(handle); }
/* Atomically wait for the semaphore to become non-zero (if needed), * then decrements it. */ void vlc_sem_wait (vlc_sem_t *sem) { int val; if (likely(semaphore_wait(*sem) == KERN_SUCCESS)) return; val = EINVAL; VLC_THREAD_ASSERT ("locking semaphore"); }
/* Destroy a semaphore. */ void vlc_sem_destroy (vlc_sem_t *sem) { int val; if (likely(semaphore_destroy(mach_task_self(), *sem) == KERN_SUCCESS)) return; val = EINVAL; VLC_THREAD_ASSERT ("destroying semaphore"); }
int vlc_cond_timedwait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { struct timespec ts = mtime_to_ts (deadline); vlc_thread_t th = thread; int (*cb)(pthread_cond_t *, pthread_mutex_t *, const struct timespec *); if (th != NULL) { vlc_testcancel (); if (vlc_mutex_trylock (&th->lock) == 0) { th->cond = &condvar->cond; vlc_mutex_unlock (&th->lock); } else { /* The lock is already held by another thread. * => That other thread has just cancelled this one. */ vlc_testcancel (); /* Cancellation did not occur even though this thread is cancelled. * => Cancellation is disabled. */ th = NULL; } } switch (condvar->clock) { case CLOCK_REALTIME: cb = pthread_cond_timedwait; break; case CLOCK_MONOTONIC: cb = pthread_cond_timedwait_monotonic_np; break; default: assert (0); } int val = cb (&condvar->cond, p_mutex, &ts); if (val != ETIMEDOUT) VLC_THREAD_ASSERT ("timed-waiting on condition"); if (th != NULL) { if (vlc_mutex_trylock (&th->lock) == 0) { thread->cond = NULL; vlc_mutex_unlock (&th->lock); } /* Else: This thread was cancelled and is cancellable. vlc_testcancel() will take of it right there: */ vlc_testcancel(); } return val; }
/** * Atomically wait for the semaphore to become non-zero (if needed), * then decrements it. */ void vlc_sem_wait (vlc_sem_t *sem) { int val; do if (likely(sem_wait (sem) == 0)) return; while ((val = errno) == EINTR); VLC_THREAD_ASSERT ("locking semaphore"); }
/** * Destroys a semaphore. */ void vlc_sem_destroy (vlc_sem_t *sem) { int val; if (likely(sem_destroy (sem) == 0)) return; val = errno; VLC_THREAD_ASSERT ("destroying semaphore"); }
/* Increment the value of a semaphore. * returns 0 on success, EOVERFLOW in case of integer overflow */ int vlc_sem_post (vlc_sem_t *sem) { int val; if (likely(semaphore_signal(*sem) == KERN_SUCCESS)) return 0; val = EINVAL; if (unlikely(val != EOVERFLOW)) VLC_THREAD_ASSERT ("unlocking semaphore"); return val; }
/** * Increments the value of a semaphore. * @return 0 on success, EOVERFLOW in case of integer overflow */ int vlc_sem_post (vlc_sem_t *sem) { int val; if (likely(sem_post (sem) == 0)) return 0; val = errno; if (unlikely(val != EOVERFLOW)) VLC_THREAD_ASSERT ("unlocking semaphore"); return val; }
/***************************************************************************** * vlc_cond_destroy: destroy a condition, inner version *****************************************************************************/ void __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar ) { #if defined( LIBVLC_USE_PTHREAD ) int val = pthread_cond_destroy( p_condvar ); VLC_THREAD_ASSERT ("destroying condition"); #elif defined( UNDER_CE ) || defined( WIN32 ) VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); CloseHandle( *p_condvar ); #elif defined( HAVE_KERNEL_SCHEDULER_H ) p_condvar->init = 0; #endif }
/** * Restore the cancellation state for the calling thread. * @param state previous state as returned by vlc_savecancel(). * @return Nothing, always succeeds. */ void vlc_restorecancel (int state) { #ifndef NDEBUG int oldstate, val; val = pthread_setcancelstate (state, &oldstate); /* This should fail if an invalid value for given for state */ VLC_THREAD_ASSERT ("restoring cancellation"); if (unlikely(oldstate != PTHREAD_CANCEL_DISABLE)) vlc_thread_fatal ("restoring cancellation while not disabled", EINVAL, __func__, __FILE__, __LINE__); #else pthread_setcancelstate (state, NULL); #endif }
/** * Atomically wait for the semaphore to become non-zero (if needed), * then decrements it. */ void vlc_sem_wait (vlc_sem_t *sem) { int val; #if defined(__APPLE__) if (likely(semaphore_wait(*sem) == KERN_SUCCESS)) return; val = EINVAL; #else do if (likely(sem_wait (sem) == 0)) return; while ((val = errno) == EINTR); #endif VLC_THREAD_ASSERT ("locking semaphore"); }
/** * Destroys a semaphore. */ void vlc_sem_destroy (vlc_sem_t *sem) { int val; #if defined(__APPLE__) if (likely(semaphore_destroy(mach_task_self(), *sem) == KERN_SUCCESS)) return; val = EINVAL; #else if (likely(sem_destroy (sem) == 0)) return; val = errno; #endif VLC_THREAD_ASSERT ("destroying semaphore"); }
/** * Increments the value of a semaphore. * @return 0 on success, EOVERFLOW in case of integer overflow */ int vlc_sem_post (vlc_sem_t *sem) { int val; #if defined(__APPLE__) if (likely(semaphore_signal(*sem) == KERN_SUCCESS)) return 0; val = EINVAL; #else if (likely(sem_post (sem) == 0)) return 0; val = errno; #endif if (unlikely(val != EOVERFLOW)) VLC_THREAD_ASSERT ("unlocking semaphore"); return val; }
/** * Waits for a condition variable up to a certain date. * This works like vlc_cond_wait(), except for the additional time-out. * * If the variable was initialized with vlc_cond_init(), the timeout has the * same arbitrary origin as mdate(). If the variable was initialized with * vlc_cond_init_daytime(), the timeout is expressed from the Unix epoch. * * @param p_condvar condition variable to wait on * @param p_mutex mutex which is unlocked while waiting, * then locked again when waking up. * @param deadline <b>absolute</b> timeout * * @return 0 if the condition was signaled, an error code in case of timeout. */ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, mtime_t deadline) { #if defined(__APPLE__) && !defined(__powerpc__) && !defined( __ppc__ ) && !defined( __ppc64__ ) /* mdate() is mac_absolute_time on OSX, which we must convert to do * the same base than gettimeofday() which pthread_cond_timedwait * relies on. */ mtime_t oldbase = mdate(); struct timeval tv; gettimeofday(&tv, NULL); mtime_t newbase = (mtime_t)tv.tv_sec * 1000000 + (mtime_t) tv.tv_usec; deadline = deadline - oldbase + newbase; #endif lldiv_t d = lldiv( deadline, CLOCK_FREQ ); struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) }; int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts); if (val != ETIMEDOUT) VLC_THREAD_ASSERT ("timed-waiting on condition"); return val; }
void vlc_cond_wait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex) { vlc_thread_t th = thread; if (th != NULL) { vlc_testcancel (); if (vlc_mutex_trylock (&th->lock) == 0) { th->cond = &condvar->cond; vlc_mutex_unlock (&th->lock); } else { /* The lock is already held by another thread. * => That other thread has just cancelled this one. */ vlc_testcancel (); /* Cancellation did not occur even though this thread is cancelled. * => Cancellation is disabled. */ th = NULL; } } int val = pthread_cond_wait (&condvar->cond, p_mutex); VLC_THREAD_ASSERT ("waiting on condition"); if (th != NULL) { if (vlc_mutex_trylock (&th->lock) == 0) { thread->cond = NULL; vlc_mutex_unlock (&th->lock); } /* Else: This thread was cancelled and is cancellable. vlc_testcancel() will take of it right there: */ vlc_testcancel(); } }
/***************************************************************************** * vlc_mutex_destroy: destroy a mutex, inner version *****************************************************************************/ void __vlc_mutex_destroy( const char * psz_file, int i_line, vlc_mutex_t *p_mutex ) { #if defined( LIBVLC_USE_PTHREAD ) int val = pthread_mutex_destroy( p_mutex ); VLC_THREAD_ASSERT ("destroying mutex"); #elif defined( UNDER_CE ) VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); DeleteCriticalSection( &p_mutex->csection ); #elif defined( WIN32 ) VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); CloseHandle( *p_mutex ); #elif defined( HAVE_KERNEL_SCHEDULER_H ) if( p_mutex->init == 9999 ) delete_sem( p_mutex->lock ); p_mutex->init = 0; #endif }
void vlc_rwlock_unlock(vlc_rwlock_t* lock) { const int val = pthread_rwlock_unlock(lock); VLC_THREAD_ASSERT("releasing R/W lock"); }
void vlc_rwlock_wrlock(vlc_rwlock_t* lock) { const int val = pthread_rwlock_wrlock(lock); VLC_THREAD_ASSERT("acquiring R/W lock for writing"); }
void vlc_rwlock_destroy(vlc_rwlock_t* lock) { const int val = pthread_rwlock_destroy(lock); VLC_THREAD_ASSERT("destroying R/W lock"); }
void vlc_rwlock_init(vlc_rwlock_t* lock) { const int val = pthread_rwlock_init(lock, NULL); VLC_THREAD_ASSERT("initializing R/W lock"); }
/** * Detaches a thread. When the specified thread completes, it will be * automatically destroyed (in particular, its stack will be reclaimed), * instead of waiting for another thread to call vlc_join(). If the thread has * already completed, it will be destroyed immediately. * * When a thread performs some work asynchronously and may complete much * earlier than it can be joined, detaching the thread can save memory. * However, care must be taken that any resources used by a detached thread * remains valid until the thread completes. This will typically involve some * kind of thread-safe signaling. * * A thread may detach itself. * * @param handle thread handle */ void vlc_detach (vlc_thread_t handle) { int val = pthread_detach (handle); VLC_THREAD_ASSERT ("detaching thread"); }