前言

在开发实时应用时,我们希望软件具备良好的跨平台和可移植,既能在实时linux也能在RTOS上工作,为实现这个目的,我们会选择使用POSIX API来设计实时应用,实现在不同的操作系统和平台上的可移植性。这样只要有POSIX支持,应用程序从一个操作系统移植到另一个操作系统,无需对源代码进行较大的修改,可以减少很多重复工作(想象很美好)。

但是,实时应用除关注接口基本功能一致外,还关注接口的实时性(执行时间确定性),那不同的实时操作系统的POSIX底层实现/行为实不实时呢?

以精确定时为例,精确定时是我们常用的操作系统服务之一,比如工业以太网(ECAT、PN...)中的通信周期,通信周期的准确控制离不开精确定时;在无线基站和终端的slot调度中,精确定时确保了数据传输的有序与高效;在实时仿真中,仿真步长的精确控制更是模拟真实场景的关键等等,这些都离不开POSIX定时接口。

本文首先简要概述POSIX标准,随后深入剖析POSIX定时接口在常用开放内核源码的RTOS(实时操作系统)上的上的实现原理做简单介绍。通过本文的介绍,希望能为读者在实际应用中提供有价值的参考,避免在RTOS中使用POSIX遇到不必要的困扰。

POSIX简介

POSIX是 IEEE(Institue of Electrical and Electronics Engineers,电气和电子工程师学会)为了规范各种 UNIX 操作系统提供的 API 接口而定义的一系列互相关联标准的总称,其正式称呼为 IEEE1003,国际标准名称为 ISO / IEC9945。此标准源于一个大约开始于 1985 年的项目。

POSIX 这个名称是由理查德 · 斯托曼(Richard Stallman)应 IEEE 的要求而提议的一个易于记忆的名称。它是 Portable Operating System Interface(可移植操作系统接口)的缩写,而 X 则表明其对 Unix API 的传承。POSIX更能正确表示这一系列相关标准,所以术语POSIX最初被用作IEEE Std 1003.1-1988的同义词,即POSIX.1(n=1)。这保持了符号“POSIX”可读性的优点,而不会与POSIX系列标准产生歧义。

关于有关POSIX. 1的背景、受众和目的的更多信息,参看该链接https://www.opengroup.org/austin/papers/backgrounder.html

https://www.opengroup.org/austin/papers/posix_faq.html

POSIX标准涉及操作系统方方面面,我们主要关注以下两个标准:

  • IEEE Std 1003.1"便携式操作系统接口 (POSIX)"--最初主要针对 UNIX 系统,1988 年第一版,2018 年最新版
  • IEEE Std 1003.13 "标准化应用环境配置文件(AEP)--POSIX 实时和嵌入式应用支持"

IEEE Std 1003.1标准,最初只用于UNIX系统。POSIX定义了一系列应用程序编程接口(API),用于在源代码级别实现可移植性。POSIX最早发布于1988年,最新版本于2018年发布。它提供了一种标准化的应用程序环境配置文件(AEP),用于实现实时和嵌入式应用程序的支持。通过遵循POSIX标准,开发人员可以编写与POSIX兼容的源代码,从而实现在不同的操作系统和平台上的可移植性。这使得开发人员能够更轻松地将应用程序从一个操作系统移植到另一个操作系统,而无需对源代码进行较大的修改。

