今天講的主題是 “如何輕松地移植Linux應用到AliOS Things上”
1、前言
近些年,大量的智能裝置已經進入人們的生活, 如智能音箱,各種支付裝置,大街小巷上各種大小的廣告機等。這些裝置中大多還是采用Linux,帶屏的裝置則大多采用Android,導緻他們必須采用較高成本的硬體。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLv50VaVlTWlFaoBDTwYVbiVHNHpleO1GTulzRilWO5xkNNh0YwIFSh9Fd4VGdsATMfd3bkFGazxyaHRGcWdUYuVzVa9GczoVdG1mWfVGc5RHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cWZwpmL2ETOzEzNwQTM5EjNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpeg)
AliOS Things是阿裡雲IoT研發的應用于物聯網智能裝置的嵌入式實時作業系統,是HaaS100搭載的作業系統。目前AliOS Things + 小程式架構已經可以替代Linux甚至Android,大大降低裝置的成本。可是Linux(包括Android)上的成熟穩定的架構,尤其是音視訊處理的架構,圖形渲染等,如果可以拿來使用,再加以适配優化,不需要重複造輪子,豈不美哉。
那如何把Unix/Linux這些優秀的架構輕松地移植到AliOS Things上呢?支援POSIX就是實作這個目标的一把利器。
2、POSIX是什麼
POSIX(Portable Operating System Interface)是IEEE組織為了維護應用在不同作業系統之間的相容性而制定的标準。 主要包括API,Shell和Utility等一整套應用運作環境。廣泛應用于UNIX/LINUX作業系統,和一些嵌入式作業系統中(如Zephyr, VxWorks, QNX, Fuchsia,FreeRTOS,RT-Thread,AliOS Things)。
POSIX标準也被稱為IEEE 1003,ISO/IEC 9945,目前标準的開發者是Austin Group,它是IEEE, Open Group, ISO/IEC的聯合組織,目前POSIX标準的最新版本是POSIX.1-2017。 剛開始時POSIX标準(IEEE 1003)又分為不同的子集,其中還處于有效狀态的有IEEE 1003.13。 IEEE 1003.13是針對嵌入式領域制定的标準,根據範圍的大小又分為4個不同的Profile,PSE51, PSE52, PSE53和PSE54,其關系如下圖。
3、為什麼需要POSIX
AliOS Things作為一個物聯網領域的嵌入式實時作業系統為什麼要支援POSIX标準呢?除了解決前言引入的問題外,還有沒有其他的目的呢?本章節将進行一個全面的闡述。
3.1、POSIX解決的核心問題
軟體生态
軟體生态是一個OS的生存核心,但建設一個OS的軟體生态又不能急于求成, 需要經過多年的積累沉澱。 顯然AliOS Things的生态還不成熟,而Linux的生态則經過了幾十年的沉澱,變得非常強大。支援POSIX則可以
- 相容Unix/Linux軟體生态。
- 相容支援POSIX标準的嵌入式系統(如FreeRTOS)的軟體生态。
标準
- API模型由國際權威組織定義,且被廣泛使用驗證過,成熟穩定。
易用
- API被廣大開發者所熟悉,降低開發者學習成本。
- 每個API都有标準化的文檔詳細說明,友善查詢使用。
- 為AliOS Things内部元件提供标準接口,友善使用和支援多平台如移植到Linux。
3.2、競品分析
其實不隻有我們這麼想,讓我們一起看看業界的嵌入式實時作業系統是否支援POSIX标準。
VxWorks
作為比較老牌的嵌入式實時作業系統,VxWorks被廣泛應用于多個領域,如航空航天,工業控制等對實時性要求很高的領域, 它也是非常重視對POSIX标準的支援,其全部支援了PSE52标準 + BSD Socket。并通過官方的PSE52認證。
QNX
作為被廣泛應用于汽車領域的嵌入式實時作業系統,同時也是比較成功的商用微核心作業系統,QNX也是比較重視對POSIX标準的支援,其全部支援了PSE52标準 + BSD Socket。
Fuchsia
作為Google全新設計研發的微核心作業系統, Fuchsia也是支援POSIX标準的。
FreeRTOS
FreeRTOS雖然主要應用于資源比較受限的MCU裝置, 其也實作部分PSE52範圍内的API。
RT-Thread
RT-Thread主要應用于物聯網領域的智能裝置, 其也比較重視對POSIX标準的支援,實作PSE52範圍内的大部分API。
AliOS Things支援POSIX的長遠目标是實作POSIX.1的最新版本,如目前是POSIX.1-2017,它共有1191個API,數量是非常大的,但是有很多并不是經常使用的API,是以短期目标是實作PSE52 + Networking标準的API + 項目中需要的API。
4、POSIX的設計與實作
POSIX作為核心與應用的接口層, 涉及到核心的多個方面。 下面僅以POSIX線程和POSIX條件變量為例介紹其設計與實作,POSIX元件的代碼位于core/osal/posix/, 頭檔案位于include/posix/。
4.1、POSIX線程
關鍵資料結構
typedef struct pthread_tcb {
aos_task_t task; /* The rhino task handle. */
unsigned int magic; /* The pthread tcb memory magic number. */
void *(*thread_entry)(void *para); /* The start routine of the thread. */
void *thread_para; /* The parameter of start routine. */
aos_sem_t join_sem; /* The semaphore for pthread_join. */
pthread_cleanup_t *cleanup; /* The registered cleanup function for the thread.*/
void *environ;
void **tls;
void *return_value; /* The thread's return value. */
pthread_attr_t attr; /* The thread's attribute. */
char thread_name[PTHREAD_NAME_MAX_LEN + 1]; /* The thread's name. */
} pthread_tcb_t;
_pthread_tcb_t是POSIX線程内部的核心資料結構,儲存着POSIX線程的關鍵資料,與核心task的tcb結構相對應,且通過tid互相關聯。POSIX線程的關鍵資料類型pthread_t會關聯到這個資料結構上。
- task 核心rhino的任務句柄。
- magic 是POSIX線程的魔術字,以差別于使用AliOS Things原生的AOS API建立的線程。
- thread_entry 新建立線程的執行入口函數的指針。
- thread_para 新建立線程的執行入口函數的參數結構指針。
- join_sem 實作線程的JOINABLE的信号量,線程退出時自身不釋放ptcb資源,由其他線程調用pthread_join擷取傳回值,并釋放資源。
- cleanup 線程在退出時要執行的清理函數指針的連結清單。
- environ 線程運作的環境變量。
- tls 存放線程私有資料。
- return_value 存放POSIX線程的傳回值的指針。
- attr 線程屬性,為POSIX線程設定屬性以更細粒度地控制線程的行為。如線程的棧位址,棧大小,線程的排程政策,排程參數等。
- thread_name 線程名字
POSIX線程的建立與銷毀
使用pthread_create建立POSIX線程。
使用pthread_exit銷毀一個POSIX線程, 或者從一個線程的入口函數傳回,也會走到線程的銷毀流程。
下面流程圖為保持邏輯清晰,略去了很多實作細節如異常處理等。
4.2、POSIX條件變量
POSIX條件變量的标準定義:
https://pubs.opengroup.org/onlinepubs/9699919799/typedef struct pthread_cond {
uint8_t flag;
int waiting;
int signals;
void *lock;
void *wait_sem;
void *wait_done;
pthread_condattr_t attr;
} pthread_cond_t;
pthread_cond_t是實作POSIX條件變量的核心資料結構。
- flag 一些内部的标記如是否為動态初始化。
- lock 是保護内部資料的一把mutex鎖。
- waiting 等待這個條件變量的線程數。
- signals 已發送信号還未收到确認的數目。
- wait_sem 線程等待的信号量,底層核心的信号量原語。
- wait_done 用于發送線程與等待線程之間握手确認的信号量, 底層核心的信号量原語。
- attr 記錄pthread條件變量的屬性,比如條件變量用到的時鐘clock。
POSIX條件變量的處理
POSIX 條件變量不僅支援觸發單個等待的線程,同時還支援廣播(pthread_cond_broadcast),觸發多個等待的線程。
4.3、實作結果如何
AliOS Things 支援了pthread,semaphore, message queue, timer, fs等多個子產品的豐富的API,開發者可以利用這些POSIX API,隻需要簡單地修改,甚至無需修改,就可以移植Unix/Linux的應用到AliOS Things上。再結合HaaS100的開發闆,開發者可以更快速地建構智能裝置所需的軟體和硬體。
4.4、動手試試
下面動手編寫一個簡單的使用POSIX PTHREAD API的Linux應用,儲存為pthread_test.c
- #include <stdio.h>
- #include <unistd.h>
- #include <pthread.h>
- static volatile int count = 1;
- pthread_mutex_t count_lock;
- void* increase_count(void *arg)
- {
- while (1) {
- sleep(1);
- pthread_mutex_lock(&count_lock);
- count += 10;
- printf("In new thread: count:%d\n", count);
- pthread_mutex_unlock(&count_lock);
- }
- }
- int main(int argc, char* argv[])
- int ret = 0;
- pthread_t new_thread;
- pthread_mutex_init(&count_lock, NULL);
- ret = pthread_create(&new_thread, NULL, increase_count, NULL);
- if (ret != 0) {
- printf("Error:%s:%d:ret:%d\n", __FILE__, __LINE__, ret);
- return -1;
- while(1) {
- count++;
- printf("In main thread: count:%d\n", count);
- return 0;
在Linux上編譯
gcc pthread_test.c -o pthread_test -lpthread
運作結果如下:
- $ ./pthread_test
- In main thread: count:2
- In new thread: count:12
- In main thread: count:13
- In new thread: count:23
- In main thread: count:24
- In new thread: count:34
- In main thread: count:35
- In new thread: count:45
- In main thread: count:46
- In new thread: count:56
- In main thread: count:57
- In new thread: count:67
- In main thread: count:68
- In new thread: count:78
- In main thread: count:79
- In new thread: count:89
- In main thread: count:90
- In new thread: count:100
把上面的pthread_test.c 移植到AliOS Things上,改寫application/example/helloworld_demo 這個demo應用。 把pthread_test.c 的内容替換application/example/helloworld_demo/appdemo.c的全部内容,并做如下2個簡單的修改。
- $ diff -ru pthread_test.c solutions/helloworld_demo/helloworld.c
- --- pthread_test.c 2021-06-17 12:01:56.638675133 +0800
- +++ solutions/helloworld_demo/helloworld.c 2021-06-17 12:04:58.479941329 +0800
- @@ -17,7 +17,7 @@
- }
- -int main(int argc, char* argv[])
- +int application_start(int argc, char* argv[])
- {
- int ret = 0;
- pthread_t new_thread;
由上可知,AliOS Things的應用入口是application_start, 不是main, 上面的Linux應用,隻需要改動一行就可以跑到AliOS Things上。
在VSCODE IDE利用alios-studio插件,點選編譯按鈕,編譯hellworld_demo, 詳細步驟可以參考
AliOS Things的編譯步驟。
下載下傳燒錄并啟動,log如下, 與Linux運作的結果一緻。
- Welcome to AliOS Things
- 1592/main_task | sys_init aos_components_init done
- 1592/main_task | mesh has been opened
- 1986/mcu_audio | mcu_audio_main exit
- [Jan 01 00:00:01.491]<I>ULOG-test sys_init aos_components_init done
參考
POSIX.1-2017 AliOS Things開發者支援
如需更多技術支援,可加入釘釘開發者群,或者關注微信公衆号。
更多技術與解決方案介紹,請通路HaaS官方網站
https://haas.iot.aliyun.com