freeRTOS源碼解析4--task.c 1

来源:https://www.cnblogs.com/freeManX1807/archive/2022/10/07/16759238.html
-Advertisement-
Play Games

關於 LOAD segment with RWX permissions 警告, 這是 Binutils 2.39 引入的一個新的安全類型的警告, GCC在升級版本時會帶著新版本的 Binutils 一起發佈. 如果要消除這個警告, 要麼修改ld文件, 要麼屏蔽掉它. ...


4、task.c解析

task.c中包含任務創建、任務調度、delay等等介面,很多需要模擬才能弄清楚裡面的機制,文章里只能儘可能詳細地描述每一個流程。

4.1 巨集和數據結構

源碼中有涉及的幾個巨集和數據結構需要先說明一下,其中幾個巨集是之前講鏈表時遺漏的,在這裡再補充一下。

4.1.1 鏈表中遺漏的巨集

 1 // 設置鏈表項的持有者
 2 #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )    ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
 3 // 獲取鏈表項的持有者
 4 #define listGET_LIST_ITEM_OWNER( pxListItem )             ( ( pxListItem )->pvOwner )
 5 // 設置鏈表項的值
 6 #define listSET_LIST_ITEM_VALUE( pxListItem, xValue )     ( ( pxListItem )->xItemValue = ( xValue ) )
 7 // 獲取鏈表項的值
 8 #define listGET_LIST_ITEM_VALUE( pxListItem )             ( ( pxListItem )->xItemValue )
 9 // 獲取鏈表的第一項的值
10 #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )        ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
11 // 獲取鏈表的第一項
12 #define listGET_HEAD_ENTRY( pxList )                      ( ( ( pxList )->xListEnd ).pxNext )
13 // 獲取鏈表項的下一項
14 #define listGET_NEXT( pxListItem )                        ( ( pxListItem )->pxNext )
15 // 獲取鏈表用於標記尾部的項
16 #define listGET_END_MARKER( pxList )                      ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
17 // 該鏈表是否為空
18 #define listLIST_IS_EMPTY( pxList )                       ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
19 // 該鏈表的總項數
20 #define listCURRENT_LIST_LENGTH( pxList )                 ( ( pxList )->uxNumberOfItems )
21 // 獲取鏈表的第一項的持有者
22 #define listGET_OWNER_OF_HEAD_ENTRY( pxList )            ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
23 // 該鏈表是否持有此項
24 #define listIS_CONTAINED_WITHIN( pxList, pxListItem )    ( ( ( pxListItem )->pxContainer == ( pxList ) ) ? ( pdTRUE ) : ( pdFALSE ) )
25 // 獲取持有該鏈表項的鏈表
26 #define listLIST_ITEM_CONTAINER( pxListItem )            ( ( pxListItem )->pxContainer )
27 // 該鏈表是否已初始化
28 #define listLIST_IS_INITIALISED( pxList )                ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

4.1.2 TCB結構體

下麵的結構體經過簡化以後的樣子,去除的那些成員變數在需要使用的時候再去理解就可以,這裡先把最基礎和常用的幾個放出來。

 

 

 1 typedef struct tskTaskControlBlock
 2 {
 3     /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
 4     /* 指向放在任務棧上的最後一項的位置。這必須是TCB結構的第一個成員。 */
 5     volatile StackType_t * pxTopOfStack;
 6 
 7     /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
 8     /* 任務的狀態鏈表項,表示該任務的狀態(就緒、阻塞、掛起)。 */
 9     ListItem_t xStateListItem;
10     /*< Used to reference a task from an event list. */
11     /* 任務的事件鏈表項。 */
12     ListItem_t xEventListItem;
13     /*< The priority of the task.  0 is the lowest priority. */
14     /* 任務的優先順序,0的優先順序最低。 */
15     UBaseType_t uxPriority;
16     /*< Points to the start of the stack. */
17     /* 指向棧的起始位置。 */
18     StackType_t * pxStack;
19     /*< Descriptive name given to the task when created.  Facilitates debugging only. */
20     /* 描述任務的名字。 */
21     char pcTaskName[ configMAX_TASK_NAME_LEN ];
22 
23     #if ( configUSE_TRACE_FACILITY == 1 )
24         /*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
25         /* 存儲每次創建TCB時遞增的數字。它允許調試器確定何時刪除任務,然後重新創建。 */
26         UBaseType_t uxTCBNumber;
27         /*< Stores a number specifically for use by third party trace code. */
28         /* 存儲專門供第三方跟蹤代碼使用的數字。 */
29         UBaseType_t uxTaskNumber;
30     #endif
31 
32     #if ( configUSE_MUTEXES == 1 )
33         /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
34         /* 上次分配給任務的優先順序-由優先順序繼承機制使用。 */
35         UBaseType_t uxBasePriority;
36         UBaseType_t uxMutexesHeld;
37     #endif
38 
39     #if ( configGENERATE_RUN_TIME_STATS == 1 )
40         /*< Stores the amount of time the task has spent in the Running state. */
41         /* 存儲任務處於“運行”狀態的時間。 */
42         uint32_t ulRunTimeCounter;
43     #endif
44 
45     #if ( configUSE_TASK_NOTIFICATIONS == 1 )
46         volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
47         volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
48     #endif
49 
50     #if ( INCLUDE_xTaskAbortDelay == 1 )
51         uint8_t ucDelayAborted;
52     #endif
53 } tskTCB;
54 
55 typedef tskTCB TCB_t;

4.1.3 全局變數

 1 /* 表示當前運行的任務 */
 2 PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
 3 /*< Prioritised ready tasks. */
 4 /* 就緒任務鏈表,每個優先順序都有一個鏈表。 */
 5 PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
 6 /*< Delayed tasks. */
 7 /* 延時任務鏈表。 */
 8 PRIVILEGED_DATA static List_t xDelayedTaskList1;
 9 /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
10 /* 延時的任務(使用兩個列表-一個用於當前tick計數溢出時的延時。 */
11 PRIVILEGED_DATA static List_t xDelayedTaskList2;
12 /*< Points to the delayed task list currently being used. */
13 /* 指向當前使用的延時鏈表。 */
14 PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList;
15 /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
16 /* 指向tick計數溢出時的延時任務。 */
17 PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList;
18 /*< Tasks that have been readied while the scheduler was suspended.  They will be moved to the ready list when the scheduler is resumed. */
19 /* 調度器掛起時進入就緒的任務。當調度器恢復時,它們將被移動到就緒鏈表中。 */
20 PRIVILEGED_DATA static List_t xPendingReadyList;
21 /*< Tasks that have been deleted - but their memory not yet freed. */
22 /* 被刪除的任務,但任務持有的記憶體還未釋放。 */
23 PRIVILEGED_DATA static List_t xTasksWaitingTermination;
24 /* 等待清理記憶體的任務數量。 */
25 PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U;
26 /*< Tasks that are currently suspended. */
27 /* 當前被暫停的任務。 */
28 PRIVILEGED_DATA static List_t xSuspendedTaskList;
29 /* 當前的任務數量。 */
30 PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
31 /* tick計數。 */
32 PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
33 /* 當前就緒任務中最高的優先順序。 */
34 PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
35 /* 指示調度器是否在運行。 */
36 PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
37 /* 調度器掛起時,tick的計數值。 */
38 PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U;
39 /* 指示是否需要進行上下文切換。 */
40 PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
41 /* 用於計時的參數。 */
42 PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0;
43 /* 用於第三方調式代碼用的,記錄任務的數量。 */
44 PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
45 /* Initialised to portMAX_DELAY before the scheduler starts. */
46 /* 調度器啟動時初始化為portMAX_DELAY,用於指示延時任務中最近結束延時的時間。 */
47 PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U;
48 /*< Holds the handle of the idle task. */
49 /* idle任務的句柄。 */
50 PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL;
51 /* 最高任務優先順序。 */
52 const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;
53 /* 指示調度器是否被掛起。 */
54 PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;
55 /*< Holds the value of a timer/counter the last time a task was switched in. */
56 /* 保存上次切換任務時計時器/計數器的值。 */
57 PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL;
58 /*< Holds the total amount of execution time as defined by the run time counter clock. */
59 /* 保存運行時間總量。 */
60 PRIVILEGED_DATA static volatile uint32_t ulTotalRunTime = 0UL;

