一.freertos是实时操作系统.谈到系统,你能想到什么...不需要过多的脑补,任务和线程组织,调度,切换.
系统如何组织,如何调度,如何切换?这就像一个城市的运转一样,其实都一样.
这篇文章先来谈谈组织这件事.
组织什么?无非是任务或者线程?什么是线程,我们姑且当做是路人甲已丙丁.
那么甲乙丙丁如何组织了,有请重要的嘉宾出场---列表
what,s 列表???
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE
volatile UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex;
MiniListItem_t xListEnd;
listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;
噢,原来这就是列表.
listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE是列表完整检查项,类似你家大门的锁,查看是否列表被破坏.
uxNumberOfItems表示列表有几个成员
pxIndex是一个指针,指向列表项.对于列表而言永远指向xListEnd成员?为什么,接着看看呗
xListEnd是列表项的兄弟,缺胳膊少腿.
那我们看下列表项是啥玩意>>
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
void * pvOwner;
struct xLIST * configLIST_VOLATILE pxContainer;
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
列表项的兄弟比列表项少了pvOwner和pxContainer成员.
xItemValue表示列表项记录的数值.嗯,什么数值,对于线程那说可能是优先级吗?利用他来排序,很有可能.
pxNext和pxPrevious是列表指针
pvOwner表示一个void *.从名字看有归属的意思,归属任务还是什么?
pxContainer一个列表指针
了解完成员,列表项兄弟和列表项区别在哪?列表项兄弟要偷懒了,他不干活(没有归属,没有列表),猜测下-可能是个标识
接下来,看看你们有什么神通广大.
二.无非就是创建,删除,链表当然有插入和移除咯.
1.创建
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.xItemValue = portMAX_DELAY;
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
void vListInitialiseItem( ListItem_t * const pxItem )
{
pxItem->pxContainer = NULL;
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
很简单吧.
2.插入.
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
{
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++;
}
首先找到插入点,插入点根据xValueOfInsertion得到.升序排列.
然后直接插入,再把当前的列表项指向列表.最后列表成员加1.
3.移除
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
mtCOVERAGE_TEST_DELAY();
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pxContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}
移除也很简单.
三:思考与总结
列表通过列表项的xItemValue链接起来,并且每个列表项有一个指向列表的指针,通过这个指针可以快速定位到列表,以便快速获取首位列表项,从而进行下一步操作.
列表项还有一个pvOwner成员.到这里猜测是指向某个事物,比如任务,队列,timer.
那么通过列表,查找到列表项,然后在找到具体事物,思路渐渐变得清晰起来.