The FreeRTOS kernel Scheduler uses a data structure that lists (list) extensively. If we want to explore the operating mechanism behind FreeRTOS, the first stumbling block is the list. For the FreeRTOS kernel, the list is the most basic part of it. In this chapter we focus on the structure of lists and list items, as well as the operation functions, and the knowledge points in this chapter are used when explaining task creation in the next chapter.
Lists are used by the FreeRTOS scheduler to track tasks, and tasks that are ready, suspended, and deferred will be attached to their respective lists. The user program can also use the list if needed.
The FreeRTOS list uses pointers to point to list items. There may be many list items under a list, and each list item has a pointer to the list. As shown in 1-1.
Figure 1-1: List and list items
The list item has two forms, the full-featured version of the list item Xlist_item and the mini-version of the list item Xmini_list_item. Let's look at their specific definitions and see the full-featured version first.
struct xlist_item{ listfirst_list_item_integrity_check_value/ * For detecting complete list item data */ Configlist_ volatileticktype_t Xitemvalue; /* List Item value */ struct xlist_item * configlist_volatile pxnext; /* point to the next list item in the list */ struct xlist_item * configlist_volatile pxprevious; /* point to the previous list item in the list */ void * Pvowner; /* point to a task tcb*/ void * Configlist_volatile Pvcontainer; /* Point to the list that contains the list item */ Listsecond_list_item_integrity_check_value/ * To detect whether the list item data is complete */};typedef struct XLIST_ ITEM listitem_t;
Macro Listfirst_list_item_integrity_check_value and Listsecond_list_item_integrity_check_value are used to check the integrity of the list item data. In Projdefs.h, if you set the macro configuse_list_data_integrity_check_bytes to 1, enable list item data integrity checks, the macro Listfirst_list_item_integrity_ Check_value and Listsecond_list_item_integrity_check_value will be replaced by two known values.
Xitemvalue is a list item value, which is usually a tracked task priority or a counter value for a scheduled event. This variable is configlist_volatile modified and configlist_volatile is mapped to the C keyword volatile, which indicates that the variable is "variable" and tells the compiler not to optimize the variable for code. Because the members of the list item may be updated in the Interrupt service program. About the volatile keyword, if not familiar, you can refer to my blog, "Writing high-quality embedded C program," section 3rd. 2.4.
Pxnext and Pxprevious are list item type pointers that are used to point to the next and previous list items in the list, and through these two pointers, the list items can form a similar doubly linked table structure.
The pointer pvowner usually points to a task TCB.
The pointer pvcontainer points to the list that contains the list item.
The mini-version of the list item Xmini_list_item is a subset of the full-featured list item Xlist_item, which is defined as follows:
struct xmini_list_item{ listfirst_list_item_integrity_check_value/ * For detecting complete list item data */ Configlist_ VOLATILE ticktype_t Xitemvalue; struct Xlist_item * configlist_volatile pxnext; struct Xlist_item * configlist_volatile pxprevious;}; typedef struct XMINI_LIST_ITEM minilistitem_t;
Now that you have a full-featured list item, why do you declare a mini-version of the list item? This is because the list structure requires a list item member, but does not require all the fields in the list item, so the mini-list item is there. The list structure body is defined as:
typedef struct xlist{ listfirst_list_integrity_check_value/ * is used to detect complete list item data */ Configlist_volatile ubasetype_t Uxnumberofitems; listitem_t * Configlist_volatile Pxindex; /* for traversing list */ minilistitem_t xlistend; /* List item */ Listsecond_list_integrity_check_value/ * To detect whether the list item data is complete */}list_t;
As with the list item definition, macros Listfirst_list_integrity_check_value and listsecond_list_integrity_check_value are used to check that the list item data is complete. In Projdefs.h, if you set the macro configuse_list_data_integrity_check_bytes to 1, enable list item data integrity checks, the macro Listfirst_list_item_integrity_ Check_value and Listsecond_list_item_integrity_check_value will be replaced by two known values.
Uxnumberofitems represents the number of list items that are hooked up in the list, and 0 indicates that the list is empty.
The list item type pointer is used to traverse the list, and after the list is initialized, the pointer points to &xlistend. Gets the next list item in the list by using Macro Listget_owner_of_next_entry ().
The list item xlistend is used to mark the end of the list. The xlistend.xitemvalue is initialized to a constant whose value is related to the hardware schema, 0xFFFF (16-bit architecture), or 0xFFFFFFFF (32-bit architecture).
Let's take a look at the list operation. Freerots provides several API functions for initializing list and list items as well as list item insertion operations.
1. Initialize the listThe list structure contains a list item member that is used primarily for the end of the tag list. The initialization list is the list item that is inserted into the list.
void Vlistinitialise (list_t * const pxlist) {/ * list index points to list items */ Pxlist->pxindex = (listitem_t *) & (PXLIST-&G T;xlistend); /* Set to maximum possible value */ pxlist->xlistend.xitemvalue =portmax_delay; /* List item xlistend Pxnext and pxprevious pointers point to it yourself */ Pxlist->xlistend.pxnext = (listitem_t *) & (pxlist-> Xlistend); pxlist->xlistend.pxprevious= (listitem_t *) & (pxlist->xlistend); Pxlist->uxnumberofitems = (ubasetype_t) 0U; /* Set to a known value to detect if the list data is complete * /Listset_list_integrity_check_1_value (pxlist); Listset_list_integrity_check_2_value (pxlist);}
If macro configuse_list_data_integrity_check_bytes is set to 1, enable list item data integrity Check, then macro Listset_list_integrity_check_1_value () And Listset_list_integrity_check_2_value are replaced by a known value, which defaults to 0X5A5A (16-bit architecture) or 0x5a5a5a5a (32-bit architecture).
Assume that the block list data integrity check is initialized as shown in Listing 1-2, Uxnumberofitems is initialized to 0,xlistend.xitemvalue initialized to 0xffffffff,pxindex, Xlistend.pxnext and xlistend.pxprevious are initialized to point to the list item xlistend.
Figure 1-2: The list after initialization
2. Initializing list items
The initial comparison of list items is simple, as long as you make sure that the list items are not in any list.
void Vlistinitialiseitem (listitem_t * const pxitem) { pxitem->pvcontainer = NULL; /* Set to a known value to detect whether the list item data is complete * /Listset_first_list_item_integrity_check_value (Pxitem); Listset_second_list_item_integrity_check_value (Pxitem);}
If the macro configuse_list_data_integrity_check_bytes is set to 1, the list item data integrity Check is enabled, then the macro Listfirst_list_item_integrity_check_ Value and Listsecond_list_item_integrity_check_value are replaced by two known values, which are either 0x5a5a (16-bit schemas) or 0x5a5a5a5a (32-bit schemas).
Assume that the block list item data integrity check is initialized after the list item 1-3 is shown. Just set the pointer pvcontainer to a null pointer, which is used to point to the list that contains the list item, which is set to NULL to indicate that the list item does not belong to any list.
Figure 1-3: List items after initialization
3. Insert the list item into the list, where the list item is located, depending on the list item value (xitemvalue) of the list item.
Each list item object has a list item value (Xitemvalue), which is usually a tracked task priority or a counter value for a scheduled event. Call the API function Vlistinsert (list_t * Const PXLIST, listitem_t * const Pxnewlistitem) To insert the list item that the Pxnewlistitem points to in the list that pxlist points to. The position of the list item in the list is determined by pxnewlistitem->xitemvalue, in descending order.
void Vlistinsert (list_t * Const PXLIST, listitem_t * const pxnewlistitem) {listitem_t *pxiterator;const ticktype_t xValue Ofinsertion = pxnewlistitem->xitemvalue; /* Check the integrity of the list and list item data only if the Configassert () definition is valid. */listtest_list_integrity (pxlist); Listtest_list_item_integrity (Pxnewlistitem); /* Insert a new list item into the list and insert the list in descending order based on the value of Xitemvalue. */if (xvalueofinsertion = = Portmax_delay) {pxiterator =pxlist->xlistend.pxprevious; } else {for (Pxiterator = (listitem_t *) & (pxlist->xlistend);p Xitera Tor->pxnext->xitemvalue <= xvalueofinsertion; Pxiterator =pxiterator->pxnext) {/* here is empty */} } Pxnewlistitem->pxnext =pxiterator->pxnext; Pxnewlistitem->pxnext->pxprevious= Pxnewlistitem; Pxnewlistitem->pxprevious =pxiterator; Pxiterator->pxnext = Pxnewlistitem; Pxnewlistitem->pvcontainer = (void*) pxlist; (pxlist->uxnumberofitems) + +;}
Inserts a new list item into the list based on the value of Xitemvalue. If there is a list item with the same Xitemvalue value as the new list item, the newly inserted list item is behind it. If the Xitemvalue value of the list item equals Portmax_delay (the end-of-list tag, when we talk about the list data structure, there is a list item member Xlistend in each list data structure body that is used to mark the end of the list.) The xlistend.xitemvalue is initialized to a constant whose value is related to the hardware schema, 0xFFFF or 0xFFFFFFFF. This constant is defined in the migration layer, which is macro portmax_delay, which means that the end of the list is reached.
We explain this function graphically, we assume that a list item value (Xitemvalue) of 32 is inserted into the initialized list shown in 1-2, and after the Vlistinsert () function is called, the list and list items are shown in relationship 1-4. The member pointers Pxnext and pxprevious of the list item xlistitem_1 point to Xlistend, and Xlistend's member pointers Pxnext and pxprevious point to list items xlistitem_ 1; The member pointer pvcontainer of the list item xlistitem_1 points to the list xlist_1, and the list member Uxnumberofitems to 1.
Figure 1-4: Inserting list items into the list
On this basis, if you then insert a list item value (Xitemvalue) to the list of 40, after you call the Vlistinsert () function, the list and list items are shown in relationship 1-5.
Figure 1-5: Inserting list items into the list
4. Inserting a list item to the end of the list
The API insertion function in section 3rd determines the insertion position based on the list item value (Xitemvalue) in the list item, and the API function Vlistinsertend () described in this section is simply inserting the list item at the end of the list. In the next chapter of the task creation analysis, you will encounter this API function, and then analyze the function in the form of an icon, and now give the source code for the function.
void Vlistinsertend (list_t * Const PXLIST, listitem_t * const Pxnewlistitem) {listitem_t* Const PXINDEX = pxlist->pxin Dex; /* Check the integrity of the list and list item data only if the Configassert () definition is valid. * /listtest_list_integrity (pxlist); Listtest_list_item_integrity (Pxnewlistitem); /* Insert a new list item in the list */ pxnewlistitem->pxnext = Pxindex; Pxnewlistitem->pxprevious =pxindex->pxprevious; Mtcoverage_test_delay (); Pxindex->pxprevious->pxnext =pxnewlistitem; pxindex->pxprevious = Pxnewlistitem; Pxnewlistitem->pvcontainer = (void*) pxlist; (pxlist->uxnumberofitems) + +;}
FreeRTOS Advanced Article 1---freertos list and list items