/* * Copyright (c) 2020 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ /** * @file: event.c * @brief: event file * @version: 1.0 * @author: AIIT XUOS Lab * @date: 2020/3/15 * */ #include DECLARE_ID_MANAGER(k_event_id_manager, ID_NUM_MAX); DoubleLinklistType k_event_list ={&k_event_list, &k_event_list}; static int32 _EventCreate(uint32 options) { int32 id = 0; x_base lock = 0; struct Event *event = NONE; event = (struct Event *)x_malloc(sizeof(struct Event)); if (event == NONE) return -ENOMEMORY; memset(event, 0, sizeof(struct Event)); lock = CriticalAreaLock(); id = IdInsertObj(&k_event_id_manager, &event->id); if (id < 0) { CriticalAreaUnLock(lock); x_free(event); return -ENOMEMORY; } event->options = options; InitDoubleLinkList(&event->pend_list); DoubleLinkListInsertNodeAfter(&k_event_list, &event->link); CriticalAreaUnLock(lock); return id; } static void _EventDelete(struct Event *event) { int resched = 0; x_base lock = 0; NULL_PARAM_CHECK(event); if (!IsDoubleLinkListEmpty(&event->pend_list)) { resched = 1; LinklistResumeAll(&event->pend_list); } lock = CriticalAreaLock(); IdRemoveObj(&k_event_id_manager, event->id.id); DoubleLinkListRmNode(&event->link); CriticalAreaUnLock(lock); x_free(event); if (resched) DO_KTASK_ASSIGN; } static int32 _EventTrigger(struct Event *event, uint32 events) { x_bool resched; x_ubase lock = 0; x_base status = 0; struct TaskDescriptor *task = NONE; struct SysDoubleLinklistNode *n = NONE; NULL_PARAM_CHECK(event); if (events == 0) return -ERROR; resched = RET_FALSE; lock = CriticalAreaLock(); event->events |= events; if (IsDoubleLinkListEmpty(&event->pend_list)) { CriticalAreaUnLock(lock); return EOK; } n = event->pend_list.node_next; while (n != &(event->pend_list)) { task = SYS_DOUBLE_LINKLIST_ENTRY(n, struct TaskDescriptor, task_dync_sched_member.sched_link); status = -ERROR; if (task->event_mode & EVENT_AND) { if ((task->event_id_trigger & (event->events & EVENT_EVENTS_MASK)) == task->event_id_trigger) status = EOK; } else if (task->event_mode & EVENT_OR) { if (task->event_id_trigger & (event->events & EVENT_EVENTS_MASK)) { task->event_id_trigger = task->event_id_trigger & (event->events & EVENT_EVENTS_MASK); status = EOK; } } n = n->node_next; if (status == EOK) { if (task->event_mode & EVENT_AUTOCLEAN) event->events &= ~task->event_id_trigger; KTaskWakeup(task->id.id); resched = RET_TRUE; } } CriticalAreaUnLock(lock); if (resched == RET_TRUE) DO_KTASK_ASSIGN; return EOK; } static int32 _EventProcess(struct Event *event, uint32 events, uint32 options, int32 msec, uint32 *processed) { x_ubase lock = 0; x_base status = 0; int32 timeout = 0; struct TaskDescriptor *task = NONE; KDEBUG_IN_KTASK_CONTEXT; NULL_PARAM_CHECK(event); if (events == 0) return -ERROR; status = -ERROR; task = GetKTaskDescriptor(); task->exstatus = EOK; timeout = CalculteTickFromTimeMs(msec); lock = CriticalAreaLock(); if (options & EVENT_AND) { if ((event->events & events) == events) status = EOK; } else if (options & EVENT_OR) { if (event->events & events) status = EOK; } else { CHECK(0); } if (status == EOK) { if (processed) *processed = (event->events & events); if (options & EVENT_AUTOCLEAN) event->events &= ~events; } else if (timeout == 0) { task->exstatus = -ETIMEOUT; } else { task->event_id_trigger = (events & EVENT_EVENTS_MASK); task->event_mode = (options & EVENT_OPTIONS_MASK); LinklistSuspend(&(event->pend_list), task, event->options); if (timeout > 0) KTaskSetDelay(task,timeout); CriticalAreaUnLock(lock); DO_KTASK_ASSIGN; if (task->exstatus != EOK) return task->exstatus; lock = CriticalAreaLock(); if (processed) *processed = task->event_id_trigger; } CriticalAreaUnLock(lock); return task->exstatus; } static EventDoneType done = { .EventCreate = _EventCreate, .EventDelete = _EventDelete, .EventTrigger = _EventTrigger, .EventProcess = _EventProcess, }; static struct Event *FindEventById(int32 id) { x_base lock = 0; struct IdNode *idnode = NONE; struct Event *event = NONE; if (id < 0) return NONE; lock = CriticalAreaLock(); idnode = IdGetObj(&k_event_id_manager, id); if (idnode == NONE) { CriticalAreaUnLock(lock); return NONE; } event = CONTAINER_OF(idnode, struct Event, id); CriticalAreaUnLock(lock); return event; } /** * This function will create a event. * * @param options the trigger way of event. * * @return id */ int32 KEventCreate(uint32 options) { KDEBUG_NOT_IN_INTERRUPT; return done.EventCreate(options); } /** * This function will delete a event. * * @param id the id number of event. * * @return */ void KEventDelete(int32 id) { KDEBUG_NOT_IN_INTERRUPT; struct Event *event = FindEventById(id); if (event == NONE) return; done.EventDelete(event); } /** * This function will trigger the event * * @param id the id number of event * @param events trigger way & events flag * * @return EOK on success. */ int32 KEventTrigger(int32 id, uint32 events) { KDEBUG_NOT_IN_INTERRUPT; struct Event *event = FindEventById(id); if (event == NONE) return -ERROR; return done.EventTrigger(event, events); } /** * This function will get the event and process this event * * @param id the id number of event * @param events events flag * @param options trigger way * @param msec timeout * @processed event processed flag * * @return EOK on success. */ int32 KEventProcess(int32 id, uint32 events, uint32 options, int32 msec, uint32 *processed) { KDEBUG_NOT_IN_INTERRUPT; struct Event *event = FindEventById(id); return done.EventProcess(event, events, options, msec, processed); }