POSIX.13(IEEE Std 1003.13)对实时和嵌入式应用程序的支持:IEEE Std 1003.13-2003是一个针对实时系统的标准,提供了对嵌入式应用程序的支持,实时配置文件可总结如下。该标准定义了几个实时系统Profiles,所有Profiles都包括部分或全部POSIX.1、.1b和.1c,以及开发平台的POSIX.2和.2a的部分内容,这些Profiles分别为PSE51、PSE52、PSE53和PSE54。

  • PSE51:最小实时配置文件(Minimal real-time)适用于资源受限的嵌入式系统。它提供了最基本的实时功能,包括任务调度、中断处理和简单的同步机制,这个子集不需要多进程(线程)和文件系统。
  • PSE52:实时控制器配置文件(Realtime controller)适用于需要严格的实时控制和调度的系统。它在PSE51的基础上增加了简单文件系统和消息队列等功能,提供了精确的任务调度、硬实时响应和实时数据处理能力。
  • PSE53:专用实时配置文件(Dedicated real-time)适用于需要高度可预测性和可靠性的实时系统。它提供了多进程、网络支持,更强大的实时功能,包括任务优先级管理、严格的时间限制和实时资源管理。
  • PSE54:多用途实时配置文件(Multi-purpose real-time)适用于需要同时支持多种实时应用的系统。它提供了完整的文件系统、shell,灵活的任务调度、多任务并发和多种实时通信机制。

综上,PSOXI标准不仅包含应用开发时常说的POSIX API,还包括文件系统、网络、shell等整个应用程序的运行环境。

目前符合 POSIX 标准协议的操作系统有:UNIX、BSD、Linux、iOS、Android、SylixOS、VxWorks、RTEMS、LynxOS 等,由于这些OS对 POSIX 的支持,其他兼容 POSIX 系统上的应用程序可以非常方便地移植到这些系统上。

RTOS对POSIX的实现情况

这里简单介绍几个常用RTOS的POSIX支持情况:

RTOS POSIX支持情况
PREEMPT-RT 完全兼容
Xenomai 完全兼容,实时部分xenomai内核和libcobalt提供,非实时部分linux内核和glibc提供
VxWorks User space(RTP):POSIX.13 PSE52 (少数接口存在限制)Kernel space:POSIX.1部分接口和POSIX.1可选功能中的一些实时接口
RTEMS POSIX 1003.1b-1993. POSIX 1003.1b-1993。POSIX 1003.1h/D3.Open Group Single UNIX Specification.单进程;
SylixOS 兼容IEEE 1003(ISO/IEC 9945)操作系统接口规范兼容POSIX 1003.1b(ISO/IEC 9945-1)实时编程的标准
Zephry PSE54
EcOS 3.0 ISO/IEC 9945—1(少部分省略)
FreeRTOS 实验性,仅实现了约 20% 的 POSIX API
RT-Thread 未找到明确说明,从源码上看兼容大部分POSIX

Zephyr

详见Zephyr开发文档https://docs.zephyrproject.org/latest/samples/posix/philosophers/README.html

Zephyr支持路线图 https://static.sched.com/hosted_files/eoss24/40/ZDS-2024-POSIX-Roadmap-for-Zephyr-LTSv3.pdf

FreeRTOS

FreeRTOS-Plus-POSIX 可实现 POSIX 线程 API 的小子集。借助此子集,熟悉 POSIX API 的应用程序开发者可使用类似线程原语的 POSIX 开发 FreeRTOS 应用程序。FreeRTOS-Plus-POSIX 仅实现了约 20% 的 POSIX API。因此,无法仅使用此包装器将现有的 POSIX 兼容应用程序或 POSIX 兼容库移植到 FreeRTOS 内核上运行。

FreeRTOS-Plus-POSIX 实现了部分 IEEE Std 1003.1-2017 版《开放组技术标准基础规范》,第 7 期。FreeRTOS-Plus-POSIX 包括以下 POSIX 线程标头文件的实现,详细信息请参阅FreeRTOS-Plus-POSIX API文档了解。

需要注意的是:FreeRTOS posix接口不支持动态创建任务,即开始调度后不能再创建新的任务。

RTOS提供的POSIX接口实时吗?

在实时应用场景中,精确定时是我们常用的接口,比如工业以太网ECAT、PN中的通信周期,无线基站/终端中的slot调度,实时仿真中的仿真步长等等。

POSIX中常用的定时接口有nanosleep()、clock_nanosleep()、timer_create()/timer_settime()等,但这些RTOS实现的POSIX实时吗?或者说定时精度如何?

nanosleep

