/* ---------------------------------------------------------------------------- * Copyright (c) Huawei Technologies Co., Ltd. 2013-2020. All rights reserved. * Description: Event * Author: Huawei LiteOS Team * Create: 2013-01-01 * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * --------------------------------------------------------------------------- */ /*这段代码是关于事件管理的实现,包括事件的初始化、读取、写入、清除等操作。*/ #include "los_event_pri.h" #include "los_task_pri.h" #include "los_spinlock.h" #include "los_mp_pri.h" #include "los_percpu_pri.h" #include "los_trace.h" #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* __cplusplus */ //LOS_EventInit()函数用于初始化事件控制块(eventCB),并将事件ID、事件列表等属性设置为初始值 LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB) { UINT32 intSave; LOS_TRACE(EVENT_CREATE, (UINTPTR)eventCB); if (eventCB == NULL) { return LOS_ERRNO_EVENT_PTR_NULL; } intSave = LOS_IntLock(); eventCB->uwEventID = 0; LOS_ListInit(&eventCB->stEventList); LOS_IntRestore(intSave); return LOS_OK; } //OsEventParamCheck()函数用于检查参数的有效性,包括事件掩码(eventMask)、模式(mode)等 LITE_OS_SEC_TEXT STATIC UINT32 OsEventParamCheck(const VOID *ptr, UINT32 eventMask, UINT32 mode) { if (ptr == NULL) { return LOS_ERRNO_EVENT_PTR_NULL; } if (eventMask == 0) { return LOS_ERRNO_EVENT_EVENTMASK_INVALID; } if (eventMask & LOS_ERRTYPE_ERROR) { return LOS_ERRNO_EVENT_SETBIT_INVALID; } if (((mode & LOS_WAITMODE_OR) && (mode & LOS_WAITMODE_AND)) || (mode & ~(LOS_WAITMODE_OR | LOS_WAITMODE_AND | LOS_WAITMODE_CLR)) || !(mode & (LOS_WAITMODE_OR | LOS_WAITMODE_AND))) { return LOS_ERRNO_EVENT_FLAGS_INVALID; } //指针非空,事件掩码非0,事件掩码不包含LOS_ERRTYPE_ERROR标志位,模式合法 return LOS_OK; } //OsEventPoll()函数用于轮询事件,根据指定的事件掩码和模式判断是否满足条件 LITE_OS_SEC_TEXT STATIC UINT32 OsEventPoll(UINT32 *eventId, UINT32 eventMask, UINT32 mode) { UINT32 ret = 0; LOS_ASSERT(ArchIntLocked()); LOS_ASSERT(LOS_SpinHeld(&g_taskSpin)); if (mode & LOS_WAITMODE_OR) { if ((*eventId & eventMask) != 0) { ret = *eventId & eventMask; } } else { if ((eventMask != 0) && (eventMask == (*eventId & eventMask))) { ret = *eventId & eventMask; } } if (ret && (mode & LOS_WAITMODE_CLR)) { *eventId = *eventId & ~ret; } return ret; } //OsEventReadCheck()函数用于检查事件读取操作的参数有效性,包括事件控制块(eventCB)、事件掩码(eventMask)、模式(mode)等 LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadCheck(const PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode) { UINT32 ret; LosTaskCB *runTask = NULL; ret = OsEventParamCheck(eventCB, eventMask, mode); if (ret != LOS_OK) { return ret; } if (OS_INT_ACTIVE) { return LOS_ERRNO_EVENT_READ_IN_INTERRUPT; } runTask = OsCurrTaskGet(); if (runTask->taskFlags & OS_TASK_FLAG_SYSTEM) { PRINT_DEBUG("Warning: DO NOT recommend to use LOS_EventRead or OsEventReadOnce in system tasks.\n"); } return LOS_OK; } //OsEventReadImp()函数是事件读取的实现,根据指定的事件掩码和模式进行轮询,并根据超时时间和是否只读取一次进行相应的操作 LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout, BOOL once, UINT32 *intSave) { UINT32 ret = 0; LosTaskCB *runTask = OsCurrTaskGet(); if (once == FALSE) { ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode); } if (ret == 0) { if (timeout == 0) { return ret; } if (!OsPreemptableInSched()) { return LOS_ERRNO_EVENT_READ_IN_LOCK; } runTask->eventMask = eventMask; runTask->eventMode = mode; OsTaskWait(&eventCB->stEventList, OS_TASK_STATUS_PEND, timeout); /* * it will immediately do the scheduling, so there's no need to release the * task spinlock. when this task's been rescheduled, it will be holding the spinlock. */ OsSchedResched(); SCHEDULER_UNLOCK(*intSave); SCHEDULER_LOCK(*intSave); if (runTask->taskStatus & OS_TASK_STATUS_TIMEOUT) { runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; return LOS_ERRNO_EVENT_READ_TIMEOUT; } ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode); } return ret; } //OsEventRead()函数是对外提供的事件读取接口,调用OsEventReadCheck()和OsEventReadImp()实现事件的读取操作 LITE_OS_SEC_TEXT STATIC UINT32 OsEventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout, BOOL once) { UINT32 ret; UINT32 intSave; ret = OsEventReadCheck(eventCB, eventMask, mode); if (ret != LOS_OK) { return ret; } LOS_TRACE(EVENT_READ, (UINTPTR)eventCB, eventCB->uwEventID, eventMask, mode, timeout); SCHEDULER_LOCK(intSave); ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once, &intSave); SCHEDULER_UNLOCK(intSave); return ret; } //OsEventWrite()函数用于向事件控制块中写入指定的事件 LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events, BOOL once) { LosTaskCB *resumedTask = NULL; LosTaskCB *nextTask = NULL; UINT32 intSave; UINT8 exitFlag = 0; if (eventCB == NULL) { return LOS_ERRNO_EVENT_PTR_NULL; } if (events & LOS_ERRTYPE_ERROR) { return LOS_ERRNO_EVENT_SETBIT_INVALID; } LOS_TRACE(EVENT_WRITE, (UINTPTR)eventCB, eventCB->uwEventID, events); SCHEDULER_LOCK(intSave); eventCB->uwEventID |= events; if (!LOS_ListEmpty(&eventCB->stEventList)) { for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList); &resumedTask->pendList != &eventCB->stEventList;) { nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList); if (((resumedTask->eventMode & LOS_WAITMODE_OR) && ((resumedTask->eventMask & events) != 0)) || ((resumedTask->eventMode & LOS_WAITMODE_AND) && ((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) { exitFlag = 1; OsTaskWake(resumedTask, OS_TASK_STATUS_PEND); } if (once == TRUE) { break; } resumedTask = nextTask; } } SCHEDULER_UNLOCK(intSave); if (exitFlag == 1) { LOS_MpSchedule(OS_MP_CPU_ALL); LOS_Schedule(); } return LOS_OK; } //LOS_EventPoll()函数是对外提供的事件轮询接口,调用OsEventParamCheck()和OsEventPoll()实现事件的轮询操作 LITE_OS_SEC_TEXT UINT32 LOS_EventPoll(UINT32 *eventId, UINT32 eventMask, UINT32 mode) { UINT32 ret; UINT32 intSave; ret = OsEventParamCheck((VOID *)eventId, eventMask, mode); if (ret != LOS_OK) { return ret; } SCHEDULER_LOCK(intSave); ret = OsEventPoll(eventId, eventMask, mode); SCHEDULER_UNLOCK(intSave); return ret; } //LOS_EventRead()函数是对外提供的事件读取接口,调用OsEventRead()实现事件的读取操作 LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout) { return OsEventRead(eventCB, eventMask, mode, timeout, FALSE); } //LOS_EventWrite()函数是对外提供的事件写入接口,调用OsEventWrite()实现事件的写入操作 LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events) { return OsEventWrite(eventCB, events, FALSE); } //LOS_EventDestroy()函数用于销毁事件控制块,将事件ID设置为0 LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB) { UINT32 intSave; UINT32 ret = LOS_OK; if (eventCB == NULL) { return LOS_ERRNO_EVENT_PTR_NULL; } SCHEDULER_LOCK(intSave); if (!LOS_ListEmpty(&eventCB->stEventList)) { ret = LOS_ERRNO_EVENT_SHOULD_NOT_DESTORY; goto OUT; } eventCB->uwEventID = 0; OUT: SCHEDULER_UNLOCK(intSave); LOS_TRACE(EVENT_DELETE, (UINTPTR)eventCB, ret); return ret; } //LOS_EventClear()函数用于清除指定的事件 LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 events) { UINT32 intSave; if (eventCB == NULL) { return LOS_ERRNO_EVENT_PTR_NULL; } LOS_TRACE(EVENT_CLEAR, (UINTPTR)eventCB, eventCB->uwEventID, events); SCHEDULER_LOCK(intSave); eventCB->uwEventID &= events; SCHEDULER_UNLOCK(intSave); return LOS_OK; } //OsEventWriteOnce()函数是事件写入的实现,与OsEventWrite()类似,但只写入一次 LITE_OS_SEC_TEXT_MINOR UINT32 OsEventWriteOnce(PEVENT_CB_S eventCB, UINT32 events) { return OsEventWrite(eventCB, events, TRUE); } #ifdef LOSCFG_COMPAT_POSIX //OsEventReadOnce()函数是事件读取的实现,与OsEventRead()类似,但只读取一次 LITE_OS_SEC_TEXT_MINOR UINT32 OsEventReadOnce(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout) { return OsEventRead(eventCB, eventMask, mode, timeout, TRUE); } // /OsEventReadWithCond()函数用于根据条件读取事件,只有当条件满足时才进行事件读取操作 LITE_OS_SEC_TEXT UINT32 OsEventReadWithCond(const EventCond *cond, PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout) { UINT32 ret; UINT32 intSave; ret = OsEventReadCheck(eventCB, eventMask, mode); if (ret != LOS_OK) { return ret; } SCHEDULER_LOCK(intSave); if (*cond->realValue != cond->value) { eventCB->uwEventID &= cond->clearEvent; goto OUT; } ret = OsEventReadImp(eventCB, eventMask, mode, timeout, FALSE, &intSave); OUT: SCHEDULER_UNLOCK(intSave); return ret; } #endif #ifdef __cplusplus #if __cplusplus } #endif #endif /* __cplusplus */