4.1.4 task.c中的巨集

 1 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
 2 /* uxTopReadyPriority holds the priority of the highest priority ready
 3  * state task. */
 4 /* uxTopReadyPriority持有就緒任務鏈表中的最高優先順序。 */
 5 // 記錄就緒任務鏈表中的最高優先順序。
 6     #define taskRECORD_READY_PRIORITY( uxPriority ) \
 7     {                                               \
 8         if( ( uxPriority ) > uxTopReadyPriority )   \
 9         {                                           \
10             uxTopReadyPriority = ( uxPriority );    \
11         }                                           \
12     } /* taskRECORD_READY_PRIORITY */
13 
14 // 選擇就緒任務鏈表中最高優先順序的任務。
15 #define taskSELECT_HIGHEST_PRIORITY_TASK()                                    \
16     {                                                                         \
17         UBaseType_t uxTopPriority = uxTopReadyPriority;                       \
18                                                                               \
19         /* Find the highest priority queue that contains ready tasks. */      \
20         /* 從記錄的最高優先順序的鏈表開始查看鏈表是否為空。 */                                         \
21         while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
22         {                                                                     \
23             configASSERT( uxTopPriority );                                    \
24             --uxTopPriority;                                                  \
25         }                                                                     \
26                                                                               \
27         /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
28          * the  same priority get an equal share of the processor time. */                    \
29         /* 將找到的鏈表中的頭鏈表項的持有者賦給就緒任務鏈表中。 */                                      \
30         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
31         /* 記錄最高優先順序。 */                                                        \
32         uxTopReadyPriority = uxTopPriority;                                                   \
33     } /* taskSELECT_HIGHEST_PRIORITY_TASK */
34 
35 #else
36 
37     // #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities )      ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
38     // #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities )      ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
39     // 這種記錄最高優先順序的辦法就是在相應位置1或清0。
40     #define taskRECORD_READY_PRIORITY( uxPriority )    portRECORD_READY_PRIORITY( uxPriority, uxTopReadyPriority )
41 
42 /*-----------------------------------------------------------*/
43     // #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )    uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )
44     // __clz指令的意思就是所有1中處於最高位的1的前面0的個數。
45     // 那麼巨集portGET_HIGHEST_PRIORITY就是算出最高位1的位置,也就是最高優先順序的值。
46     #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                  \
47     {                                                                                           \
48         UBaseType_t uxTopPriority;                                                              \
49                                                                                                 \
50         /* 找到最高優先順序。 */                         \
51         portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                          \
52         configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
53         /* 將找到的鏈表中的頭鏈表項的持有者賦給就緒任務鏈表中。 */                                                        \
54         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );   \
55     } /* taskSELECT_HIGHEST_PRIORITY_TASK() */
56 
57 /*-----------------------------------------------------------*/
58 
59     // 如果uxPriority優先順序的就緒鏈表為空,則將該位清0。
60     #define taskRESET_READY_PRIORITY( uxPriority )                                                     \
61     {                                                                                                  \
62         if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ ( uxPriority ) ] ) ) == ( UBaseType_t ) 0 ) \
63         {                                                                                              \
64             portRESET_READY_PRIORITY( ( uxPriority ), ( uxTopReadyPriority ) );                        \
65         }                                                                                              \
66     }
67 
68 #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
69 
70 // 交換pxDelayedTaskList和pxOverflowDelayedTaskList指向的鏈表,並記錄溢出的次數和重置最近延時時間。
71 #define taskSWITCH_DELAYED_LISTS()                                                \
72     {                                                                             \
73         List_t * pxTemp;                                                          \
74                                                                                   \
75         /* The delayed tasks list should be empty when the lists are switched. */ \
76         configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );               \
77                                                                                   \
78         pxTemp = pxDelayedTaskList;                                               \
79         pxDelayedTaskList = pxOverflowDelayedTaskList;                            \
80         pxOverflowDelayedTaskList = pxTemp;                                       \
81         xNumOfOverflows++;                                                        \
82         prvResetNextTaskUnblockTime();                                            \
83     }
84 
85 // 將pxTCB放入就緒鏈表。先查看是否比記錄的最高優先順序還高,是的話更新記錄的最高優先順序,然後插入到相應鏈表的尾部。
86 #define prvAddTaskToReadyList( pxTCB )                                                                 \
87         taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                                             \
88         listINSERT_END( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
89 
90 #define prvGetTCBFromHandle( pxHandle )    ( ( ( pxHandle ) == NULL ) ? pxCurrentTCB : ( pxHandle ) )
View Code

 

接下來就是介面函數了,在理解了相關的巨集和數據結構後,再去看介面函數就會相對輕鬆一些。在下一篇開始解析介面函數,今天就到這裡。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在日常後端Api開發中,我們跟前端的溝通中,通常需要協商好入參的數據類型,和參數是通過什麼方式存在於請求中的,是表單(form)、請求體(body)、地址欄參數(query)、還是說通過請求頭(header)。 當協商好後,我們的介面又需要怎麼去接收這些數據呢?很多小伙伴可能上手就是直接寫一個實體, ...
  • 一:背景 1.講故事 在分析的眾多dump中,經常會遇到各種奇葩的問題,僅通過dump這種快照形式還是有很多問題搞不定,而通過 perfview 這種粒度又太粗,很難找到問題之所在,真的很頭疼,比如本篇的 短命線程 問題,參考圖如下: 我們在 t2 時刻抓取的dump對查看 短命線程 毫無幫助,我根 ...
  • 1.用vmware添加一塊10G的硬碟,且永久掛載到/data01中,寫出詳細的步驟 2.用自己語言描述raid0和raid1的區別 RAID 0: 將兩個或以上相同信號,容量的硬碟組合,磁碟陣列的總容量是多個硬碟的總和,數據依次寫 入物理磁碟,理想狀態下,硬碟讀寫性能會翻倍。但只要壞一塊磁碟,所有 ...
  • SPI是我最常用的介面之一,連接管腳僅為4根;在常見的晶元間通信方式中,速度遠優於UART、I2C等其他介面。STM32的SPI口的同步時鐘最快可到PCLK的二分之一,單個位元組或字的通信時間都在us以下,因此大多數情況下我們會使用查詢法控制SPI口的傳輸。但對於大量且連續的通信,再使用查詢法就顯得有 ...
  • 下載地址:https://nodejs.org/dist/v14.16.0/node-v14.16.0-linux-x64.tar.gz 解壓壓縮包 tar zxvf /opt/software/node-v14.16.0-linux-x64.tar.gz -C /opt/ 添加至環境變數 vim ...
  • 一、CentOS 7.9 安裝 Jenkins 2.361.2 1 下載地址:https://www.jenkins.io/download 2 簡介 Jenkins是一個Java開發的開源持續集成工具,廣泛用於項目開發,具有自動化構建、測試和部署等功能,它的運行需要Java環境。 二、Jenkin ...
  • 一、CentOS 7.9 安裝 nginx-1.22.0 下載地址:http://nginx.org/en/download.html 2 安裝前的準備 # 操作系統內核版本 uname -a # 操作系統發行版本 cat /etc/redhat-release 在安裝Nginx之前,我們需要確保全 ...
  • Arnold 是一款先進的蒙特卡洛光線追蹤渲染器,專為動畫長度和視覺效果的需求而打造。C4DtoA 4.4.0 使用 Arnold 7.1.3.1 , 是一個功能版本,帶來了對 Cinema 4D 2023 中 OCIO 顏色管理的支持、對 OSL 元數據支持的改進和一些錯誤修複。不再支持 Cine ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...