在POSIX标准中,对nanosleep()睡眠时间分辨率的定义为1/HZ,即操作系统的Tick周期时间,意味着实际睡眠分辨率与系统时钟滴答周期近似,下表总结了常见RTOS的nanosleep()底层实现及精度,从标准上看,这些RTOS都符合POSIX标准,但HZ不足以支撑很多us级定时应用场景。

RTOS 实现原理 精度
PREEMPT-RT 高精度hrtimer,每次定时最终由硬件timer中断handler中唤醒 ns
Xenomai 高精度hrtimer,每次定时最终由硬件timer中断handler中唤醒 ns
VxWorks 睡眠时间转换对齐到Tick Tick
RTEMS
SylixOS 未启用LW_CFG_TIME_HIGH_RESOLUTION_EN时,睡眠时间转换为Tick,每个Tick中统一处理;启用LW_CFG_TIME_HIGH_RESOLUTION_EN后,CPU不足一个Tcik的nanosleep转换为while(1)死等时间到达 Tick或ns
Zephry 睡眠时间转换为Tick Tick
EcOS 3.0 睡眠时间转换为Tick Tick
FreeRTOS 睡眠时间转换为Tick Tick
RT-Thread 5.x版本虽然实现了hrtimer逻辑,但是你用时会发现是个半成品,可以选择一个硬件Timer来实现hrtimer底层定时,但是这样每次只能有一个任务处于定时状态(用全局变量来维护timer的参数,且ctime层 hrtime、cputime接口职责隔离不清晰,无可扩展性,可以看出"能跑就行",质量堪忧);默认情况下还是基于Tick。 Tick或ns

这里不得不提一下,一些操作系统所宣传的ns级延时,基本指的是逻辑如下,对于用惯了xenomai/Peempt-RT的hrtimer来说,不明白CPU死等的方式有什么值得宣传的(这让我想起了郭天祥...)。

udeley(){
do {
从硬件读取当前时间;
} while (当前时间未到达指定时间);
}

Timer-不同linux版本和xenomai的实现差异

计时器管理器提供的服务包括:

  • timer_create - 创建每进程定时器
  • timer_delete - 删除每进程定时器
  • timer_settime - 设置下一个定时器的到期时间
  • timer_gettime - 获取定时器的剩余时间
  • timer_getoverrun - 获取定时器超时计数

在xenomai中,我们通常会通过如下方式来定时触发周期任务:

sev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_ptr = &timerid;
sev.sigev_notify_thread_id = get_thread_pid(); /*timer create*/
timer_create(CLOCK_MONOTONIC, &sev, &timerid); /* Start the timer */
timer_overrun = timer_getoverrun(timerid); /*get current time*/
err = clock_gettime(CLOCK_MONOTONIC, &now); tspec.it_value = now;
tspec.it_value.tv_sec += 0;
tspec.it_value.tv_nsec += 2000000;
tsnorm(&tspec.it_value);
tspec.it_interval.tv_sec = 0;
tspec.it_interval.tv_nsec = 1000000; /**/
timer_settime(timerid, TIMER_ABSTIME, &tspec, NULL);
while (1)
s = sigwait(&GlobalSignalMaskSet, &sig);
/*.............*/
}

但是,PREEMPT-RT和xenomai中关于timer的接口底层实现有区别:

PREEMPT-RT Timer实现原理

大家都知道,linux中断分为上半部和下半部,未启用PREEMPT-RT时,上半部表示硬件中断上下文,即响应中断就直接执行中断上半部;

启用PREEMPT-RT后,有所不同,通常上半部由中断线程来处理,即中断产生后,唤醒中断线程来处理中断上半部,此时中断上半部在线程上下文执行。并不是所有中断都是中断线程来执行,比如系统Timer中断就是不能中断线程化的,还是在硬件中断上下执行。对于中断下半部,基本没有变化,还是由softirq、workqueue线程等执行。

