los_event.c 14.5 KB
Newer Older
1
/*
2 3
 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *
 * 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.h"
#include "los_percpu_pri.h"
37
#include "los_sched_pri.h"
38 39 40 41
#if (LOSCFG_BASE_CORE_SWTMR == YES)
#include "los_exc.h"
#endif

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/******************************************************************************
事件(Event)是一种任务间通信的机制,可用于任务间的同步。
	多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。
	一对多同步模型:一个任务等待多个事件的触发。可以是任意一个事件发生时唤醒任务处理事件,也可以是几个事件都发生后才唤醒任务处理事件。
	多对多同步模型:多个任务等待多个事件的触发。

事件特点
	任务通过创建事件控制块来触发事件或等待事件。
	事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。
	事件仅用于任务间的同步,不提供数据传输功能。
	多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。
	多个任务可以对同一事件进行读写操作。
	支持事件读写超时机制。

事件读取模式
	在读事件时,可以选择读取模式。读取模式如下:
	所有事件(LOS_WAITMODE_AND):逻辑与,基于接口传入的事件类型掩码eventMask,
		只有这些事件都已经发生才能读取成功,否则该任务将阻塞等待或者返回错误码。
	任一事件(LOS_WAITMODE_OR):逻辑或,基于接口传入的事件类型掩码eventMask,
		只要这些事件中有任一种事件发生就可以读取成功,否则该任务将阻塞等待或者返回错误码。
	清除事件(LOS_WAITMODE_CLR):这是一种附加读取模式,需要与所有事件模式或任一事件模式结合
		使用(LOS_WAITMODE_AND | LOS_WAITMODE_CLR或 LOS_WAITMODE_OR | LOS_WAITMODE_CLR)。在这种模式下,
		当设置的所有事件模式或任一事件模式读取成功后,会自动清除事件控制块中对应的事件类型位。

运作机制
	任务在调用LOS_EventRead接口读事件时,可以根据入参事件掩码类型eventMask读取事件的单个或者多个事件类型。
		事件读取成功后,如果设置LOS_WAITMODE_CLR会清除已读取到的事件类型,反之不会清除已读到的事件类型,需显式清除。
		可以通过入参选择读取模式,读取事件掩码类型中所有事件还是读取事件掩码类型中任意事件。
	任务在调用LOS_EventWrite接口写事件时,对指定事件控制块写入指定的事件类型,
		可以一次同时写多个事件类型。写事件会触发任务调度。
	任务在调用LOS_EventClear接口清除事件时,根据入参事件和待清除的事件类型,
		对事件对应位进行清0操作。		
		
使用场景
	事件可应用于多种任务同步场景,在某些同步场景下可替代信号量。

注意事项
	在系统初始化之前不能调用读写事件接口。如果调用,系统运行会不正常。
	在中断中,可以对事件对象进行写操作,但不能进行读操作。
	在锁任务调度状态下,禁止任务阻塞于读事件。
	LOS_EventClear 入参值是:要清除的指定事件类型的反码(~events)。
	为了区别LOS_EventRead接口返回的是事件还是错误码,事件掩码的第25位不能使用。
******************************************************************************/
85
//初始化一个事件控制块
86 87 88 89 90 91 92 93
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
    UINT32 intSave;

    if (eventCB == NULL) {
        return LOS_ERRNO_EVENT_PTR_NULL;
    }

94
    intSave = LOS_IntLock();//锁中断
95
    eventCB->uwEventID = 0;
96
    LOS_ListInit(&eventCB->stEventList);//事件链表初始化
97
    LOS_IntRestore(intSave);//恢复中断
98 99
    return LOS_OK;
}
100
//事件参数检查
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
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;
    }
    return LOS_OK;
}
122
//根据用户传入的事件值、事件掩码及校验模式,返回用户传入的事件是否符合预期
123 124 125 126
LITE_OS_SEC_TEXT UINT32 OsEventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode)
{
    UINT32 ret = 0;

127 128
    LOS_ASSERT(OsIntLocked());//断言不允许中断了
    LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));//任务自旋锁
129

