📄 cond.c
字号:
/** * @file * This file is part of the Xenomai project. * * @note Copyright (C) 2004 Philippe Gerum <rpm@xenomai.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * \ingroup cond *//*! * \ingroup native * \defgroup cond Condition variable services. * * Condition variable services. * * A condition variable is a synchronization object which allows tasks * to suspend execution until some predicate on shared data is * satisfied. The basic operations on conditions are: signal the * condition (when the predicate becomes true), and wait for the * condition, blocking the task execution until another task signals * the condition. A condition variable must always be associated with * a mutex, to avoid a well-known race condition where a task prepares * to wait on a condition variable and another task signals the * condition just before the first task actually waits on it. * *@{*/#include <nucleus/pod.h>#include <nucleus/registry.h>#include <native/task.h>#include <native/mutex.h>#include <native/cond.h>#ifdef CONFIG_XENO_EXPORT_REGISTRYstatic int __cond_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ RT_COND *cond = (RT_COND *)data; char *p = page; int len; spl_t s; xnlock_get_irqsave(&nklock,s); if (xnsynch_nsleepers(&cond->synch_base) > 0) { xnpholder_t *holder; /* Pended condvar -- dump waiters. */ holder = getheadpq(xnsynch_wait_queue(&cond->synch_base)); while (holder) { xnthread_t *sleeper = link2thread(holder,plink); p += sprintf(p,"+%s\n",xnthread_name(sleeper)); holder = nextpq(xnsynch_wait_queue(&cond->synch_base),holder); } } xnlock_put_irqrestore(&nklock,s); len = (p - page) - off; if (len <= off + count) *eof = 1; *start = page + off; if(len > count) len = count; if(len < 0) len = 0; return len;}extern xnptree_t __native_ptree;static xnpnode_t __cond_pnode = { .dir = NULL, .type = "condvars", .entries = 0, .read_proc = &__cond_read_proc, .write_proc = NULL, .root = &__native_ptree,};#elif defined(CONFIG_XENO_OPT_REGISTRY)static xnpnode_t __cond_pnode = { .type = "condvars"};#endif /* CONFIG_XENO_EXPORT_REGISTRY *//** * @fn int rt_cond_create(RT_COND *cond, const char *name) * @brief Create a condition variable. * * Create a synchronization object that allows tasks to suspend * execution until some predicate on shared data is satisfied. * * @param cond The address of a condition variable descriptor Xenomai * will use to store the variable-related data. This descriptor must * always be valid while the variable is active therefore it must be * allocated in permanent memory. * * @param name An ASCII string standing for the symbolic name of the * condition variable. When non-NULL and non-empty, this string is * copied to a safe place into the descriptor, and passed to the * registry package if enabled for indexing the created variable. * * @return 0 is returned upon success. Otherwise: * * - -ENOMEM is returned if the system fails to get enough dynamic * memory from the global real-time heap in order to register the * condition variable. * * - -EEXIST is returned if the @a name is already in use by some * registered object. * * - -EPERM is returned if this service was called from an * asynchronous context. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_cond_create (RT_COND *cond, const char *name){ int err = 0; if (xnpod_asynch_p()) return -EPERM; xnsynch_init(&cond->synch_base,XNSYNCH_PRIO); cond->handle = 0; /* i.e. (still) unregistered cond. */ cond->magic = XENO_COND_MAGIC; xnobject_copy_name(cond->name,name);#if defined(__KERNEL__) && defined(CONFIG_XENO_OPT_PERVASIVE) cond->cpid = 0;#endif /* __KERNEL__ && CONFIG_XENO_OPT_PERVASIVE */#ifdef CONFIG_XENO_OPT_REGISTRY /* <!> Since xnregister_enter() may reschedule, only register complete objects, so that the registry cannot return handles to half-baked objects... */ if (name) { xnpnode_t *pnode = &__cond_pnode; if (!*name) { /* Since this is an anonymous object (empty name on entry) from user-space, it gets registered under an unique internal name but is not exported through /proc. */ xnobject_create_name(cond->name,sizeof(cond->name),(void*)cond); pnode = NULL; } err = xnregistry_enter(cond->name,cond,&cond->handle,pnode); if (err) rt_cond_delete(cond); }#endif /* CONFIG_XENO_OPT_REGISTRY */ return err;}/** * @fn int rt_cond_delete(RT_COND *cond) * @brief Delete a condition variable. * * Destroy a condition variable and release all the tasks currently * pending on it. A condition variable exists in the system since * rt_cond_create() has been called to create it, so this service must * be called in order to destroy it afterwards. * * @param cond The descriptor address of the affected condition * variable. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a cond is not a condition variable * descriptor. * * - -EIDRM is returned if @a cond is a deleted condition variable * descriptor. * * - -EPERM is returned if this service was called from an * asynchronous context. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_cond_delete (RT_COND *cond){ int err = 0, rc; spl_t s; if (xnpod_asynch_p()) return -EPERM; xnlock_get_irqsave(&nklock,s); cond = xeno_h2obj_validate(cond,XENO_COND_MAGIC,RT_COND); if (!cond) { err = xeno_handle_error(cond,XENO_COND_MAGIC,RT_COND); goto unlock_and_exit; } rc = xnsynch_destroy(&cond->synch_base);#ifdef CONFIG_XENO_OPT_REGISTRY if (cond->handle) xnregistry_remove(cond->handle);#endif /* CONFIG_XENO_OPT_REGISTRY */ xeno_mark_deleted(cond); if (rc == XNSYNCH_RESCHED) /* Some task has been woken up as a result of the deletion: reschedule now. */ xnpod_schedule(); unlock_and_exit: xnlock_put_irqrestore(&nklock,s); return err;}/** * @fn int rt_cond_signal(RT_COND *cond) * @brief Signal a condition variable. * * If the condition variable is pended, the first waiting task (by * queuing priority order) is immediately unblocked. * * @param cond The descriptor address of the affected condition * variable. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a cond is not a condition variable * descriptor. * * - -EIDRM is returned if @a cond is a deleted condition variable * descriptor. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Interrupt service routine * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_cond_signal (RT_COND *cond){ int err = 0; spl_t s; xnlock_get_irqsave(&nklock,s); cond = xeno_h2obj_validate(cond,XENO_COND_MAGIC,RT_COND); if (!cond) { err = xeno_handle_error(cond,XENO_COND_MAGIC,RT_COND); goto unlock_and_exit; } if (thread2rtask(xnsynch_wakeup_one_sleeper(&cond->synch_base)) != NULL) { xnsynch_set_owner(&cond->synch_base,NULL); /* No ownership to track. */ xnpod_schedule();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -