天天看點

Linux上應用竟然可以輕松的移植到RTOS上1、前言2、POSIX是什麼3、為什麼需要POSIX4、POSIX的設計與實作參考開發者支援

今天講的主題是 “如何輕松地移植Linux應用到AliOS Things上”

1、前言

近些年,大量的智能裝置已經進入人們的生活, 如智能音箱,各種支付裝置,大街小巷上各種大小的廣告機等。這些裝置中大多還是采用Linux,帶屏的裝置則大多采用Android,導緻他們必須采用較高成本的硬體。

Linux上應用竟然可以輕松的移植到RTOS上1、前言2、POSIX是什麼3、為什麼需要POSIX4、POSIX的設計與實作參考開發者支援

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,其關系如下圖。

Linux上應用竟然可以輕松的移植到RTOS上1、前言2、POSIX是什麼3、為什麼需要POSIX4、POSIX的設計與實作參考開發者支援

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線程, 或者從一個線程的入口函數傳回,也會走到線程的銷毀流程。

下面流程圖為保持邏輯清晰,略去了很多實作細節如異常處理等。

Linux上應用竟然可以輕松的移植到RTOS上1、前言2、POSIX是什麼3、為什麼需要POSIX4、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條件變量的處理

Linux上應用竟然可以輕松的移植到RTOS上1、前言2、POSIX是什麼3、為什麼需要POSIX4、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

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <pthread.h>
  4. static volatile int count = 1;
  5. pthread_mutex_t count_lock;
  6. void* increase_count(void *arg)
  7. {
  8.     while (1) {
  9.         sleep(1);
  10.         pthread_mutex_lock(&count_lock);
  11.         count += 10;
  12.         printf("In new thread: count:%d\n", count);
  13.         pthread_mutex_unlock(&count_lock);
  14.     }
  15. }
  16. int main(int argc, char* argv[])
  17.     int ret = 0;
  18.     pthread_t new_thread;
  19.     pthread_mutex_init(&count_lock, NULL);
  20.     ret = pthread_create(&new_thread, NULL, increase_count, NULL);
  21.     if (ret != 0) {
  22.         printf("Error:%s:%d:ret:%d\n", __FILE__, __LINE__, ret);
  23.         return -1;
  24.     while(1) {
  25.         count++;
  26.         printf("In main thread: count:%d\n", count);
  27.     return 0;

在Linux上編譯

gcc pthread_test.c -o pthread_test -lpthread

運作結果如下:

  1. $ ./pthread_test
  2. In main thread: count:2
  3. In new thread: count:12
  4. In main thread: count:13
  5. In new thread: count:23
  6. In main thread: count:24
  7. In new thread: count:34
  8. In main thread: count:35
  9. In new thread: count:45
  10. In main thread: count:46
  11. In new thread: count:56
  12. In main thread: count:57
  13. In new thread: count:67
  14. In main thread: count:68
  15. In new thread: count:78
  16. In main thread: count:79
  17. In new thread: count:89
  18. In main thread: count:90
  19. 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個簡單的修改。

  1. $ diff -ru pthread_test.c solutions/helloworld_demo/helloworld.c
  2. --- pthread_test.c 2021-06-17 12:01:56.638675133 +0800
  3. +++ solutions/helloworld_demo/helloworld.c    2021-06-17 12:04:58.479941329 +0800
  4. @@ -17,7 +17,7 @@
  5.  }
  6. -int main(int argc, char* argv[])
  7. +int application_start(int argc, char* argv[])
  8.  {
  9.      int ret = 0;
  10.      pthread_t new_thread;

由上可知,AliOS Things的應用入口是application_start, 不是main, 上面的Linux應用,隻需要改動一行就可以跑到AliOS Things上。

在VSCODE IDE利用alios-studio插件,點選編譯按鈕,編譯hellworld_demo, 詳細步驟可以參考

AliOS Things的編譯步驟

下載下傳燒錄并啟動,log如下, 與Linux運作的結果一緻。

  1.            Welcome to AliOS Things          
  2.      1592/main_task | sys_init aos_components_init done
  3.      1592/main_task |         mesh has been opened       
  4.      1986/mcu_audio | mcu_audio_main exit
  5. [Jan 01 00:00:01.491]<I>ULOG-test sys_init aos_components_init done

參考

POSIX.1-2017 AliOS Things

開發者支援

如需更多技術支援,可加入釘釘開發者群,或者關注微信公衆号。

Linux上應用竟然可以輕松的移植到RTOS上1、前言2、POSIX是什麼3、為什麼需要POSIX4、POSIX的設計與實作參考開發者支援

更多技術與解決方案介紹,請通路HaaS官方網站

https://haas.iot.aliyun.com

繼續閱讀