linux内核中,进程创建的每个timer都会对应内核中高精度timer的一个对象,这些hrtimer用红黑树组织,所有timer最后由硬件timer中断驱动运行,运行原理如下:

  • 未启用PREEMPT-RT时,hrtimer由Hrtimer softirq驱动,即硬件定时超时,唤醒软中断处理,软中断线程检查hrtimer超时情况,并调用对应的超时处理函数,超时处理函数中会唤醒对应的线程;
  • 启用PREEMPT-RT后,情况有所有不同,在PREEMPT-RT中,hrtimer分为两类,一类是在硬中断上下执行超时回调(HRTIMER_MODE_HARD),一类在软中断上下文执行超时回调(HRTIMER_MODE_SOFT);
    • 对于HRTIMER_MODE_HARD因为在中断上下文执行的超时回调,时延低,任务定时精度高;
    • 对于HRTIMER_MODE_SOFT timer,软中断到期模式的高精度定时器,到期的时候在类型为HRTIMER_SOFTIRQ的软中断里面执行定时器回调函数。在实时内核中,软中断由软中断线程执行,或者在进程开启软中断的时候执行,任务时延高定时不精确。
    • 如果没有指定到期模式,那么在实时内核中默认使用软中断到期模式。

那PREEMPT-RT中,POSIX API底层用的是HRTIMER_MODE_HARD还是HRTIMER_MODE_SOFT?

API timer类型
nanosleep()clock_nanosleep() HRTIMER_MODE_HARD
timer_create()+timer_settime() 4.16版本以前高精度定时器总是在硬中断里面执行定时器回调函数,所以timer相关接口定时精确,详见https://www.spinics.net/lists/kernel/msg3208465.html4.16版本及以后版本增加HRTIMER_MODE_SOFT,timer系列接口定时不再精确(不实时,抖动大)。

Xenomai Timer实现原理

原理,详见本博客博文xenomai时间子系统

xenomai内核提供的所有POSIX接口都是实时的。

总结

我们仅比较了两个实时应用常见API在不同RTOS中的实现,应该明白,POSIX只是一个API标准,不同的系统底层实现不同,我们在将我们的实时任务移植适配到不同的RTOS的时候,需要事先评估用到的POSIX接口在这些RTOS上的实时行为与我们的期待是否相符。

参考

https://www.baeldung.com/linux/posix

https://unix.stackexchange.com/questions/11983/what-exactly-is-posix

https://static.sched.com/hosted_files/eoss2023/2e/Zephyr RTOS - Posix.pdf

VxWorks_7_programmers_guide.pdf

https://docs.rtems.org/branches/master/posix-users/index.html

https://ecos.sourceware.org/docs-latest/ref/posix-standard-support.html

【原创】不同RTOS POSIX接口的实现差异的更多相关文章

  1. 消息队列接口API(posix 接口和 system v接口)

    消息队列 posix API 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.信号这种通信方式更像\"即时\"的通信方式,它要求接受信号的进程在某个时间范围内对信 ...

  2. windows qt 使用c++ posix接口编写多线程程序(真神奇)good

    一.多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序.一般情况下,两种类型的多任务处理:基于进程和基于线程.基于进程的多任务处理是程序的并发执行.基于线程的多任务处理 ...

  3. C#提供APP接口之JSON差异

    C#在给APP提供接口,现在返回的数据大部分分为三类:JSON.XML.BTYE. 今天简单说下C#给APP提供接口返回JSON的一些异同: 1.通过Newtonsoft.Json.JsonConve ...

  4. pjd-fstest The test suite checks POSIX compliance - 测试文件系统posix 接口兼容性

    pjd-fstest: 参考网址:https://www.tuxera.com/community/posix-test-suite/ fstest是一套简化版的文件系统POSIX兼容性测试套件,它可 ...

  5. POSIX 进程间通信 (可移植操作系统接口)

    1.什么是POSIX标准 Portable Operating System Interface for Computing System. 他是一个针对操作系统(准确地说是针对类Unix操作系统)的 ...

  6. 【原创】xenomai与VxWorks实时性对比(资源抢占上下文切换对比)

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有问题,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ (下面数据,仅供个人参考) 可能大部分人一直好奇Vx ...

  7. 【原创】linux实时应用如何printf输出不影响实时性?

    版权声明:本文为本文为博主原创文章,转载请注明出处 https://www.cnblogs.com/wsg1100.如有错误,欢迎指正. @ 目录 1. 前言 2. linux终端输出 3. 常见的N ...

  8. [RTOS]--uCOS、FreeRTOS、RTThread、RTX等RTOS的对比之特点

    本篇博客就来细数这几个RTOS的特点.   以下内容均来自官方网站或者官方手册Feature的Google翻译的加了我的一些调整,没有任何主观成分. 1. FreeRTOS   FreeRTOS是专为 ...

  9. 浅入浅出 Go 语言接口的原理

    浅入浅出 Go 语言接口的原理 接口是 Go 语言的重要组成部分,它在 Go 语言中通过一组方法指定了一个对象的行为,接口 interface 的引入能够让我们在 Go 语言更好地组织并写出易于测试的 ...

  10. 聊聊我理解的ANSI C、ISO C、GNU C、POSIX C

    几句话了解C标准之间的关系 C语言标准 早期的计算机汇编语言是与机器平台紧密耦合的,为了屏蔽这种耦合,增加代码的可移植性,C语言随机出现. 二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异, ...

