cond.c
来自「xenomai 很好的linux实时补丁」· C语言 代码 · 共 564 行 · 第 1/2 页
C
564 行
if(err) goto unlock_and_return; /* Bind mutex to cond. */ if (cond->mutex == NULL) { cond->mutex = mutex; ++mutex->mutex->condvars; } /* Wait for another thread to signal the condition. */ xnsynch_sleep_on(&cond->synchbase, to); /* There are four possible wakeup conditions : - cond_signal / cond_broadcast, no status bit is set, and the function should return 0 ; - timeout, the status XNTIMEO is set, and the function should return ETIMEDOUT ; - pthread_kill, the status bit XNBREAK is set, but ignored, the function simply returns EINTR (used only by the user-space interface, replaced by 0 anywhere else), causing a wakeup, spurious or not whether pthread_cond_signal was called between pthread_kill and the moment when xnsynch_sleep_on returned ; - pthread_cancel, no status bit is set, but cancellation specific bits are set, and tested only once the mutex is reacquired, so that the cancellation handler can be called with the mutex locked, as required by the specification. */ err = 0; if (xnthread_test_flags(cur, XNBREAK)) err = EINTR; else if (xnthread_test_flags(cur, XNTIMEO)) err = ETIMEDOUT; /* Unbind mutex and cond, if no other thread is waiting, if the job was not already done. */ if (!xnsynch_nsleepers(&cond->synchbase) && cond->mutex == mutex) { --mutex->mutex->condvars; cond->mutex = NULL; } /* relock mutex */ mutex_restore_count(cur, mutex, count); thread_cancellation_point(cur); unlock_and_return: xnlock_put_irqrestore(&nklock, s); return err;}/** * Wait on a condition variable. * * This service atomically unlocks the mutex @a mx, and block the calling thread * until the condition variable @a cnd is signalled using pthread_cond_signal() * or pthread_cond_broadcast(). When the condition is signaled, this service * re-acquire the mutex before returning. * * Spurious wakeups occur if a signal is delivered to the blocked thread, so, an * application should not assume that the condition changed upon successful * return from this service. * * Even if the mutex @a mx is recursive and its recursion count is greater than * one on entry, it is unlocked before blocking the caller, and the recursion * count is restored once the mutex is re-acquired by this service before * returning. * * Once a thread is blocked on a condition variable, a dynamic binding is formed * between the condition vairable @a cnd and the mutex @a mx; if another thread * calls this service specifying @a cnd as a condition variable but another * mutex than @a mx, this service returns immediately with the EINVAL status. * * This service is a cancellation point for Xenomai POSIX skin threads * (created with the pthread_create() service). When such a thread is cancelled * while blocked in a call to this service, the mutex @a mx is re-acquired * before the cancellation cleanup handlers are called. * * @param cnd the condition variable to wait for; * * @param mx the mutex associated with @a cnd. * * @return 0 on success, * @return an error number if: * - EINVAL, the specified condition variable or mutex is invalid; * - EPERM, the caller context is invalid; * - EINVAL, another thread is currently blocked on @a cnd using another mutex * than @a mx; * - EPERM, the specified mutex is not owned by the caller. * * @par Valid contexts: * - Xenomai kernel-space thread; * - Xenomai user-space thread (switches to primary mode). * * @see http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cond_wait.html * */int pthread_cond_wait (pthread_cond_t *cnd, pthread_mutex_t *mx){ struct __shadow_mutex *mutex = &((union __xeno_mutex *) mx)->shadow_mutex; struct __shadow_cond *cond = &((union __xeno_cond *) cnd)->shadow_cond; int err; err = pse51_cond_timedwait_internal(cond, mutex, XN_INFINITE); return err == EINTR ? 0 : err;}/** * Wait a bounded time on a condition variable. * * This service is equivalent to pthread_cond_wait(), except that the calling * thread remains blocked on the condition variable @a cnd only until the * timeout specified by @a abstime expires. * * The timeout @a abstime is expressed as an absolute value of the @a clock * attribute passed to pthread_cond_init(). By default, @a CLOCK_REALTIME is * used. * * @param cnd the condition variable to wait for; * * @param mx the mutex associated with @a cnd; * * @param abstime the timeout, expressed as an absolute value of the clock * attribute passed to pthread_cond_init(). * * @return 0 on success, * @return an error number if: * - EINVAL, the specified condition variable, mutex or timeout is invalid; * - EPERM, the caller context is invalid; * - EINVAL, another thread is currently blocked on @a cnd using another mutex * than @a mx; * - EPERM, the specified mutex is not owned by the caller; * - ETIMEDOUT, the specified timeout expired. * * @par Valid contexts: * - Xenomai kernel-space thread; * - Xenomai user-space thread (switches to primary mode). * * @see http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cond_timedwait.html * */int pthread_cond_timedwait (pthread_cond_t *cnd, pthread_mutex_t *mx, const struct timespec *abstime){ struct __shadow_mutex *mutex = &((union __xeno_mutex *) mx)->shadow_mutex; struct __shadow_cond *cond = &((union __xeno_cond *) cnd)->shadow_cond; int err; err = pse51_cond_timedwait_internal(cond, mutex, ts2ticks_ceil(abstime)+1); return err == EINTR ? 0 : err;}/** * Signal a condition variable. * * This service unblocks one thread blocked on the condition variable @a cnd. * * If more than one thread is blocked on the specified condition variable, the * highest priority thread is unblocked. * * @param cnd the condition variable to be signalled. * * @return 0 on succes, * @return an error number if: * - EINVAL, the condition variable is invalid. * * @see http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cond_signal.html. * */int pthread_cond_signal (pthread_cond_t *cnd){ struct __shadow_cond *shadow = &((union __xeno_cond *) cnd)->shadow_cond; pse51_cond_t *cond; spl_t s; xnlock_get_irqsave(&nklock, s); if (!pse51_obj_active(shadow, PSE51_COND_MAGIC, struct __shadow_cond)) { xnlock_put_irqrestore(&nklock, s); return EINVAL; } cond = shadow->cond; /* FIXME: If the mutex associated with cnd is owned by the current thread, we could postpone rescheduling until pthread_mutex_unlock is called, this would save two useless context switches. */ if (xnsynch_wakeup_one_sleeper(&cond->synchbase) != NULL) xnpod_schedule(); xnlock_put_irqrestore(&nklock, s); return 0;}/** * Broadcast a condition variable. * * This service unblocks all threads blocked on the condition variable @a cnd. * * @param cnd the condition variable to be signalled. * * @return 0 on succes, * @return an error number if: * - EINVAL, the condition variable is invalid. * * @see http://www.opengroup.org/onlinepubs/000095399/functions/pthread_cond_broadcast.html * */int pthread_cond_broadcast (pthread_cond_t *cnd){ struct __shadow_cond *shadow = &((union __xeno_cond *) cnd)->shadow_cond; pse51_cond_t *cond; spl_t s; xnlock_get_irqsave(&nklock, s); if (!pse51_obj_active(shadow, PSE51_COND_MAGIC, struct __shadow_cond)) { xnlock_put_irqrestore(&nklock, s); return EINVAL; } cond = shadow->cond; if(xnsynch_flush(&cond->synchbase, 0) == XNSYNCH_RESCHED) xnpod_schedule(); xnlock_put_irqrestore(&nklock, s); return 0;}void pse51_cond_pkg_init (void){ initq(&pse51_condq); pthread_condattr_init(&default_cond_attr);}void pse51_cond_pkg_cleanup (void){ xnholder_t *holder; spl_t s; xnlock_get_irqsave(&nklock, s); while ((holder = getheadq(&pse51_condq)) != NULL) {#ifdef CONFIG_XENO_OPT_DEBUG xnprintf("Posix condition variable %p was not destroyed, destroying" " now.\n", link2cond(holder));#endif /* CONFIG_XENO_OPT_DEBUG */ cond_destroy_internal(link2cond(holder)); } xnlock_put_irqrestore(&nklock, s);}/*@}*/EXPORT_SYMBOL(pthread_cond_init);EXPORT_SYMBOL(pthread_cond_destroy);EXPORT_SYMBOL(pthread_cond_wait);EXPORT_SYMBOL(pthread_cond_timedwait);EXPORT_SYMBOL(pthread_cond_signal);EXPORT_SYMBOL(pthread_cond_broadcast);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?