近些年,大量的智能设备已经进入人们的生活, 如智能音箱,各种支付设备,大街小巷上各种大小的广告机等。这些设备中大多还是采用Linux,带屏的设备则大多采用Android,导致他们必须采用较高成本的硬件。
AliOS Things是阿里云IoT研发的应用于物联网智能设备的嵌入式实时操作系统,是HaaS100搭载的操作系统。目前AliOS Things + 小程序框架已经可以替代Linux甚至Android,大大降低设备的成本。可是Linux(包括Android)上的成熟稳定的框架,尤其是音视频处理的框架,图形渲染等,如果可以拿来使用,再加以适配优化,不需要重复造轮子,岂不美哉。
那如何把Unix/Linux这些优秀的框架轻松地移植到AliOS Things上呢?支持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,其关系如下图。
AliOS Things作为一个物联网领域的嵌入式实时操作系统为什么要支持POSIX标准呢?除了解决前言引入的问题外,还有没有其他的目的呢?本章节将进行一个全面的阐述。
软件生态
软件生态是一个OS的生存核心,但建设一个OS的软件生态又不能急于求成, 需要经过多年的积累沉淀。 显然AliOS Things的生态还不成熟,而Linux的生态则经过了几十年的沉淀,变得非常强大。支持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。
POSIX作为内核与应用的接口层, 涉及到内核的多个方面。 下面仅以POSIX线程和POSIX条件变量为例介绍其设计与实现,POSIX组件的代码位于core/osal/posix/, 头文件位于include/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会关联到这个数据结构上。
POSIX线程的创建与销毁
使用pthread_create创建POSIX线程。
使用pthread_exit销毁一个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条件变量的核心数据结构。
POSIX条件变量的处理
POSIX 条件变量不仅支持触发单个等待的线程,同时还支持广播(pthread_cond_broadcast),触发多个等待的线程。
AliOS Things 支持了pthread,semaphore, message queue, timer, fs等多个模块的丰富的API,开发者可以利用这些POSIX API,只需要简单地修改,甚至无需修改,就可以移植Unix/Linux的应用到AliOS Things上。再结合HaaS100的开发板,开发者可以更快速地构建智能设备所需的软件和硬件。
下面动手编写一个简单的使用POSIX PTHREAD API的Linux应用,保存为pthread_test.c
#include
#include
#include
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
把上面的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
#include
-#include
+#include
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]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之下是不是很简单,一起来试试吧。
POSIX.1-2017
AliOS Things物联网操作系统
如需更多技术支持,可加入钉钉开发者群
更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/