随机推荐

  1. Emmet Documentation ( Abbreviations+CSS Abbreviations )

    Emmet Documentation Emmet - the essential toolkit for web-developers Abbreviations Abbreviations Syn ...

  2. 强!10.6K star,一款开源HTTP测试工具,适合新手,简单、容易上手!

    大家好,我是狂师! 今天给大家推荐一款开源的HTTP测试工具:Hurl,相比curl.wget功能更强大,且更容易上手.很适用新手使用. 1.项目介绍 Hurl是一个使用Rust语言开发的命令行工具, ...

  3. #折半搜索,状压dp#nssl 1471 Y

    分析 设\(dp[i][j][s]\)表示从\(i\)到\(j\)的一条路径状态为\(s\)是否存在 但是这样肯定会T掉,考虑拼凑路径,分成两部分, 设\(dp[0/1][s]\)分别表示以某个起点/ ...

  4. 并发编程面试必备之ConcurrentHashMap源码解析

    ConcurrentHashMap在我的面试生涯中,10次有8次是会被问到的,记得刚毕业那会,被问到ConcurrentHashMap源码的无助与苦涩,无奈只能网上找了一些教程,背一背,才算是蒙混过关 ...

  5. Cert Manager 申请SSL证书流程及相关概念-二

    中英文对照表 英文 英文 - K8S CRD 中文 备注 certificates Certificate 证书 certificates.cert-manager.io/v1 certificate ...

  6. Gin

    0x01 准备 (1)概述 定义:一个 golang 的微框架 特点:封装优雅,API 友好,源码注释明确,快速灵活,容错方便 优势: 对于 golang 而言,web 框架的依赖要远比 Python ...

  7. k8s 深入篇———— 编排[八]

    前言 简单整理一下编排. 正文 一个deployment 例子: apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployme ...

  8. ionic 4 app 自动版本更新

    前言 介绍一下ionic4 app的自动更新.ionic 不多介绍了,后面一个后系列,背负着骂名的ionic其实还是可以的,如果刚入门ionic可能觉得很坑,但是呢,往后你就发现另外一件事,那就是其他 ...

  9. async/await 贴脸输出,这次你总该明白了

    出来混总是要还的 最近在准备记录一个.NET Go核心能力的深度对比, 关于.NET/Go的异步实现总感觉没敲到点上. async/await是.NET界老生常谈的话题,每至于此,状态机又是必聊的话题 ...

  10. 论文研究区域图的制作方法:ArcGIS

      本文介绍基于ArcMap软件,绘制论文中研究区域示意图.概况图等的方法.   最近需要绘制与地学有关论文.文献中的研究区域概况图.对于这一类图片,我个人比较喜欢基于ArcMap与PPT结合的方式来 ...