📄 event.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 event *//*! * \ingroup native * \defgroup event Event flag group services. * * An event flag group is a synchronization object represented by a * long-word structure; every available bit in such word can be used * to map a user-defined event flag. When a flag is set, the * associated event is said to have occurred. Xenomai tasks and interrupt * handlers can use event flags to signal the occurrence of events to * other tasks; those tasks can either wait for the events to occur in * a conjunctive manner (all awaited events must have occurred to wake * up), or in a disjunctive way (at least one of the awaited events * must have occurred to wake up). * *@{*/#include <nucleus/pod.h>#include <nucleus/registry.h>#include <native/task.h>#include <native/event.h>#ifdef CONFIG_XENO_EXPORT_REGISTRYstatic int __event_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ RT_EVENT *event = (RT_EVENT *)data; char *p = page; int len; spl_t s; xnlock_get_irqsave(&nklock,s); p += sprintf(p,"=0x%lx\n",event->value); if (xnsynch_nsleepers(&event->synch_base) > 0) { xnpholder_t *holder; /* Pended event -- dump waiters. */ holder = getheadpq(xnsynch_wait_queue(&event->synch_base)); while (holder) { xnthread_t *sleeper = link2thread(holder,plink); RT_TASK *task = thread2rtask(sleeper); const char *mode = (task->wait_args.event.mode & EV_ANY) ? "any" : "all"; unsigned long mask = task->wait_args.event.mask; p += sprintf(p,"+%s (mask=0x%lx, %s)\n",xnthread_name(sleeper),mask,mode); holder = nextpq(xnsynch_wait_queue(&event->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 __event_pnode = { .dir = NULL, .type = "events", .entries = 0, .read_proc = &__event_read_proc, .write_proc = NULL, .root = &__native_ptree,};#elif defined(CONFIG_XENO_OPT_REGISTRY)static xnpnode_t __event_pnode = { .type = "events"};#endif /* CONFIG_XENO_EXPORT_REGISTRY *//** * @fn int rt_event_create(RT_EVENT *event,const char *name,unsigned long ivalue,int mode) * @brief Create an event group. * * Event groups provide for task synchronization by allowing a set of * flags (or "events") to be waited for and posted atomically. An * event group contains a mask of received events; any set of bits * from the event mask can be pended or posted in a single operation. * * Tasks can wait for a conjunctive (AND) or disjunctive (OR) set of * events to occur. A task pending on an event group in conjunctive * mode is woken up as soon as all awaited events are set in the event * mask. A task pending on an event group in disjunctive mode is woken * up as soon as any awaited event is set in the event mask. * @param event The address of an event group descriptor Xenomai will * use to store the event-related data. This descriptor must always * be valid while the group is active therefore it must be allocated * in permanent memory. * * @param name An ASCII string standing for the symbolic name of the * group. 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 event group. * * @param ivalue The initial value of the group's event mask. * * @param mode The event group creation mode. The following flags can * be OR'ed into this bitmask, each of them affecting the new group: * * - EV_FIFO makes tasks pend in FIFO order on the event group. * * - EV_PRIO makes tasks pend in priority order on the event group. * * @return 0 is returned upon success. Otherwise: * * - -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. * * - -ENOMEM is returned if the system fails to get enough dynamic * memory from the global real-time heap in order to register the * event group. * * Environments: * * This service can be called from: * * - Kernel module initialization/cleanup code * - Kernel-based task * - User-space task * * Rescheduling: possible. */int rt_event_create (RT_EVENT *event, const char *name, unsigned long ivalue, int mode){ int err = 0; if (xnpod_asynch_p()) return -EPERM; xnsynch_init(&event->synch_base,mode & EV_PRIO); event->value = ivalue; event->handle = 0; /* i.e. (still) unregistered event. */ event->magic = XENO_EVENT_MAGIC; xnobject_copy_name(event->name,name);#if defined(__KERNEL__) && defined(CONFIG_XENO_OPT_PERVASIVE) event->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 = &__event_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(event->name,sizeof(event->name),(void*)event); pnode = NULL; } err = xnregistry_enter(event->name,event,&event->handle,pnode); if (err) rt_event_delete(event); }#endif /* CONFIG_XENO_OPT_REGISTRY */ return err;}/** * @fn int rt_event_delete(RT_EVENT *event) * @brief Delete an event group. * * Destroy an event group and release all the tasks currently pending * on it. An event group exists in the system since rt_event_create() * has been called to create it, so this service must be called in * order to destroy it afterwards. * * @param event The descriptor address of the affected event group. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a event is not a event group descriptor. * * - -EIDRM is returned if @a event is a deleted event group 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_event_delete (RT_EVENT *event){ int err = 0, rc; spl_t s; if (xnpod_asynch_p()) return -EPERM; xnlock_get_irqsave(&nklock,s); event = xeno_h2obj_validate(event,XENO_EVENT_MAGIC,RT_EVENT); if (!event) { err = xeno_handle_error(event,XENO_EVENT_MAGIC,RT_EVENT); goto unlock_and_exit; } rc = xnsynch_destroy(&event->synch_base);#ifdef CONFIG_XENO_OPT_REGISTRY if (event->handle) xnregistry_remove(event->handle);#endif /* CONFIG_XENO_OPT_REGISTRY */ xeno_mark_deleted(event); 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_event_signal(RT_EVENT *event,unsigned long mask) * @brief Post an event group. * * Post a set of bits to the event mask. All tasks having their wait * request fulfilled by the posted events are resumed. * * @param event The descriptor address of the affected event. * * @param mask The set of events to be posted. * * @return 0 is returned upon success. Otherwise: * * - -EINVAL is returned if @a event is not an event group descriptor. * * - -EIDRM is returned if @a event is a deleted event group 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_event_signal (RT_EVENT *event, unsigned long mask){ xnpholder_t *holder, *nholder; int err = 0, resched = 0; spl_t s; xnlock_get_irqsave(&nklock,s); event = xeno_h2obj_validate(event,XENO_EVENT_MAGIC,RT_EVENT); if (!event) { err = xeno_handle_error(event,XENO_EVENT_MAGIC,RT_EVENT); goto unlock_and_exit; } /* Post the flags. */ event->value |= mask; /* And wakeup any sleeper having its request fulfilled. */ nholder = getheadpq(xnsynch_wait_queue(&event->synch_base)); while ((holder = nholder) != NULL) { RT_TASK *sleeper = thread2rtask(link2thread(holder,plink)); int mode = sleeper->wait_args.event.mode; unsigned long bits = sleeper->wait_args.event.mask; if (((mode & EV_ANY) && (bits & event->value) != 0) || (!(mode & EV_ANY) && ((bits & event->value) == bits))) { sleeper->wait_args.event.mask = (bits & event->value); nholder = xnsynch_wakeup_this_sleeper(&event->synch_base,holder); resched = 1; } else nholder = nextpq(xnsynch_wait_queue(&event->synch_base),holder); } if (resched) xnpod_schedule(); unlock_and_exit: xnlock_put_irqrestore(&nklock,s); return err;}/** * @fn int rt_event_wait(RT_EVENT *event,unsigned long mask,unsigned long *mask_r,int mode,RTIME timeout) * @brief Pend on an event group.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -