首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

FreeRTOS分析(1)

FreeRTOS分析(1)

freertos是一个轻量级的rtos,它目前实现了一个微内核,并且port到arm7, avr, pic18, coldfire等众多处理器上;目前已经在rtos的市场上占有不少的份额。它当然不是一个与vxworks之类的rtos竞争的操作系统,它的目标在 于低性能小RAM的处理器上。整个系统只有3个文件,外加上port的和处理器相关的两个文件,实现是很简洁的。
与ucosii不同,它是free的,ucosii不是free的,虽然它的代码是公开的。FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理。FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、 优先级最高的任务先运行。FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。这一点是和ucosii不同的。
另外一点不同是freertos既可以配置为可抢占内核也可以配置为不可抢占内核。当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这 样可提高CPU的运行效率。
这篇文章是以freertos v5.0版本的代码为例子分析下它的任务管理方面的实现。时间关系可能没有太多时间写的很详细了。
1.链表管理
freertos里面的任务管理,queue,semaphore管理等都借助于双向链表,它定义了个通用的数据结构



struct xLIST_ITEM
{
    portTickType xItemValue; //链表节点的数据项,通常用在任务延时,表示                              //一个任务延时的节拍数      
    volatile struct xLIST_ITEM * pxNext; //通过这两个成员变量将所有节点
    volatile struct xLIST_ITEM * pxPrevious;//链接成双向链表  
    void * pvOwner;  //指向该item的所有者,通常是任务控制块            
    void * pvContainer; //指向此链表结点所在的链表                     
};
这个数据结构定义了一个通用的链表节点;下面的数据结构定义了一个双向链表
typedef struct xLIST
{
    volatile unsigned portBASE_TYPE uxNumberOfItems;//表示该链表中节点的数目
    volatile xListItem * pxIndex;//用于遍历链表,指向上次访问的节点         
    volatile xMiniListItem xListEnd;//链表尾结点
} xList;

而下面这个数据结构用在xList中,只是为了标记一个链表的尾,是一个marker
struct xMINI_LIST_ITEM
{
    portTickType xItemValue;
    volatile struct xLIST_ITEM *pxNext;
    volatile struct xLIST_ITEM *pxPrevious;
};
typedef struct xMINI_LIST_ITEM xMiniListItem;

对于链表的操作也定义了一系列的函数和宏,在list.c文件中。如初始化个链表,吧一个节点插入链表等。
初始化链表:
void vListInitialise( xList *pxList )
{
    /* The list structure contains a list item which is used to mark the
    end of the list.  To initialise the list the list end is inserted
    as the only list entry. */
    pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );

    /* The list end value is the highest possible value in the list to
    ensure it remains at the end of the list. */
    pxList->xListEnd.xItemValue = portMAX_DELAY;

    /* The list end next and previous pointers point to itself so we know
    when the list is empty. */
    pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
    pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );

    pxList->uxNumberOfItems = 0;
}
把一个节点插入到链表尾部:
void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )
{
volatile xListItem * pxIndex;

    /* Insert a new list item into pxList, but rather than sort the list,
    makes the new list item the last item to be removed by a call to
    pvListGetOwnerOfNextEntry.  This means it has to be the item pointed to by
    the pxIndex member. */
    pxIndex = pxList->pxIndex;

    pxNewListItem->pxNext = pxIndex->pxNext;
    pxNewListItem->pxPrevious = pxList->pxIndex;
    pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
    pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;
    pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;

    /* Remember which list the item is in. */
    pxNewListItem->pvContainer = ( void * ) pxList;

    ( pxList->uxNumberOfItems )++;
}
这些就不多说了。

2.任务控制块
typedef struct tskTaskControlBlock
{
       volatile portSTACK_TYPE     *pxTopOfStack;//指向堆栈顶
       xListItem                      xGenericListItem;   //通过它将任务连入就绪链表或者延时链表或者挂起链表中
       xListItem                      xEventListItem;//通过它把任务连入事件等待链表
       unsigned portBASE_TYPE    uxPriority;//优先级
       portSTACK_TYPE               *pxStack;              //指向堆栈起始位置
       signed portCHAR                 pcTaskName[ configMAX_TASK_NAME_LEN ];
       #if ( portCRITICAL_NESTING_IN_TCB == 1 )
              unsigned portBASE_TYPE uxCriticalNesting;
       #endif

       #if ( configUSE_TRACE_FACILITY == 1 )
              unsigned portBASE_TYPE    uxTCBNumber;//用于trace,debug时候提供方便
       #endif     

       #if ( configUSE_MUTEXES == 1 )
              unsigned portBASE_TYPE uxBasePriority;//当用mutex发生优先级反转时用
       #endif

       #if ( configUSE_APPLICATION_TASK_TAG == 1 )
              pdTASK_HOOK_CODE pxTaskTag;
       #endif

} tskTCB;
其中uxBasePriority用于解决优先级反转,freertos采用优先级继承的办法解决这个问题,在继承时,将任务原先的优先级保存在这个成员中,将来再从这里恢复任务的优先级。
继承事业,薪火相传
返回列表