130
    if (mode & LOS_WAITMODE_OR) {//如果模式是读取掩码中任意事件
131 132 133
        if ((*eventID & eventMask) != 0) {
            ret = *eventID & eventMask;
        }
134 135
    } else {//等待全部事件发生
        if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) {//必须满足全部事件发生
136 137 138 139
            ret = *eventID & eventMask;
        }
    }

140
    if (ret && (mode & LOS_WAITMODE_CLR)) {//读取完成后清除事件
141 142 143 144 145
        *eventID = *eventID & ~ret;
    }

    return ret;
}
146
//检查读事件
147 148 149 150 151
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadCheck(const PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode)
{
    UINT32 ret;
    LosTaskCB *runTask = NULL;

152
    ret = OsEventParamCheck(eventCB, eventMask, mode);//事件参数检查
153 154 155 156
    if (ret != LOS_OK) {
        return ret;
    }

157 158
    if (OS_INT_ACTIVE) {//中断正在进行
        return LOS_ERRNO_EVENT_READ_IN_INTERRUPT;//不能在中断发送时读事件
159 160
    }

161 162
    runTask = OsCurrTaskGet();//获取当前任务
    if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {//任务属于系统任务
163
        OsBackTrace();
164
        return LOS_ERRNO_EVENT_READ_IN_SYSTEM_TASK;//不能在系统任务中读取事件
165 166 167
    }
    return LOS_OK;
}
168
//读取指定事件类型的实现函数,超时时间为相对时间:单位为Tick
169 170 171 172 173 174 175
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
                                              UINT32 timeout, BOOL once)
{
    UINT32 ret = 0;
    LosTaskCB *runTask = OsCurrTaskGet();

    if (once == FALSE) {
176
        ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);//检测事件是否符合预期
177 178
    }

179 180
    if (ret == 0) {//不符合预期时
        if (timeout == 0) {//不等待的情况
181 182 183
            return ret;
        }

184
        if (!OsPreemptableInSched()) {//不能抢占式调度
185 186 187 188 189
            return LOS_ERRNO_EVENT_READ_IN_LOCK;
        }

        runTask->eventMask = eventMask;
        runTask->eventMode = mode;
190
        runTask->taskEvent = eventCB;//事件控制块
191 192 193
        OsTaskWaitSetPendMask(OS_TASK_WAIT_EVENT, eventMask, timeout);
        ret = OsSchedTaskWait(&eventCB->stEventList, timeout, TRUE);
        if (ret == LOS_ERRNO_TSK_TIMEOUT) {
194 195 196
            return LOS_ERRNO_EVENT_READ_TIMEOUT;
        }

197
        ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);//检测事件是否符合预期
198 199 200
    }
    return ret;
}
201
//读取指定事件类型,超时时间为相对时间:单位为Tick
202 203 204 205 206 207
LITE_OS_SEC_TEXT STATIC UINT32 OsEventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout,
                                           BOOL once)
{
    UINT32 ret;
    UINT32 intSave;

208
    ret = OsEventReadCheck(eventCB, eventMask, mode);//读取事件检查
209 210 211 212 213
    if (ret != LOS_OK) {
        return ret;
    }

    SCHEDULER_LOCK(intSave);
214
    ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once);//读事件实现函数
