內核介紹
- 內核處於硬件層之上,內核部分包括內核庫、實時內核實現。
-
實時內核的實現包括:對象管理、線程管理及調度器、線程間通信管理、時鍾管理及內存管理等等,內核最小的資源占用情況是 3KB ROM,1.2KB RAM。
線程調度
- 線程是 RT-Thread 操作系統中最小的調度單位,線程調度算法是基於優先級的全搶占式多線程調度算法,即在系統中除了中斷處理函數、調度器上鎖部分的代碼和禁止中斷的代碼是不可搶占的之外,系統的其他部分都是可以搶占的,包括線程調度器自身。
- 支持 256 個線程優先級(也可通過配置文件更改為最大支持 32 個或 8 個線程優先級,針對 STM32 默認配置是 32 個線程優先級),0 優先級代表最高優先級,最低優先級留給空閑線程使用;
- 同時它也支持創建多個具有相同優先級的線程,相同優先級的線程間采用時間片的輪轉調度算法進行調度,使每個線程運行相同時間;
- 系統也不限制線程數量的多少,線程數目只和硬件平台的具體內存相關。
時鍾管理
- RT-Thread 的時鍾管理以時鍾節拍為基礎,時鍾節拍是 RT-Thread 操作系統中最小的時鍾單位。
- RT-Thread 的定時器提供兩類定時器機制:第一類是單次觸發定時器,這類定時器在啟動后只會觸發一次定時器事件,然后定時器自動停止。第二類是周期觸發定時器,這類定時器會周期性的觸發定時器事件,直到用戶手動的停止定時器否則將永遠持續執行下去。
線程間同步
- RT-Thread 采用信號量、互斥量與事件集實現線程間同步。
- 互斥量采用優先級繼承的方式解決了實時系統常見的優先級翻轉問題。
- 線程同步機制支持線程按優先級等待或按先進先出方式獲取信號量或互斥量。線程通過對事件的發送與接收進行同步;事件集支持多事件的 “或觸發” 和 “與觸發”,適合於線程等待多個事件的情況。
線程間通信
- RT-Thread 支持郵箱和消息隊列等通信機制。郵箱中一封郵件的長度固定為 4 字節大小;消息隊列能夠接收不固定長度的消息,並把消息緩存在自己的內存空間中。
- 郵箱效率較消息隊列更為高效。郵箱和消息隊列的發送動作可安全用於中斷服務例程中。
- 通信機制支持線程按優先級等待或按先進先出方式獲取。
內存管理
- RT-Thread 支持靜態內存池管理及動態內存堆管理。
- 當靜態內存池具有可用內存時,系統對內存塊分配的時間將是恆定的;當靜態內存池為空時,系統將申請內存塊的線程掛起或阻塞掉 (即線程等待一段時間后仍未獲得內存塊就放棄申請並返回,或者立刻返回等待的時間取決於申請內存塊時設置的等待時間參數),當其他線程釋放內存塊到內存池時,如果有掛起的待分配內存塊的線程存在的話,則系統會將這個線程喚醒。
- 動態內存堆管理模塊在系統資源不同的情況下,分別提供了面向小內存系統的內存管理算法及面向大內存系統的 SLAB 內存管理算法。
I/O 設備管理
- RT-Thread 將 PIN、I2C、SPI、USB、UART 等作為外設設備,統一通過設備注冊完成。實現了按名稱訪問的設備管理子系統,可按照統一的 API 界面訪問硬件設備。
- 對不同的設備可以掛接相應的事件。當設備事件觸發時,由驅動程序通知給上層的應用程序。
RT-Thread 啟動流程
- MDK裸機啟動流程:系統啟動后,先從匯編代碼startup_stm32f103xe.s 開始運行,然后跳轉到 C 代碼的main()函數進行運行
-
1 IMPORT __main 2 LDR R0, =SystemInit 3 BLX R0 4 LDR R0, =__main 5 BX R0 6 ENDP
- RT-Thread在進入main()之前會進行RT-Thread系統功能初始化,
-
我們使用了 MDK 的擴展功能 $Sub$$ 和$Super$$ 。可以給 main 添加 $Sub$$ 的前綴符號作為一個新功能函數 $Sub$$main ,這個 $Sub$$main 可以先調用一些要補充在 main 之前的功能函數(這里添加 RT-Thread 系統初始化功能),再調用 $Super$$main
轉到 main() 函數執行,這樣可以讓用戶不用去管 main() 之前的系統初始化操作。 -
T-Thread 支持多種平台和多種編譯器,而 rtthread_startup() 函數是 RT-Thread 規定的統一入口點,所以 $Sub$$main 函數只需調用rtthread_startup() 函數即可;
-
在 components.c 的代碼中找到rtthread_startup() 函數,我們看到 RT-Thread 的啟動流程如下圖所示:
-
1 /* components.c 中定義的這段代碼*/ 2 /* re-define main function */ 3 int $Sub$$main(void) 4 { 5 rt_hw_interrupt_disable(); 6 rtthread_startup(); 7 return 0; 8 }
-
1 int rtthread_startup(void) 2 { 3 rt_hw_interrupt_disable(); 4 5 /* board level initialization 6 * NOTE: please initialize heap inside board initialization. 7 */ 8 rt_hw_board_init(); 9 10 /* show RT-Thread version */ 11 rt_show_version(); 12 13 /* timer system initialization */ 14 rt_system_timer_init(); 15 16 /* scheduler system initialization */ 17 rt_system_scheduler_init(); 18 19 #ifdef RT_USING_SIGNALS 20 /* signal system initialization */ 21 rt_system_signal_init(); 22 #endif 23 24 /* create init_thread */ 25 rt_application_init(); 26 27 /* timer thread initialization */ 28 rt_system_timer_thread_init(); 29 30 /* idle thread initialization */ 31 rt_thread_idle_init(); 32 33 /* start scheduler */ 34 rt_system_scheduler_start(); 35 36 /* never reach here */ 37 return 0; 38 }
1 /* the system main thread */ 2 void main_thread_entry(void *parameter) 3 { 4 extern int main(void); 5 extern int $Super$$main(void); 6 7 /* RT-Thread components initialization */ 8 rt_components_init(); 9 10 /* invoke system main function */ 11 #if defined(__CC_ARM) || defined(__CLANG_ARM) 12 $Super$$main(); /* for ARMCC. */ 13 #elif defined(__ICCARM__) || defined(__GNUC__) 14 main(); 15 #endif 16 } 17 18 void rt_application_init(void) 19 { 20 rt_thread_t tid; 21 22 #ifdef RT_USING_HEAP 23 tid = rt_thread_create("main", main_thread_entry, RT_NULL, 24 1024*100, 0, 20); 25 RT_ASSERT(tid != RT_NULL);
- rt_hw_board_init() 中完成系統時鍾設置,為系統提供心跳、串口初始化,將系統輸入輸出終端綁定到這個串口,后續系統運行信息就會從串口打印出來。
- main() 函數是 RT-Thread 的用戶代碼入口,用戶可以在 main() 函數里添加自己的應用。
-
1 int main(void) 2 { 3 /* user app entry */ 4 return 0; 5 }
RT-Thread 程序內存分布
- 一般 MCU 包含的存儲空間有:片內 Flash 與片內 RAM,RAM 相當於內存,Flash 相當於硬盤。編譯器會將一個程序分類為好幾個部分,分別存儲在 MCU 不同的存儲區。
- Code:代碼段,存放程序的代碼部分;
- RO-data:只讀數據段,存放程序中定義的常量;
- RW-data:讀寫數據段,存放初始化為非 0 值的全局變量;
- ZI-data:0 數據段,存放未初始化的全局變量及初始化為 0 的變量;
- RO Size 包含了 Code 及 RO-data,表示程序占用 Flash 空間的大小;
- RW Size 包含了 RW-data 及 ZI-data,表示運行時占用的 RAM 的大小;
- ROM Size 包含了 Code、RO Data 以及 RW Data,表示燒寫程序所占用的 Flash 空間的大小;
-
程序運行之前,需要有文件實體被燒錄到 STM32 的 Flash 中,一般是 bin 或者 hex 文件,該被燒錄文件稱為可執行映像文件。如圖下圖中左圖所示,是可執行映像文件燒錄到 STM32 后的內存分布,它包含 RO 段和 RW 段兩個部分:其中 RO 段中保存了 Code、RO-data 的數據,RW 段保存了 RW-data 的數據,由於 ZI-data 都是 0,所以未包含在映像文件中。
- STM32 在上電啟動之后默認從 Flash 啟動,啟動之后會將 RW 段中的 RW-data(初始化的全局變量)搬運到 RAM 中,但不會搬運 RO 段,即 CPU 的執行代碼從 Flash 中讀取,另外根據編譯器給出的 ZI 地址和大小分配出 ZI 段,並將這塊 RAM 區域清零。
RT-Thread 自動初始化機制
- 自動初始化機制是指初始化函數不需要被顯式調用,只需要在函數定義處通過宏定義的方式進行申明,就會在系統啟動過程中被執行。
-
1 int stm32_hw_usart_init(void) 2 { 3 struct stm32_uart *uart; 4 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; 5 6 #ifdef RT_USING_UART1 7 uart = &uart1; 8 uart->UartHandle.Instance = USART1; 9 10 serial1.ops = &stm32_uart_ops; 11 serial1.config = config; 12 13 /* register UART1 device */ 14 rt_hw_serial_register(&serial1, 15 "uart1", 16 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, 17 uart); 18 #endif /* RT_USING_UART1 */ 19 ...... 20 ...... 21 } 22 INIT_BOARD_EXPORT(stm32_hw_usart_init);
-
代碼最后的 INIT_BOARD_EXPORT(stm32_hw_usart_init) 表示使用自動初始化功能,按照這種方式,stm32_hw_usart_init() 函數就會被系統自動調用
-
系統啟動流程圖中,有兩個函數:rt_components_board_init() 與 rt_components_init(),其后的帶底色方框內部的函數表示被自動初始化的函數
- “board init functions” 為所有通過 INIT_BOARD_EXPORT(fn) 申明的初始化函數。
- “pre-initialization functions” 為所有通過 INIT_PREV_EXPORT(fn) 申明的初始化函數。
- “device init functions” 為所有通過 INIT_DEVICE_EXPORT(fn) 申明的初始化函數。
- “components init functions” 為所有通過 INIT_COMPONENT_EXPORT(fn) 申明的初始化函數。
- “enviroment init functions” 為所有通過 INIT_ENV_EXPORT(fn) 申明的初始化函數。
- “application init functions” 為所有通過 INIT_APP_EXPORT(fn) 申明的初始化函數。
- rt_components_board_init() 函數執行的比較早,主要初始化相關硬件環境,執行這個函數時將會遍歷通過 INIT_BOARD_EXPORT(fn) 申明的初始化函數表,並調用各個函數。
- rt_components_init() 函數會在操作系統運行起來之后創建的 main 線程里被調用執行,這個時候硬件環境和操作系統已經初始化完成,可以執行應用相關代碼。
- RT-Thread 的自動初始化機制使用了自定義 RTI 符號段,將需要在啟動時進行初始化的函數指針放到了該段中,形成一張初始化函數表,在系統啟動過程中會遍歷該表,並調用表中的函數,達到自動初始化的目的。
- 用來實現自動初始化功能的宏接口定義詳細描述如下
- 初始化函數主動通過這些宏接口進行申明,如 INIT_BOARD_EXPORT(rt_hw_usart_init),鏈接器會自動收集所有被申明的初始化函數,放到 RTI 符號段中,該符號段位於內存分布的 RO 段中,該 RTI符號段中的所有函數在系統初始化時會被自動調用。
RT-Thread 內核對象模型
靜態對象和動態對象
- 靜態內核對象和動態內核對象,靜態內核對象通常放在RW 段和 ZI 段中,在系統啟動后在程序中初始化;動態內核對象則是從內存堆中創建的,而后手工做初始化。
-
1 static rt_uint8_t main_stack[2048]; 2 struct rt_thread main_thread; 3 4 void rt_application_init(void) 5 { 6 rt_thread_t tid; 7 8 #ifdef RT_USING_HEAP 9 /* 10 * 線程名:main 11 * 線程入口:main_thread_entry 12 * 參數:RT_NULL 13 * 站空間大小:1024*100 14 * 優先級:0 15 * 時間片:20個OS Tick 16 */ 17 tid = rt_thread_create("main", main_thread_entry, RT_NULL, //動態線程 18 1024*100, 0, 20); 19 RT_ASSERT(tid != RT_NULL); 20 #else 21 rt_err_t result; 22 23 tid = &main_thread; 24 /* 25 * 靜態線程對象:main_thread 26 * 線程名:main 27 * 線程入口:main_thread_entry 28 * 參數:RT_NULL 29 * 線程起始地址:main_stack 30 * 線程堆棧大小:sizeof(main_stack) 31 * 優先級:RT_MAIN_THREAD_PRIORITY 32 * 時間片:20個OS Tick 33 */ 34 result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL, //靜態線程 35 main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20); 36 RT_ASSERT(result == RT_EOK); 37 38 /* if not define RT_USING_HEAP, using to eliminate the warning */ 39 (void)result; 40 #endif 41 42 rt_thread_startup(tid); //啟動線程 43 }
- main_thread 是一個靜態線程對象,線程控制塊 main_thread 與棧空間 main_stack 都是編譯時決定的;
- mian是一個動態線程對象,用到的空間是動態分配的,包括線程控制塊和棧空間;
- 靜態對象會占用 RAM 空間,不依賴於內存堆管理器,內存分配時間確定。動態對象則依賴於內存堆管理器,運行時申請 RAM 空間,當對象被刪除后,占用的 RAM 空間被釋放;
內核對象管理架構
- RT-Thread 采用內核對象管理系統來訪問 / 管理所有內核對象,內核對象包含了內核中絕大部分設施,這些內核對象可以是靜態分配的靜態對象,也可以是從系統內存堆中分配的動態對象。
- RT-Thread 內核對象包括:線程,信號量,互斥量,事件,郵箱,消息隊列和定時器,內存池,設備驅動等。對象容器中包含了每類內核對象的信息,包括對象類型,大小等。對象容器給每類內核對象分配了一個鏈表,所有的內核對象都被鏈接到該鏈表上
- RT-Thread 中各類內核對象的派生和繼承關系
-
rt_object 派生出來的有:線程對象、內存池對象、定時器對象、設備對象和 IPC對象(IPC:Inter-Process Communication,進程間通信。在 RT-Thread 實時操作系統中,IPC 對象的作用是進行線程間同步與通信);由 IPC 對象派生出信號量、互斥量、事件、郵箱與消息隊列、信號等對象。
- 對於每一種具體內核對象和對象控制塊,除了基本結構外,還有自己的擴展屬性(私有屬性),例如,對於線程控制塊,在基類對象基礎上進行擴展,增加了線程狀態、優先級等屬性。這些屬性在基類對象的操作中不會用到,只有在與具體線程相關的操作中才會使用。因此從面向對象的觀點,可以認為每一種具體對象是抽象對象的派生,繼承了基本對象的屬性並在此基礎上擴展了與自己相關的屬性。
對象控制塊
- 內核對象控制塊的數據結構
-
1 /** 2 * Base structure of Kernel object 3 */ 4 struct rt_object 5 { 6 char name[RT_NAME_MAX]; /**< name of kernel object 內核對象名稱*/ 7 rt_uint8_t type; /**< type of kernel object 內核對象類型*/ 8 rt_uint8_t flag; /**< flag of kernel object 內核對象的參數*/ 9 10 #ifdef RT_USING_MODULE 11 void *module_id; /**< id of application module 內核對象模型id*/ 12 #endif 13 rt_list_t list; /**< list node of kernel object 內核對象管理鏈表*/ 14 }; 15 typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */
- 內核對象支持的類型:
-
enum rt_object_class_type { RT_Object_Class_Thread = 0, /**< The object is a thread. 線程類型*/ RT_Object_Class_Semaphore, /**< The object is a semaphore. 信號量類型*/ RT_Object_Class_Mutex, /**< The object is a mutex. 互斥量類型*/ RT_Object_Class_Event, /**< The object is a event. 時間類型*/ RT_Object_Class_MailBox, /**< The object is a mail box. 郵箱類型*/ RT_Object_Class_MessageQueue, /**< The object is a message queue. 消息隊列類型*/ RT_Object_Class_MemHeap, /**< The object is a memory heap 內存堆類型*/ RT_Object_Class_MemPool, /**< The object is a memory pool. 內存池類型*/ RT_Object_Class_Device, /**< The object is a device 設備類型*/ RT_Object_Class_Timer, /**< The object is a timer. 定時器類型*/ RT_Object_Class_Module, /**< The object is a module. 模塊*/ RT_Object_Class_Unknown, /**< The object is unknown. 未知類型*/ RT_Object_Class_Static = 0x80 /**< The object is a static object. 靜態類型*/ };
-
如果是靜態對象,那么對象類型的最高位將是 1(是RT_Object_Class_Static 與其他對象類型的與操作),否則就是動態對象,系統最多能夠容納的對象類別數目是 127 個。
內核對象管理方式
- 內核對象容器的數據結構
-
/** * The information of the kernel object */ struct rt_object_information { enum rt_object_class_type type; /**< object class type */ rt_list_t object_list; /**< object list */ rt_size_t object_size; /**< object size */ };
-
一類對象由一個 rt_object_information 結構體來管理,每一個這類對象的具體實例都通過鏈表的形式掛接在 object_list 上。而這一類對象的內存塊尺寸由 object_size 標識出來
初始化對象
- 在使用一個未初始化的靜態對象前必須先對其進行初始化。初始化對象使用接口:
-
void rt_object_init(struct rt_object *object, //需要初始化的對象指針,它必須指向具體的對象內存塊,而不能是空指針或野指針 enum rt_object_class_type type, //對象的類型,必須是 rt_object_class_type 枚舉類型中列出的除RT_Object_Class_Static 以外的類型 const char *name) //對象的名字。每個對象可以設置一個名字,這個名字的最大長度由 RT_NAME_MAX指定
脫離對象
- 從內核對象管理器中脫離一個對象。脫離對象使用以下接口:
-
/** * This function will detach a static object from object system, * and the memory of static object is not freed. * * @param object the specified object to be detached. */ void rt_object_detach(rt_object_t object)
分配對象
- 對象初始化、脫離的接口,都是面向對象內存塊已經有的情況下,而動態的對象則可以在需要時申請,不需要時釋放出內存空間給其他應用使用。申請分配新的對象可以使用以下接口:
-
/** * This function will allocate an object from object system * * @param type the type of object * @param name the object name. In system, the object's name must be unique. * * @return object */ rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
刪除對象
- 對於一個動態對象,當不再使用時,可以調用如下接口刪除對象,並釋放相應的系統資源:
-
/** * This function will delete an object and release object memory. * * @param object the specified object to be deleted. */ void rt_object_delete(rt_object_t object)
- 當調用以上接口時,首先從對象容器鏈表中脫離對象,然后釋放對象所占用的內存。
辨別對象
- 判斷指定對象是否是系統對象(靜態內核對象)。辨別對象使用以下接口:
-
/** * This function will judge the object is system object or not. * Normally, the system object is a static object and the type * of object set to RT_Object_Class_Static. * * @param object the specified object to be judged. * * @return RT_TRUE if a system object, RT_FALSE for others. */ rt_bool_t rt_object_is_systemobject(rt_object_t object)
-
在 RT-Thread 操作系統中,一個系統對象也就是一個靜態對象,對象類型標識上 RT_Object_Class_Static 位置位。通常使用 rt_object_init() 方式初始化的對象都是系統對象。
RT-Thread 內核配置示例
- RT-Thread 的一個重要特性是高度可裁剪性,支持對內核進行精細調整,對組件進行靈活拆卸。配置主要是通過修改工程目錄下的 rtconfig.h 文件來進行,用戶可以通過打開 / 關閉該文件中的宏定義來對代碼進行條件編譯,最終達到系統配置和裁剪的目的。
- 在實際應用中,系統配置文件 rtconfig.h 是由配置工具自動生成的,無需手動更改。
-
/* RT-Thread 內核部分 */ #define RT_NAME_MAX 8 // 表示內核對象的名稱的最大長度,若代碼中對象名稱的最大長度大於宏定義的長度,*多余的部分將被截掉。 #define RT_ALIGN_SIZE 4 // 字節對齊時設定對齊的字節個數。常使用 ALIGN(RT_ALIGN_SIZE) 進行字節對齊。 #define RT_THREAD_PRIORITY_32 #define RT_THREAD_PRIORITY_MAX 32 // 定義系統線程優先級數;通常用 RT_THREAD_PRIORITY_MAX-1 定義空閑線程的優先級 #define RT_TICK_PER_SECOND 1000 // 定義時鍾節拍,為 1000 時表示 1000 個 tick 每秒,一個 tick 為 10ms #define RT_USING_OVERFLOW_CHECK // 檢查棧是否溢出,未定義則關閉 #define RT_USING_HOOK // 定義該宏使用 HOOK #define RT_IDEL_HOOK_LIST_SIZE 4 // 定義HOOK鏈表大小 #define IDLE_THREAD_STACK_SIZE 1024 // 定義線程棧大小 #define RT_DEBUG // 定義該宏開啟 debug 模式,未定義則關閉 /* 線程間同步與通信部分,該部分會使用到的對象有信號量、互斥量、事件、郵箱、消息隊列、信號等。 */ #define RT_USING_SEMAPHORE // 定義該宏可開啟信號量的使用,未定義則關閉 #define RT_USING_MUTEX // 定義該宏可開啟互斥量的使用,未定義則關閉 #define RT_USING_EVENT // 定義該宏可開啟事件集的使用,未定義則關閉 #define RT_USING_MAILBOX // 定義該宏可開啟郵箱的使用,未定義則關閉 #define RT_USING_MESSAGEQUEUE // 定義該宏可開啟消息隊列的使用,未定義則關閉 /* 內存管理部分 */ #define RT_USING_MEMPOOL // 開啟靜態內存池的使用 #define RT_USING_MEMHEAP // 定義該宏可開啟兩個或以上內存堆拼接的使用,未定義則關閉 #define RT_USING_SMALL_MEM // 開啟小內存管理算法 #define RT_USING_HEAP // 開啟堆的使用 /* 內核設備對象 */ #define RT_USING_DEVICE // 表示開啟了系統設備的使用 #define RT_USING_CONSOLE // 定義該宏可開啟系統控制台設備的使用,未定義則關閉 #define RT_CONSOLEBUF_SIZE 128 // 定義控制台設備的緩沖區大小 #define RT_CONSOLE_DEVICE_NAME "uart1" // 控制台設備的名稱 /* 自動初始化方式 */ #define RT_USING_COMPONENTS_INIT // 定義該宏開啟自動初始化機制,未定義則關閉 /* Command shell */ #define RT_USING_FINSH // 定義該宏可開啟系統 FinSH 調試工具的使用,未定義則關閉 #define FINSH_THREAD_NAME "tshell" // 開啟系統 FinSH 時:將該線程名稱定義為 tshell #define FINSH_USING_HISTORY // 開啟系統 FinSH 時:使用歷史命令 #define FINSH_HISTORY_LINES 5 // 開啟系統 FinSH 時:對歷史命令行數的定義 #define FINSH_USING_SYMTAB // 開啟系統 FinSH 時:定義該宏開啟使用 Tab 鍵,未定義則關閉 #define FINSH_USING_DESCRIPTION // 開啟系統 FinSH 時:定義該宏使用描述,未定義則關閉 #define FINSH_THREAD_PRIORITY 20 // 開啟系統 FinSH 時:定義該線程的優先級 #define FINSH_THREAD_STACK_SIZE 2048 // 開啟系統 FinSH 時:定義該線程的棧大小 #define FINSH_CMD_SIZE 80 // 開啟系統 FinSH 時:定義命令字符長度 /* Device virtual file system */ #define RT_USING_DFS // 使用DFS文件系統 #define DFS_USING_WORKDIR // 使用工作目錄 #define DFS_FILESYSTEMS_MAX 4 // 文件系統 #define DFS_FILESYSTEM_TYPES_MAX 4 // 文件系統類型 #define DFS_FD_MAX 8 // DF容器大小 #define RT_USING_DFS_ELMFAT // 使用elmfat文件系統
常見宏定義說明
- RT-Thread 中經常使用一些宏定義,舉例 Keil 編譯環境下一些常見的宏定義:rtdef.h
-
rt_inline,定義如下,static 關鍵字的作用是令函數只能在當前的文件中使用;inline 表示內聯,用static 修飾后在調用函數時會建議編譯器進行內聯展開。
-
#define rt_inline static __inline
-
RT_USED,定義如下,該宏的作用是向編譯器說明這段代碼有用,即使函數中沒有調用也要保留編譯。例如 RT-Thread 自動初始化功能使用了自定義的段,使用 RT_USED 會將自定義的代碼段保留。
-
#define RT_USED __attribute__((used))
- RT_UNUSED,定義如下,表示函數或變量可能不使用,這個屬性可以避免編譯器產生警告信息。
-
#define RT_UNUSED __attribute__((unused))
-
RT_WEAK,定義如下,常用於定義函數,編譯器在鏈接函數時會優先鏈接沒有該關鍵字前綴的函數,如果找不到則再鏈接由 weak 修飾的函數
-
#define RT_WEAK __weak
-
ALIGN(n),定義如下,作用是在給某對象分配地址空間時,將其存放的地址按照 n 字節對齊,這里 n 可取 2 的冪次方。字節對齊的作用不僅是便於 CPU 快速訪問,同時合理的利用字節對齊可以有效地節省存儲空間。
-
#define ALIGN(n) __attribute__((aligned(n)))
-
RT_ALIGN(size,align),定義如下,作用是將 size 提升為 align 定義的整數的倍數,例如,RT_ALIGN(13,4) 將返回 16。
-
#define RT_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1))
參考
- 《RT-Thread 編程指南》