如何輕鬆地移植Linux應用到AliOS Things上

1、前言

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

 

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

image.png

 

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標準的操作系統

其實不只有我們這麼想,讓我們一起看看業界的嵌入式實時操作系統是否支持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 {
    unsigned int    magic;
    pthread_attr_t  attr;
    ktask_t        *tid;

    void *(*thread_entry)(void *para);
    void *thread_para;

    ksem_t *join_sem;

    unsigned char          cancel_state;
    volatile unsigned char cancel_type;
    volatile unsigned char canceled;

    _pthread_cleanup_t *cleanup;
    _pthread_environ_t *environ;

    void **tls;
    void  *return_value;
} _pthread_tcb_t;

_pthread_tcb_t是POSIX線程內部的核心數據結構,保存着POSIX線程的關鍵數據,與內核task的tcb結構相對應,且通過tid相互關聯。POSIX線程的關鍵數據類型pthread_t會關聯到這個數據結構上。

  • magic 是POSIX線程的魔術字,以區別於使用AliOS Things原生的AOS API創建的線程。
  • attr 線程屬性,爲POSIX線程設置屬性以更細粒度地控制線程的行爲。如線程的棧地址,棧大小,線程的調度策略,調度參數等。
  • tid 指向內核task的tcb結構。
  • thread_entry 新創建線程的執行入口函數的指針。
  • thread_para 新創建線程的執行入口函數的參數結構指針。
  • join_sem 實現線程的JOINABLE的信號量,線程退出時自身不釋放ptcb資源,由其他線程調用pthread_join獲取返回值,並釋放資源。
  • cancel_state/cancel_type/canceled 分別表示POSIX線程取消狀態(是否使能取消),取消類型(延遲取消、立馬取消),是否取消。目前POSIX線程的取消功能暫未實現。
  • cleanup 線程在退出時要執行的清理函數指針的鏈表。
  • tls  存放線程私有數據。
  • return_value 存放POSIX線程的返回值的指針。

 

POSIX線程的創建與銷燬

使用pthread_create創建POSIX線程。

使用pthread_exit銷燬一個POSIX線程, 或者從一個線程的入口函數返回,也會走到線程的銷燬流程。

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

posix1.png

 

4.2、POSIX條件變量

POSIX條件變量的標準定義:https://pubs.opengroup.org/onlinepubs/9699919799/

關鍵數據結構

typedef struct pthread_cond {
    kmutex_t *lock;
    int       waiting;
    int       signals;
    ksem_t   *wait_sem;
    ksem_t   *wait_done;

    pthread_condattr_t attr;
} pthread_cond_t;

pthread_cond_t是實現POSIX條件變量的核心數據結構。

  • lock 是保護內部數據的一把mutex鎖。
  • waiting 等待這個條件變量的線程數。
  • signals 已發送信號還未收到確認的數目。
  • wait_sem 線程等待的信號量,底層內核的信號量原語。
  • wait_done 用於發送線程與等待線程之間握手確認的信號量, 底層內核的信號量原語。
  • attr  記錄pthread條件變量的屬性,比如條件變量用到的時鐘clock。

 

POSIX條件變量的處理

pthread-cond.png

POSIX 條件變量不僅支持觸發單個等待的線程,同時還支持廣播(pthread_cond_broadcast),觸發多個等待的線程。

 

4.3、AliOS Things上POSIX接口實現

AliOS Things 支持了pthread,semaphore, message queue, timer, fs等多個模塊的豐富的API,開發者可以利用這些POSIX API,只需要簡單地修改,甚至無需修改,就可以移植Unix/Linux的應用到AliOS Things上。再結合HaaS100的開發板,開發者可以更快速地構建智能設備所需的軟件和硬件。

 

5、動手試試

5.1、寫一個Linux下基於POSIX接口的應用

下面動手編寫一個簡單的使用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) {
        sleep(1);
        pthread_mutex_lock(&count_lock);
        count++;
        printf("In main thread: count:%d\n", count);
        pthread_mutex_unlock(&count_lock);
    }
    
    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

5.2、移植到AliOS Things上

把上面的pthread_test.c 移植到AliOS Things上,改寫application/example/helloworld_demo 這個demo應用。 把pthread_test.c 的內容替換application/example/helloworld_demo/appdemo.c的全部內容,並做如下2個簡單的修改。

$ diff -ru ~/app/pthread_test.c  ~/project/gitee/AliOS-Things/AliOS-Things/application/example/helloworld_demo/appdemo.c 
--- ~/app/pthread_test.c	2020-12-10 23:02:56.915084914 +0800
+++ ~/project/gitee/AliOS-Things/AliOS-Things/application/example/helloworld_demo/appdemo.c	2020-12-10 23:06:10.616376591 +0800
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <pthread.h>
+#include <posix/pthread.h>
 
 static volatile int count = 1;
 pthread_mutex_t count_lock;
@@ -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。  AliOS Things上的posix頭文件在posix目錄下,如posix/pthread.h。

 

編譯helloworld_demo

aos make helloworld_demo@haas100 -c config
aos make

下載燒錄並啓動,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

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

移植Linux下應用到AliOS Things之下是不是很簡單,一起來試試吧。

 

6、參考鏈接

POSIX.1-2017

AliOS Things物聯網操作系統

 

7、開發者技術支持

如需更多技術支持,可加入釘釘開發者羣

更多技術與解決方案介紹,請訪問阿里雲AIoT首頁https://iot.aliyun.com/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章