赞
踩
事件(event)作为OSEK的OS对象,主要用于拓展任务的同步,即使得拓展任务进入或离开等待状态(waiting state)。更直白地来说,事件可以用于唤醒等待状态的任务,使之进入就绪态,或者使得当前任务进入等待状态。显然,前者通过系统接口SetEvent来实现,而后者则是通过WaitEvent来实现。
涉及到事件的系统接口主要有以下几个:
- /* TaskID: Reference to the task for which one or several events are to be set */
- /* Mask: Mask of the events to be set */
- StatusType SetEvent ( TaskType <TaskID>, EventMaskType <Mask> )
-
- /* Mask: Mask of the events to be cleared */
- StatusType ClearEvent ( EventMaskType <Mask> )
-
- /* TaskID: Task whose event mask is to be returned */
- /* Event Reference to the memory of the return data */
- /* This service returns the current state of all event bits of the task <TaskID>, not the events that the task is waiting for */
- StatusType GetEvent ( TaskType <TaskID>, EventMaskRefType <Event> )
-
- /* Mask Mask of the events waited for */
- StatusType WaitEvent ( EventMaskType <Mask> )
此外,从以上API就可以看出,在OSEK中,事件作为一种受OS管控的对象,可以由任意任务或二类中断设置发起(SetEvent),即事件的触发时全局的,无归属权限制的;但event的处理权,包括等待和清除,完全在其所归属的任务手中,即事件并非独立的OS对象,而是静态分配给指定的拓展任务的。就其本质来说,事件的本质是通知机制,当事件被发起时,若事件的归属任务没有被挂起,则相当于将事件的状态变化直接通知到该拓展任务;当接收到事件发起的通知时,若该二类任务处于等待状态(waiting state),则会进入就绪态(ready state),若该二类任务处于运行态(running state),则仍然会保持在运行态。
因此,SetEvent需要TaskID作为输入参数,而ClearEvent 和WaitEvent 则不需要,且只可在event所属的拓展任务来调用。在拓展任务中调用清除和等待事件,默认处理的是本任务的事件;而事件的状态是以掩码的形式来管理的,即对应的可以是一个事件组/集合。也就是说,一个拓展任务可以等待多个专属于自己的事件。
如图1所示,在支持优先级抢占的拓展任务间的事件同步场景中,T1的优先级较高,较低优先级的任务T2通过SetEvent接口通知(唤醒)T1,以达到任务间同步的效果。
图1 抢占式拓展任务间的事件同步
其中,scheduler演示了响应的任务调度点,event of extended task T1指示了T1的event的时域状态变化。显然,在T2发起事件后,随即就触发了任务调度,T1抢占了T2,进入运行态,而T2失去了CPU的使用权,退回了就绪态(没有受资源阻塞,并非等待态,而是退回就绪态);当T1清除完事件,并重新等待事件后,T1受资源阻塞,退回了等待状态,进而触发系统调度,使得T2重新进入运行态。
在非抢占式调度下,只有在任务主动让出CPU或显式地强制发起重调度时,才会触发任务上下文切换,其事件同步的场景如图2所示。
图2 非抢占式拓展任务间的事件同步
在freeRTOS中,二进制信号量是通过队列来实现的,且每个二进制信号量都维护者两个任务列表,用于记录等待接收和等待设置发起该信号量(事件)的任务。
- List_t xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
- List_t xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
而每个任务的控制块(TCB)中由用于记录该任务的事件列表,如下所示:
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
显然,事件的作用和用于同步的二进制信号量属于同一范畴。更进一步地,freeRTOS提供了更轻量级的任务通知机制,即notify(通知)机制,其对应的数据结构也集成在了TCB当中,如下所示:
- #if ( configUSE_TASK_NOTIFICATIONS == 1 )
- volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
- volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
- #endif
显然,在实现方法上,notify机制和OSEK的事件机制相似度更高。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。