タスクとは何か
FreeRTOSにおけるタスクは、戻り値を持たず、無限ループで実行されるC言語関数として定義される。この関数は一度開始されると終了せず、システムのシャットダウンまたは明示的な削除まで継続的に動作する。
タスクの構成要素
1. タスクスタック
ベアメタル環境では全関数が共通のスタックを使用するが、RTOS環境では各タスクが独自のスタック領域を持つ。この領域は静的に確保されたグローバル配列、または動的に割り当てられたRAM上のメモリブロックとして実装される。
2. タスクリスト制御ブロック(TCB)
TCBはタスクの状態やコンテキストを管理するデータ構造であり、その中にxStateListItemなどのリストアイテムが含まれる。これはタスクをリスト構造に統合するための「フック」のような役割を果たす。
3. リスト構造
FreeRTOSでは双方向連結リストを用いてタスクやイベントを管理する。主な構造体は以下の通りである。
typedef struct xLIST {
UBaseType_t uxNumberOfItems;
ListItem_t *pxIndex;
MiniListItem_t xListEnd;
} List_t;
4. リストアイテム
リストアイテムには通常のListItem_tと軽量版のMiniListItem_tがある。
struct xLIST_ITEM {
TickType_t xItemValue;
struct xLIST_ITEM *pxNext;
struct xLIST_ITEM *pxPrevious;
void *pvOwner;
void *pvContainer;
};
struct xMINI_LIST_ITEM {
TickType_t xItemValue;
struct xLIST_ITEM *pxNext;
struct xLIST_ITEM *pxPrevious;
};
リストの初期化
リストはvListInitialise()で初期化され、終端マーカーとして機能するxListEndが自己参照する形で設定される。これにより空リストの判定が可能になる。
void vListInitialise(List_t *pxList) {
pxList->pxIndex = &(pxList->xListEnd);
pxList->xListEnd.xItemValue = portMAX_DELAY;
pxList->xListEnd.pxNext = &(pxList->xListEnd);
pxList->xListEnd.pxPrevious = &(pxList->xListEnd);
pxList->uxNumberOfItems = 0;
}
リストアイテムの挿入
vListInsert()はアイテムをソート順に挿入し、vListInsertEnd()はリスト末尾(現在のインデックスの直前)に挿入する。
void vListInsert(List_t *pxList, ListItem_t *pxNewListItem) {
TickType_t xValue = pxNewListItem->xItemValue;
ListItem_t *pxIterator = (xValue == portMAX_DELAY) ?
pxList->xListEnd.pxPrevious :
findInsertPosition(pxList, xValue);
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pvContainer = pxList;
pxList->uxNumberOfItems++;
}
static inline ListItem_t* findInsertPosition(List_t *pxList, TickType_t xValue) {
ListItem_t *it = &(pxList->xListEnd);
while (it->pxNext->xItemValue <= xValue) {
it = it->pxNext;
}
return it;
}
vListInsertEnd()はインデックス位置の直前に挿入することで、リスト走査時の取得順序を制御する。