You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
LiteOS-Reading/src/kernel/base/los_event.c

343 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* ----------------------------------------------------------------------------
* 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 */