215 216 217
    SCHEDULER_UNLOCK(intSave);
    return ret;
}
218
//事件恢复操作
219 220
LITE_OS_SEC_TEXT STATIC UINT8 OsEventResume(LosTaskCB *resumedTask, const PEVENT_CB_S eventCB, UINT32 events)
{
221
    UINT8 exitFlag = 0;//是否唤醒
222 223 224

    if (((resumedTask->eventMode & LOS_WAITMODE_OR) && ((resumedTask->eventMask & events) != 0)) ||
        ((resumedTask->eventMode & LOS_WAITMODE_AND) &&
225 226
        ((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {//逻辑与 和 逻辑或 的处理
        exitFlag = 1; 
227 228

        resumedTask->taskEvent = NULL;
229 230
        OsTaskWakeClearPendMask(resumedTask);
        OsSchedTaskWake(resumedTask);
231 232 233 234
    }

    return exitFlag;
}
235
//以不安全的方式写事件
236 237 238 239 240 241
LITE_OS_SEC_TEXT VOID OsEventWriteUnsafe(PEVENT_CB_S eventCB, UINT32 events, BOOL once, UINT8 *exitFlag)
{
    LosTaskCB *resumedTask = NULL;
    LosTaskCB *nextTask = NULL;
    BOOL schedFlag = FALSE;

242 243
    eventCB->uwEventID |= events;//对应位贴上标签
    if (!LOS_ListEmpty(&eventCB->stEventList)) {//等待事件链表判断,处理等待事件的任务
244
        for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList);
245 246 247 248
             &resumedTask->pendList != &eventCB->stEventList;) {//循环获取任务链表
            nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList);//获取任务实体
            if (OsEventResume(resumedTask, eventCB, events)) {//是否恢复任务
                schedFlag = TRUE;//任务已加至就绪队列,申请发生一次调度
249
            }
250 251
            if (once == TRUE) {//是否只处理一次任务
                break;//退出循环
252
            }
253
            resumedTask = nextTask;//检查链表中下一个任务
254 255 256
        }
    }

257
    if ((exitFlag != NULL) && (schedFlag == TRUE)) {//是否让外面调度
258 259 260
        *exitFlag = 1;
    }
}
261
//写入事件
262 263 264 265 266 267 268 269 270 271 272 273 274
LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events, BOOL once)
{
    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;
    }

275 276 277
    SCHEDULER_LOCK(intSave);	//禁止调度
    OsEventWriteUnsafe(eventCB, events, once, &exitFlag);//写入事件
    SCHEDULER_UNLOCK(intSave);	//允许调度
278

279 280 281
    if (exitFlag == 1) { //需要发生调度
        LOS_MpSchedule(OS_MP_CPU_ALL);//通知所有CPU调度
        LOS_Schedule();//执行调度
282 283 284
    }
    return LOS_OK;
}
285
//根据用户传入的事件值、事件掩码及校验模式,返回用户传入的事件是否符合预期
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
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;
}
301
//读取指定事件类型,超时时间为相对时间:单位为Tick
302 303 304 305
LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout)
{
    return OsEventRead(eventCB, eventMask, mode, timeout, FALSE);
}
306
//写指定的事件类型
307 308 309 310
LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)
{
    return OsEventWrite(eventCB, events, FALSE);
}
311
//只读一次事件
312 313 314 315 316
LITE_OS_SEC_TEXT_MINOR UINT32 OsEventReadOnce(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
                                              UINT32 timeout)
{
    return OsEventRead(eventCB, eventMask, mode, timeout, TRUE);
}
317
//只写一次事件
318 319 320 321
LITE_OS_SEC_TEXT_MINOR UINT32 OsEventWriteOnce(PEVENT_CB_S eventCB, UINT32 events)
{
    return OsEventWrite(eventCB, events, TRUE);
}
322
//销毁指定的事件控制块
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)
{
    UINT32 intSave;

    if (eventCB == NULL) {
        return LOS_ERRNO_EVENT_PTR_NULL;
    }

    SCHEDULER_LOCK(intSave);
    if (!LOS_ListEmpty(&eventCB->stEventList)) {
        SCHEDULER_UNLOCK(intSave);
        return LOS_ERRNO_EVENT_SHOULD_NOT_DESTORY;
    }

    eventCB->uwEventID = 0;
    LOS_ListDelInit(&eventCB->stEventList);
    SCHEDULER_UNLOCK(intSave);

    return LOS_OK;
}
343
//清除指定的事件类型
344 345 346 347 348 349 350 351 352 353 354 355 356
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;
    }
    SCHEDULER_LOCK(intSave);
    eventCB->uwEventID &= events;
    SCHEDULER_UNLOCK(intSave);

    return LOS_OK;
}
357
//有条件式读事件
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
#ifdef LOSCFG_COMPAT_POSIX
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);
OUT:
    SCHEDULER_UNLOCK(intSave);
    return ret;
}
#endif