STVM OSAL 层架构设计文档
0. 架构总览
0.1 三层结构
#mermaid-svg-Ghc51OHw7uksTwHw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Ghc51OHw7uksTwHw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ghc51OHw7uksTwHw .error-icon{fill:#552222;}#mermaid-svg-Ghc51OHw7uksTwHw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ghc51OHw7uksTwHw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ghc51OHw7uksTwHw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ghc51OHw7uksTwHw .marker.cross{stroke:#333333;}#mermaid-svg-Ghc51OHw7uksTwHw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ghc51OHw7uksTwHw p{margin:0;}#mermaid-svg-Ghc51OHw7uksTwHw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ghc51OHw7uksTwHw .cluster-label text{fill:#333;}#mermaid-svg-Ghc51OHw7uksTwHw .cluster-label span{color:#333;}#mermaid-svg-Ghc51OHw7uksTwHw .cluster-label span p{background-color:transparent;}#mermaid-svg-Ghc51OHw7uksTwHw .label text,#mermaid-svg-Ghc51OHw7uksTwHw span{fill:#333;color:#333;}#mermaid-svg-Ghc51OHw7uksTwHw .node rect,#mermaid-svg-Ghc51OHw7uksTwHw .node circle,#mermaid-svg-Ghc51OHw7uksTwHw .node ellipse,#mermaid-svg-Ghc51OHw7uksTwHw .node polygon,#mermaid-svg-Ghc51OHw7uksTwHw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ghc51OHw7uksTwHw .rough-node .label text,#mermaid-svg-Ghc51OHw7uksTwHw .node .label text,#mermaid-svg-Ghc51OHw7uksTwHw .image-shape .label,#mermaid-svg-Ghc51OHw7uksTwHw .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ghc51OHw7uksTwHw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ghc51OHw7uksTwHw .rough-node .label,#mermaid-svg-Ghc51OHw7uksTwHw .node .label,#mermaid-svg-Ghc51OHw7uksTwHw .image-shape .label,#mermaid-svg-Ghc51OHw7uksTwHw .icon-shape .label{text-align:center;}#mermaid-svg-Ghc51OHw7uksTwHw .node.clickable{cursor:pointer;}#mermaid-svg-Ghc51OHw7uksTwHw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ghc51OHw7uksTwHw .arrowheadPath{fill:#333333;}#mermaid-svg-Ghc51OHw7uksTwHw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ghc51OHw7uksTwHw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ghc51OHw7uksTwHw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ghc51OHw7uksTwHw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ghc51OHw7uksTwHw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ghc51OHw7uksTwHw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ghc51OHw7uksTwHw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ghc51OHw7uksTwHw .cluster text{fill:#333;}#mermaid-svg-Ghc51OHw7uksTwHw .cluster span{color:#333;}#mermaid-svg-Ghc51OHw7uksTwHw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Ghc51OHw7uksTwHw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ghc51OHw7uksTwHw rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ghc51OHw7uksTwHw .icon-shape,#mermaid-svg-Ghc51OHw7uksTwHw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ghc51OHw7uksTwHw .icon-shape p,#mermaid-svg-Ghc51OHw7uksTwHw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ghc51OHw7uksTwHw .icon-shape .label rect,#mermaid-svg-Ghc51OHw7uksTwHw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ghc51OHw7uksTwHw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ghc51OHw7uksTwHw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ghc51OHw7uksTwHw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 唯一依赖入口
include osal.hpp
调用 13 个函数
OSAL 抽象层 ------ 1 个接口头 + 7 个后端实现
osal.hpp
4 类 13 个函数
osal.cpp 默认空实现
osal_linux.cpp
普通 / PREEMPT_RT / Xenomai
osal_windows.cpp
MSVC / MinGW
osal_freertos.cpp
V10+
osal_rtthread.cpp
v4.x+
osal_vxworks.cpp
6.x / 7.x
STVM 核心运行时 ------ 零 OS 依赖
VM.cpp
指令执行循环
Scheduler.cpp
PLC 顺序扫描
BytecodeProgram
字节码内存模型
IecCodegen / IecSymbolTable
编译期,不进 lib
cpu_affinity.cpp
向后兼容 wrapper
宿主应用(自由选择 OS)
stvm-run (Linux 命令行)
STM32 FreeRTOS 任务
i.MX8M RT-Thread 线程
PREEMPT_RT PLC 主循环
SylixOS 国产系统
VxWorks 7 硬实时任务
0.2 依赖方向(单向、无环)
宿主应用 → STVM 核心运行时 → OSAL 抽象层 → OS 后端实现
↑ ↓
└──────────────────────────────────────────┘
无反向依赖
关键保证:
- OSAL 后端可以独立替换(链接时选择)
- STVM 核心
#include "stvm/osal.hpp",永远不会#include <sched.h>/<windows.h>/<FreeRTOS.h> - 7 个后端实现文件内部用
#ifdef保护------没有对应 OS 头文件时自动 fallback 到空实现,在任何平台都能编译通过
1. 核心运行时的零 OS 依赖设计
1.1 STVM 的 PLC 扫描模型天然隔离 OS
#mermaid-svg-iYHN3afb7vSN4uHd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iYHN3afb7vSN4uHd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iYHN3afb7vSN4uHd .error-icon{fill:#552222;}#mermaid-svg-iYHN3afb7vSN4uHd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iYHN3afb7vSN4uHd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iYHN3afb7vSN4uHd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iYHN3afb7vSN4uHd .marker.cross{stroke:#333333;}#mermaid-svg-iYHN3afb7vSN4uHd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iYHN3afb7vSN4uHd p{margin:0;}#mermaid-svg-iYHN3afb7vSN4uHd defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-iYHN3afb7vSN4uHd g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-iYHN3afb7vSN4uHd g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-iYHN3afb7vSN4uHd g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-iYHN3afb7vSN4uHd g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-iYHN3afb7vSN4uHd g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-iYHN3afb7vSN4uHd .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-iYHN3afb7vSN4uHd .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-iYHN3afb7vSN4uHd .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-iYHN3afb7vSN4uHd .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-iYHN3afb7vSN4uHd .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-iYHN3afb7vSN4uHd .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-iYHN3afb7vSN4uHd .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-iYHN3afb7vSN4uHd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iYHN3afb7vSN4uHd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iYHN3afb7vSN4uHd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iYHN3afb7vSN4uHd .edgeLabel .label text{fill:#333;}#mermaid-svg-iYHN3afb7vSN4uHd .label div .edgeLabel{color:#333;}#mermaid-svg-iYHN3afb7vSN4uHd .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-iYHN3afb7vSN4uHd .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-iYHN3afb7vSN4uHd .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-iYHN3afb7vSN4uHd .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-iYHN3afb7vSN4uHd .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-iYHN3afb7vSN4uHd .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iYHN3afb7vSN4uHd .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iYHN3afb7vSN4uHd #statediagram-barbEnd{fill:#333333;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iYHN3afb7vSN4uHd .cluster-label,#mermaid-svg-iYHN3afb7vSN4uHd .nodeLabel{color:#131300;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-iYHN3afb7vSN4uHd .note-edge{stroke-dasharray:5;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-note text{fill:black;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram-note .nodeLabel{color:black;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagram .edgeLabel{color:red;}#mermaid-svg-iYHN3afb7vSN4uHd #dependencyStart,#mermaid-svg-iYHN3afb7vSN4uHd #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-iYHN3afb7vSN4uHd .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iYHN3afb7vSN4uHd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Scheduler 构造
首次 runOnce()
set_thread_affinity(cfg.cpu_affinity)
检查周期任务是否到期
clock_us_ += tick
所有任务 FINISHED / ERROR
Init
FirstRun
BindAffinity
顺序扫描所有 ready tasks
CheckPeriodic
AdvanceClock
Exit
主循环完全是
纯内存数据结构操作
无阻塞、无 sleep
无真实系统调用
Scheduler 的 clock_us_ 是虚拟时钟:
| 方式 | API 调用 | 说明 |
|---|---|---|
| 默认(零 OS 依赖) | 无 | runOnce() 内部手动 clock_us_ += tick_us |
| 可选真实时钟 | osal::get_time_us() |
宿主设置时,每个 runOnce() 前读一次 |
| 两者对比 | 虚拟时钟:确定性行为;真实时钟:受系统负载影响 | PLC 硬实时要求通常用虚拟时钟 |
1.2 剥离前 vs 剥离后的依赖面
| 依赖类型 | 剥离前 | 剥离后 | 现在 |
|---|---|---|---|
| 多线程 API | 无(好) | 无 | ✅ 保持 |
| 真实时钟 API | 无(好) | 无 | ✅ 保持 |
| CPU 亲和性 | sched_setaffinity / SetThreadAffinityMask |
→ osal::set_thread_affinity() |
✅ 隔离 |
| 文件 IO | std::fopen/fread/fwrite |
→ osal::file_open/read/write |
✅ 隔离 |
| trace 输出 | std::fopen |
→ osal::file_open |
✅ 隔离 |
2. OSAL API 详细设计
2.1 API 全景(4 类 13 个函数)
#mermaid-svg-jHMLG5K4wPflasqq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jHMLG5K4wPflasqq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jHMLG5K4wPflasqq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jHMLG5K4wPflasqq .error-icon{fill:#552222;}#mermaid-svg-jHMLG5K4wPflasqq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jHMLG5K4wPflasqq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jHMLG5K4wPflasqq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jHMLG5K4wPflasqq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jHMLG5K4wPflasqq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jHMLG5K4wPflasqq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jHMLG5K4wPflasqq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jHMLG5K4wPflasqq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jHMLG5K4wPflasqq .marker.cross{stroke:#333333;}#mermaid-svg-jHMLG5K4wPflasqq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jHMLG5K4wPflasqq p{margin:0;}#mermaid-svg-jHMLG5K4wPflasqq g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-jHMLG5K4wPflasqq g.classGroup text .title{font-weight:bolder;}#mermaid-svg-jHMLG5K4wPflasqq .cluster-label text{fill:#333;}#mermaid-svg-jHMLG5K4wPflasqq .cluster-label span{color:#333;}#mermaid-svg-jHMLG5K4wPflasqq .cluster-label span p{background-color:transparent;}#mermaid-svg-jHMLG5K4wPflasqq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jHMLG5K4wPflasqq .cluster text{fill:#333;}#mermaid-svg-jHMLG5K4wPflasqq .cluster span{color:#333;}#mermaid-svg-jHMLG5K4wPflasqq .nodeLabel,#mermaid-svg-jHMLG5K4wPflasqq .edgeLabel{color:#131300;}#mermaid-svg-jHMLG5K4wPflasqq .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-jHMLG5K4wPflasqq .label text{fill:#131300;}#mermaid-svg-jHMLG5K4wPflasqq .labelBkg{background:#ECECFF;}#mermaid-svg-jHMLG5K4wPflasqq .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-jHMLG5K4wPflasqq .classTitle{font-weight:bolder;}#mermaid-svg-jHMLG5K4wPflasqq .node rect,#mermaid-svg-jHMLG5K4wPflasqq .node circle,#mermaid-svg-jHMLG5K4wPflasqq .node ellipse,#mermaid-svg-jHMLG5K4wPflasqq .node polygon,#mermaid-svg-jHMLG5K4wPflasqq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jHMLG5K4wPflasqq .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq g.clickable{cursor:pointer;}#mermaid-svg-jHMLG5K4wPflasqq g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-jHMLG5K4wPflasqq g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-jHMLG5K4wPflasqq .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-jHMLG5K4wPflasqq .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-jHMLG5K4wPflasqq .dashed-line{stroke-dasharray:3;}#mermaid-svg-jHMLG5K4wPflasqq .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-jHMLG5K4wPflasqq #compositionStart,#mermaid-svg-jHMLG5K4wPflasqq .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #compositionEnd,#mermaid-svg-jHMLG5K4wPflasqq .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #dependencyStart,#mermaid-svg-jHMLG5K4wPflasqq .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #dependencyStart,#mermaid-svg-jHMLG5K4wPflasqq .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #extensionStart,#mermaid-svg-jHMLG5K4wPflasqq .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #extensionEnd,#mermaid-svg-jHMLG5K4wPflasqq .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #aggregationStart,#mermaid-svg-jHMLG5K4wPflasqq .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #aggregationEnd,#mermaid-svg-jHMLG5K4wPflasqq .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #lollipopStart,#mermaid-svg-jHMLG5K4wPflasqq .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq #lollipopEnd,#mermaid-svg-jHMLG5K4wPflasqq .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-jHMLG5K4wPflasqq .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-jHMLG5K4wPflasqq .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jHMLG5K4wPflasqq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jHMLG5K4wPflasqq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jHMLG5K4wPflasqq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} <<namespace>>
osal
+"get_time_us() : uint64_t"
+"file_open(path, mode) : FileHandle"
+"file_read(h, buf, n) : size_t"
+"file_write(h, buf, n) : size_t"
+"file_seek(h, off, whence) : int"
+"file_tell(h) : long"
+"file_close(h) : int"
+"set_thread_affinity(core_id) : bool"
+"reset_thread_affinity() : bool"
+"get_core_count() : int"
+"set_thread_priority(policy, priority) : bool"
+"reset_thread_priority() : bool"
<<typedef>>
FileHandle
uintptr_t
<<enum>>
OpenMode
ReadBinary
WriteBinary
<<enum>>
SchedPolicy
Other
Fifo
Rr
2.2 时基
cpp
uint64_t get_time_us();
| 后端 | 实现 | 精度 | 备注 |
|---|---|---|---|
| Linux 普通 | clock_gettime(CLOCK_MONOTONIC) |
~1μs | 受 NTP 调整影响 |
| Linux PREEMPT_RT | clock_gettime(CLOCK_MONOTONIC_RAW) |
< 100ns | 不受 NTP 影响,硬实时要求 |
| Linux Xenomai | clock_gettime(CLOCK_MONOTONIC) |
< 5μs | 通过 RTDM 桥接 rt_clock |
| Windows | QueryPerformanceCounter |
~200ns | 硬件计数器 |
| FreeRTOS | xTaskGetTickCount() * TICK_US |
tick 周期 | 默认 1ms,可配 |
| RT-Thread | rt_tick_get() * (1e6 / RT_TICK_PER_SECOND) |
tick 周期 | |
| VxWorks | tickGet() * 1e6 / sysClkRateGet() |
tick 周期 | |
| 空实现 | 返回 0 | - | Scheduler 用虚拟时钟 |
2.3 文件 IO
cpp
using FileHandle = uintptr_t; // opaque handle,不暴露底层 FILE*/fd
constexpr FileHandle INVALID_FILE = 0;
enum class OpenMode { ReadBinary, WriteBinary };
FileHandle file_open (const char* path, OpenMode mode);
size_t file_read (FileHandle h, void* buf, size_t n);
size_t file_write(FileHandle h, const void* buf, size_t n);
int file_seek (FileHandle h, long offset, int whence);
long file_tell (FileHandle h);
int file_close(FileHandle h);
| 后端 | FileHandle 实际值 | 实现 |
|---|---|---|
| Linux / Windows | FILE* |
std::fopen/fread/fwrite |
| SylixOS / FreeRTOS FatFs | fd (int) |
POSIX open/read/write/lseek/close |
| RT-Thread | fd (int) |
dfs POSIX 层 开箱即用 |
| VxWorks | FILE* |
fopen/fread/fwrite |
| FreeRTOS 无 FatFs / 裸机 | INVALID_FILE |
返回失败 |
2.4 CPU 亲和性
cpp
bool set_thread_affinity(int core_id); // -1 表示取消绑定
bool reset_thread_affinity();
int get_core_count();
| 后端 | API | 粒度 |
|---|---|---|
| Linux / SylixOS | pthread_setaffinity_np |
线程级(而非进程级) |
| Windows | SetThreadAffinityMask |
线程级 |
| VxWorks 7 | taskCpuSetAffinity |
任务级 |
| FreeRTOS | ❌ false | 原生不支持 |
| RT-Thread v5.x | rt_thread_setaffinity |
线程级 |
| 空实现 | false / 1 | - |
2.5 调度优先级
cpp
enum class SchedPolicy { Other, Fifo, Rr };
bool set_thread_priority(SchedPolicy policy, int priority);
bool reset_thread_priority();
语义映射(核心难点):
| OS | 优先级语义 | osal 映射 |
|---|---|---|
| Linux | SCHED_FIFO/RR: 1-99(越大越高) | 直接用(osal Fifo + 50 → Linux SCHED_FIFO 50) |
| RT-Thread | 数字越大越高(与 Linux 同向) | 直接用 |
| VxWorks | 数字越小越高(与 Linux 反向!) | 翻转:osal 50 → VxWorks 200(250-50) |
| FreeRTOS | 数字越大越高 | ❌ 返回 false(无 SCHED_OTHER/FIFO 区分语义) |
| Windows | 不支持硬实时策略 | ❌ false |
3. 后端实现详解
3.1 文件布局
src/platform/osal/
├── osal.cpp ← 默认空实现(任何 OS 能链接)
├── osal_linux.cpp ← Linux / WSL / Android / PREEMPT_RT / Xenomai
├── osal_windows.cpp ← MSVC / MinGW
├── osal_freertos.cpp ← FreeRTOS V10+
├── osal_rtthread.cpp ← RT-Thread v4.x+
└── osal_vxworks.cpp ← VxWorks 6.x / 7.x
3.2 #ifdef 保护策略
每个后端文件内部三层防护:
cpp
// 层 1:OS 平台判断(最外层)
#if defined(__linux__) || defined(__APPLE__) || defined(__ANDROID__)
// 层 2:具体组件判断(FreeRTOS/RT-Thread/VxWorks 有条件编译的内部功能)
#if defined(configNUMBER_OF_CORES) && configNUMBER_OF_CORES > 1
return configNUMBER_OF_CORES;
#endif
// 层 3:兜底------fallback 到空实现
#else // !__linux__
namespace stvm::osal { /* 空实现 */ }
#endif
效果:
- 在 Windows/MSVC 上只选
osal_windows.cpp,其他 6 个文件因#ifdef不满足整文件编译为空 - 在 Linux 上选
osal_linux.cpp,其他文件同理自动空化 - 避免链接多个后端产生符号冲突
3.3 Linux 后端:PREEMPT_RT / Xenomai 自动检测
#mermaid-svg-4ybpYbanr3n3ygid{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4ybpYbanr3n3ygid .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4ybpYbanr3n3ygid .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4ybpYbanr3n3ygid .error-icon{fill:#552222;}#mermaid-svg-4ybpYbanr3n3ygid .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4ybpYbanr3n3ygid .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4ybpYbanr3n3ygid .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4ybpYbanr3n3ygid .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4ybpYbanr3n3ygid .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4ybpYbanr3n3ygid .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4ybpYbanr3n3ygid .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4ybpYbanr3n3ygid .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4ybpYbanr3n3ygid .marker.cross{stroke:#333333;}#mermaid-svg-4ybpYbanr3n3ygid svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4ybpYbanr3n3ygid p{margin:0;}#mermaid-svg-4ybpYbanr3n3ygid .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4ybpYbanr3n3ygid .cluster-label text{fill:#333;}#mermaid-svg-4ybpYbanr3n3ygid .cluster-label span{color:#333;}#mermaid-svg-4ybpYbanr3n3ygid .cluster-label span p{background-color:transparent;}#mermaid-svg-4ybpYbanr3n3ygid .label text,#mermaid-svg-4ybpYbanr3n3ygid span{fill:#333;color:#333;}#mermaid-svg-4ybpYbanr3n3ygid .node rect,#mermaid-svg-4ybpYbanr3n3ygid .node circle,#mermaid-svg-4ybpYbanr3n3ygid .node ellipse,#mermaid-svg-4ybpYbanr3n3ygid .node polygon,#mermaid-svg-4ybpYbanr3n3ygid .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4ybpYbanr3n3ygid .rough-node .label text,#mermaid-svg-4ybpYbanr3n3ygid .node .label text,#mermaid-svg-4ybpYbanr3n3ygid .image-shape .label,#mermaid-svg-4ybpYbanr3n3ygid .icon-shape .label{text-anchor:middle;}#mermaid-svg-4ybpYbanr3n3ygid .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-4ybpYbanr3n3ygid .rough-node .label,#mermaid-svg-4ybpYbanr3n3ygid .node .label,#mermaid-svg-4ybpYbanr3n3ygid .image-shape .label,#mermaid-svg-4ybpYbanr3n3ygid .icon-shape .label{text-align:center;}#mermaid-svg-4ybpYbanr3n3ygid .node.clickable{cursor:pointer;}#mermaid-svg-4ybpYbanr3n3ygid .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-4ybpYbanr3n3ygid .arrowheadPath{fill:#333333;}#mermaid-svg-4ybpYbanr3n3ygid .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4ybpYbanr3n3ygid .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4ybpYbanr3n3ygid .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4ybpYbanr3n3ygid .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4ybpYbanr3n3ygid .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4ybpYbanr3n3ygid .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-4ybpYbanr3n3ygid .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4ybpYbanr3n3ygid .cluster text{fill:#333;}#mermaid-svg-4ybpYbanr3n3ygid .cluster span{color:#333;}#mermaid-svg-4ybpYbanr3n3ygid div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4ybpYbanr3n3ygid .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4ybpYbanr3n3ygid rect.text{fill:none;stroke-width:0;}#mermaid-svg-4ybpYbanr3n3ygid .icon-shape,#mermaid-svg-4ybpYbanr3n3ygid .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4ybpYbanr3n3ygid .icon-shape p,#mermaid-svg-4ybpYbanr3n3ygid .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-4ybpYbanr3n3ygid .icon-shape .label rect,#mermaid-svg-4ybpYbanr3n3ygid .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4ybpYbanr3n3ygid .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-4ybpYbanr3n3ygid .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-4ybpYbanr3n3ygid :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} XENO_SKIN 宏存在
/sys/kernel/realtime = 1
其他
osal_linux.cpp 加载
detectKernel
运行时检查
Xenomai
CLOCK_MONOTONIC
SCHED_FIFO 生效
PREEMPT_RT
CLOCK_MONOTONIC_RAW
SCHED_FIFO 生效
普通 Linux
CLOCK_MONOTONIC
SCHED_FIFO 可设但效果非实时
关键代码(osal_linux.cpp):
cpp
static LinuxKernelType detectKernel() {
#ifdef __XENO_SKIN__
return LinuxKernelType::Xenomai;
#else
std::ifstream rt("/sys/kernel/realtime");
if (!rt) return LinuxKernelType::Normal;
int v = 0; rt >> v;
return (v == 1) ? LinuxKernelType::PreemptRt : LinuxKernelType::Normal;
#endif
}
static const LinuxKernelType kKernelType = detectKernel(); // 进程启动时检测一次
3.4 VxWorks 后端:优先级语义翻转
VxWorks 的优先级语义(数字越小越高)与 Linux/RT-Thread(数字越大越高)完全相反。osal 接口统一用"越大越高"语义,VxWorks 后端需要内部翻转:
cpp
bool set_thread_priority(SchedPolicy, int priority) {
// osal priority 0..99(越大越高)→ VxWorks priority 250..151(越小越高)
int vx_prio = 250 - std::max(0, std::min(99, priority));
return taskPrioritySet(taskIdSelf(), vx_prio) == OK;
}
| osal priority | VxWorks priority | 含义 |
|---|---|---|
| 0 | 250 | 最低(接近 idle) |
| 50 | 200 | 中等 |
| 99 | 151 | 最高(给中断/系统任务留 0-150) |
3.5 RT-Thread 后端:dfs POSIX 开箱即用
RT-Thread 的 dfs(device file system)提供完整 POSIX 兼容层 ,包括 open/read/write/lseek/close------不需要额外挂载 FatFs,osal 的文件 IO 直接可用。
cpp
#include "dfs_posix.h" // POSIX 兼容层
FileHandle file_open(const char* path, OpenMode mode) {
int flags = (mode == OpenMode::ReadBinary) ? O_RDONLY
: (O_WRONLY | O_CREAT | O_TRUNC);
return static_cast<FileHandle>(::open(path, flags, 0));
}
3.6 FreeRTOS 后端:可选 FatFs
FreeRTOS 原生没有文件系统。文件 IO 需要宿主额外挂载 FatFs/LittleFS:
cmake
# 有 FatFs 时
cmake -DSTVM_OSAL_BACKEND=FREERTOS -DSTVM_FREERTOS_HAS_FATFS=1 ..
cpp
#if defined(STVM_FREERTOS_HAS_FATFS)
# include <fcntl.h>
# include <unistd.h>
FileHandle file_open(const char* path, OpenMode mode) { ... ::open(path, flags, 0644) ... }
#else
FileHandle file_open(const char*, OpenMode) { return INVALID_FILE; } // 空实现
#endif
4. CMake 集成
4.1 自动检测流程图
#mermaid-svg-Rcbae6HJaQgR6YmR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Rcbae6HJaQgR6YmR .error-icon{fill:#552222;}#mermaid-svg-Rcbae6HJaQgR6YmR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Rcbae6HJaQgR6YmR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Rcbae6HJaQgR6YmR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Rcbae6HJaQgR6YmR .marker.cross{stroke:#333333;}#mermaid-svg-Rcbae6HJaQgR6YmR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Rcbae6HJaQgR6YmR p{margin:0;}#mermaid-svg-Rcbae6HJaQgR6YmR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR .cluster-label text{fill:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR .cluster-label span{color:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR .cluster-label span p{background-color:transparent;}#mermaid-svg-Rcbae6HJaQgR6YmR .label text,#mermaid-svg-Rcbae6HJaQgR6YmR span{fill:#333;color:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR .node rect,#mermaid-svg-Rcbae6HJaQgR6YmR .node circle,#mermaid-svg-Rcbae6HJaQgR6YmR .node ellipse,#mermaid-svg-Rcbae6HJaQgR6YmR .node polygon,#mermaid-svg-Rcbae6HJaQgR6YmR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Rcbae6HJaQgR6YmR .rough-node .label text,#mermaid-svg-Rcbae6HJaQgR6YmR .node .label text,#mermaid-svg-Rcbae6HJaQgR6YmR .image-shape .label,#mermaid-svg-Rcbae6HJaQgR6YmR .icon-shape .label{text-anchor:middle;}#mermaid-svg-Rcbae6HJaQgR6YmR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Rcbae6HJaQgR6YmR .rough-node .label,#mermaid-svg-Rcbae6HJaQgR6YmR .node .label,#mermaid-svg-Rcbae6HJaQgR6YmR .image-shape .label,#mermaid-svg-Rcbae6HJaQgR6YmR .icon-shape .label{text-align:center;}#mermaid-svg-Rcbae6HJaQgR6YmR .node.clickable{cursor:pointer;}#mermaid-svg-Rcbae6HJaQgR6YmR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Rcbae6HJaQgR6YmR .arrowheadPath{fill:#333333;}#mermaid-svg-Rcbae6HJaQgR6YmR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Rcbae6HJaQgR6YmR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Rcbae6HJaQgR6YmR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Rcbae6HJaQgR6YmR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Rcbae6HJaQgR6YmR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Rcbae6HJaQgR6YmR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Rcbae6HJaQgR6YmR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Rcbae6HJaQgR6YmR .cluster text{fill:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR .cluster span{color:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Rcbae6HJaQgR6YmR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Rcbae6HJaQgR6YmR rect.text{fill:none;stroke-width:0;}#mermaid-svg-Rcbae6HJaQgR6YmR .icon-shape,#mermaid-svg-Rcbae6HJaQgR6YmR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Rcbae6HJaQgR6YmR .icon-shape p,#mermaid-svg-Rcbae6HJaQgR6YmR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Rcbae6HJaQgR6YmR .icon-shape .label rect,#mermaid-svg-Rcbae6HJaQgR6YmR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Rcbae6HJaQgR6YmR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Rcbae6HJaQgR6YmR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Rcbae6HJaQgR6YmR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 显式指定
AUTO 默认
Linux / Android
Windows
SylixOS
VxWorks
其他 / Generic
cmake ..
STVM_OSAL_BACKEND
AUTO/LINUX/WINDOWS/...
直接用指定值
CMAKE_SYSTEM_NAME?
osal_linux.cpp
osal_windows.cpp
osal_linux.cpp
POSIX 同 Linux
osal_vxworks.cpp
osal.cpp
默认空实现
4.2 CMake 核心代码(已在 CMakeLists.txt 中)
cmake
# 选项(STRING cache 类型,因为 AUTO 是字符串而非布尔)
set(STVM_OSAL_BACKEND "AUTO" CACHE STRING "OSAL backend")
set_property(CACHE STVM_OSAL_BACKEND PROPERTY STRINGS
AUTO LINUX WINDOWS FREERTOS RTTHREAD SYLIXOS VXWORKS BARE)
# 自动检测
if(STVM_OSAL_BACKEND STREQUAL "AUTO")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(_OSAL_BACKEND "LINUX")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(_OSAL_BACKEND "WINDOWS")
...
else()
set(_OSAL_BACKEND "${STVM_OSAL_BACKEND}")
endif()
# 源文件选择(每个文件内部有 #ifdef 保护)
if(_OSAL_BACKEND STREQUAL "LINUX")
list(APPEND STVM_SOURCES src/platform/osal/osal_linux.cpp)
elseif(...)
...
endif()
message(STATUS "OSAL backend : ${_OSAL_BACKEND}")
4.3 构建命令速查
| 场景 | 命令 |
|---|---|
| Linux / WSL(自动检测) | cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. |
| PREEMPT_RT 硬实时 | 同上(Linux 后端运行时自动检测 RT 内核) |
| SylixOS 交叉编译 | cmake -DCMAKE_SYSTEM_NAME=SylixOS .. |
| FreeRTOS + FatFs | cmake -DSTVM_OSAL_BACKEND=FREERTOS -DSTVM_FREERTOS_HAS_FATFS=1 -DFREERTOS_DIR=.. |
| RT-Thread | cmake -DSTVM_OSAL_BACKEND=RTTHREAD -DRTTHREAD_DIR=.. |
| VxWorks 7 | cmake -DSTVM_OSAL_BACKEND=VXWORKS -DCMAKE_C_COMPILER=cceppc .. |
| Windows MSVC | cmake -G "Visual Studio 18 2026" .. |
5. 核心代码改造点
5.1 改造清单(5 个文件)
#mermaid-svg-xctFIvYds9DZORyz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xctFIvYds9DZORyz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xctFIvYds9DZORyz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xctFIvYds9DZORyz .error-icon{fill:#552222;}#mermaid-svg-xctFIvYds9DZORyz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xctFIvYds9DZORyz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xctFIvYds9DZORyz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xctFIvYds9DZORyz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xctFIvYds9DZORyz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xctFIvYds9DZORyz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xctFIvYds9DZORyz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xctFIvYds9DZORyz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xctFIvYds9DZORyz .marker.cross{stroke:#333333;}#mermaid-svg-xctFIvYds9DZORyz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xctFIvYds9DZORyz p{margin:0;}#mermaid-svg-xctFIvYds9DZORyz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xctFIvYds9DZORyz .cluster-label text{fill:#333;}#mermaid-svg-xctFIvYds9DZORyz .cluster-label span{color:#333;}#mermaid-svg-xctFIvYds9DZORyz .cluster-label span p{background-color:transparent;}#mermaid-svg-xctFIvYds9DZORyz .label text,#mermaid-svg-xctFIvYds9DZORyz span{fill:#333;color:#333;}#mermaid-svg-xctFIvYds9DZORyz .node rect,#mermaid-svg-xctFIvYds9DZORyz .node circle,#mermaid-svg-xctFIvYds9DZORyz .node ellipse,#mermaid-svg-xctFIvYds9DZORyz .node polygon,#mermaid-svg-xctFIvYds9DZORyz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xctFIvYds9DZORyz .rough-node .label text,#mermaid-svg-xctFIvYds9DZORyz .node .label text,#mermaid-svg-xctFIvYds9DZORyz .image-shape .label,#mermaid-svg-xctFIvYds9DZORyz .icon-shape .label{text-anchor:middle;}#mermaid-svg-xctFIvYds9DZORyz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xctFIvYds9DZORyz .rough-node .label,#mermaid-svg-xctFIvYds9DZORyz .node .label,#mermaid-svg-xctFIvYds9DZORyz .image-shape .label,#mermaid-svg-xctFIvYds9DZORyz .icon-shape .label{text-align:center;}#mermaid-svg-xctFIvYds9DZORyz .node.clickable{cursor:pointer;}#mermaid-svg-xctFIvYds9DZORyz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xctFIvYds9DZORyz .arrowheadPath{fill:#333333;}#mermaid-svg-xctFIvYds9DZORyz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xctFIvYds9DZORyz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xctFIvYds9DZORyz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xctFIvYds9DZORyz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xctFIvYds9DZORyz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xctFIvYds9DZORyz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xctFIvYds9DZORyz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xctFIvYds9DZORyz .cluster text{fill:#333;}#mermaid-svg-xctFIvYds9DZORyz .cluster span{color:#333;}#mermaid-svg-xctFIvYds9DZORyz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xctFIvYds9DZORyz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xctFIvYds9DZORyz rect.text{fill:none;stroke-width:0;}#mermaid-svg-xctFIvYds9DZORyz .icon-shape,#mermaid-svg-xctFIvYds9DZORyz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xctFIvYds9DZORyz .icon-shape p,#mermaid-svg-xctFIvYds9DZORyz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xctFIvYds9DZORyz .icon-shape .label rect,#mermaid-svg-xctFIvYds9DZORyz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xctFIvYds9DZORyz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xctFIvYds9DZORyz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xctFIvYds9DZORyz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 改造
剥离后
program.cpp
osal::file_open/read/write
VM.cpp L129
osal::file_open
Scheduler.cpp
cpu_affinity.hpp (wrapper)
cpu_affinity.cpp
→ 转发到 osal::
剥离前
program.cpp
std::fopen/fread/fwrite
VM.cpp L129
trace std::fopen
Scheduler.cpp
cpu_affinity.hpp
cpu_affinity.cpp
sched.h / Windows.h
5.2 向后兼容策略
#mermaid-svg-EENQ5nG2TJCqh7vx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EENQ5nG2TJCqh7vx .error-icon{fill:#552222;}#mermaid-svg-EENQ5nG2TJCqh7vx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EENQ5nG2TJCqh7vx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EENQ5nG2TJCqh7vx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EENQ5nG2TJCqh7vx .marker.cross{stroke:#333333;}#mermaid-svg-EENQ5nG2TJCqh7vx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EENQ5nG2TJCqh7vx p{margin:0;}#mermaid-svg-EENQ5nG2TJCqh7vx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx .cluster-label text{fill:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx .cluster-label span{color:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx .cluster-label span p{background-color:transparent;}#mermaid-svg-EENQ5nG2TJCqh7vx .label text,#mermaid-svg-EENQ5nG2TJCqh7vx span{fill:#333;color:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx .node rect,#mermaid-svg-EENQ5nG2TJCqh7vx .node circle,#mermaid-svg-EENQ5nG2TJCqh7vx .node ellipse,#mermaid-svg-EENQ5nG2TJCqh7vx .node polygon,#mermaid-svg-EENQ5nG2TJCqh7vx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EENQ5nG2TJCqh7vx .rough-node .label text,#mermaid-svg-EENQ5nG2TJCqh7vx .node .label text,#mermaid-svg-EENQ5nG2TJCqh7vx .image-shape .label,#mermaid-svg-EENQ5nG2TJCqh7vx .icon-shape .label{text-anchor:middle;}#mermaid-svg-EENQ5nG2TJCqh7vx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EENQ5nG2TJCqh7vx .rough-node .label,#mermaid-svg-EENQ5nG2TJCqh7vx .node .label,#mermaid-svg-EENQ5nG2TJCqh7vx .image-shape .label,#mermaid-svg-EENQ5nG2TJCqh7vx .icon-shape .label{text-align:center;}#mermaid-svg-EENQ5nG2TJCqh7vx .node.clickable{cursor:pointer;}#mermaid-svg-EENQ5nG2TJCqh7vx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EENQ5nG2TJCqh7vx .arrowheadPath{fill:#333333;}#mermaid-svg-EENQ5nG2TJCqh7vx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EENQ5nG2TJCqh7vx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EENQ5nG2TJCqh7vx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EENQ5nG2TJCqh7vx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EENQ5nG2TJCqh7vx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EENQ5nG2TJCqh7vx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EENQ5nG2TJCqh7vx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EENQ5nG2TJCqh7vx .cluster text{fill:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx .cluster span{color:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EENQ5nG2TJCqh7vx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EENQ5nG2TJCqh7vx rect.text{fill:none;stroke-width:0;}#mermaid-svg-EENQ5nG2TJCqh7vx .icon-shape,#mermaid-svg-EENQ5nG2TJCqh7vx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EENQ5nG2TJCqh7vx .icon-shape p,#mermaid-svg-EENQ5nG2TJCqh7vx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EENQ5nG2TJCqh7vx .icon-shape .label rect,#mermaid-svg-EENQ5nG2TJCqh7vx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EENQ5nG2TJCqh7vx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EENQ5nG2TJCqh7vx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EENQ5nG2TJCqh7vx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 旧 API(保留)
新 API(推荐)
cpu_affinity.cpp
转发到
#include stvm/osal.hpp
osal::set_thread_affinity()
#include stvm/platform/cpu_affinity.hpp
cpu_affinity::bindCurrentThread()
保留 cpu_affinity.hpp + cpu_affinity.cpp 作为向后兼容 wrapper,因为:
stvm_api.cpp的 C APIstvm_set_cpu_affinity()暴露了旧命名空间- 外部宿主代码可能已 include 旧头文件
- 单一实现点(osal 后端)避免跨平台代码重复
6. 实时 Linux 部署指南
6.1 推荐配置
#mermaid-svg-Gh5ShseVznNucnil{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Gh5ShseVznNucnil .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Gh5ShseVznNucnil .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Gh5ShseVznNucnil .error-icon{fill:#552222;}#mermaid-svg-Gh5ShseVznNucnil .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Gh5ShseVznNucnil .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Gh5ShseVznNucnil .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Gh5ShseVznNucnil .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Gh5ShseVznNucnil .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Gh5ShseVznNucnil .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Gh5ShseVznNucnil .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Gh5ShseVznNucnil .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Gh5ShseVznNucnil .marker.cross{stroke:#333333;}#mermaid-svg-Gh5ShseVznNucnil svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Gh5ShseVznNucnil p{margin:0;}#mermaid-svg-Gh5ShseVznNucnil .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Gh5ShseVznNucnil .cluster-label text{fill:#333;}#mermaid-svg-Gh5ShseVznNucnil .cluster-label span{color:#333;}#mermaid-svg-Gh5ShseVznNucnil .cluster-label span p{background-color:transparent;}#mermaid-svg-Gh5ShseVznNucnil .label text,#mermaid-svg-Gh5ShseVznNucnil span{fill:#333;color:#333;}#mermaid-svg-Gh5ShseVznNucnil .node rect,#mermaid-svg-Gh5ShseVznNucnil .node circle,#mermaid-svg-Gh5ShseVznNucnil .node ellipse,#mermaid-svg-Gh5ShseVznNucnil .node polygon,#mermaid-svg-Gh5ShseVznNucnil .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Gh5ShseVznNucnil .rough-node .label text,#mermaid-svg-Gh5ShseVznNucnil .node .label text,#mermaid-svg-Gh5ShseVznNucnil .image-shape .label,#mermaid-svg-Gh5ShseVznNucnil .icon-shape .label{text-anchor:middle;}#mermaid-svg-Gh5ShseVznNucnil .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Gh5ShseVznNucnil .rough-node .label,#mermaid-svg-Gh5ShseVznNucnil .node .label,#mermaid-svg-Gh5ShseVznNucnil .image-shape .label,#mermaid-svg-Gh5ShseVznNucnil .icon-shape .label{text-align:center;}#mermaid-svg-Gh5ShseVznNucnil .node.clickable{cursor:pointer;}#mermaid-svg-Gh5ShseVznNucnil .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Gh5ShseVznNucnil .arrowheadPath{fill:#333333;}#mermaid-svg-Gh5ShseVznNucnil .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Gh5ShseVznNucnil .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Gh5ShseVznNucnil .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gh5ShseVznNucnil .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Gh5ShseVznNucnil .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gh5ShseVznNucnil .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Gh5ShseVznNucnil .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Gh5ShseVznNucnil .cluster text{fill:#333;}#mermaid-svg-Gh5ShseVznNucnil .cluster span{color:#333;}#mermaid-svg-Gh5ShseVznNucnil div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Gh5ShseVznNucnil .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Gh5ShseVznNucnil rect.text{fill:none;stroke-width:0;}#mermaid-svg-Gh5ShseVznNucnil .icon-shape,#mermaid-svg-Gh5ShseVznNucnil .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Gh5ShseVznNucnil .icon-shape p,#mermaid-svg-Gh5ShseVznNucnil .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Gh5ShseVznNucnil .icon-shape .label rect,#mermaid-svg-Gh5ShseVznNucnil .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Gh5ShseVznNucnil .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Gh5ShseVznNucnil .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Gh5ShseVznNucnil :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SCHED_FIFO 调度
PLC 任务 优先级 50-60
设备驱动 优先级 80+
系统守护 优先级 20-30
CPU 亲和性绑定
PLC 任务 → CPU 1
网卡驱动 → CPU 2
用户进程 → CPU 0
isolcpus=1 启动参数
(隔离 CPU 免受其他调度干扰)
PREEMPT_RT 内核
CONFIG_PREEMPT_RT_FULL=y
CONFIG_CPU_FREQ=n
(禁用频率调整)
CONFIG_HZ=1000
/sys/kernel/realtime = 1
6.2 宿主侧完整代码
cpp
#include <csignal>
#include <stvm/osal.hpp>
#include <stvm/stvm.hpp>
int main() {
// 1. 禁用本进程被 OOM killer 选中(嵌入式关键系统)
// echo -1000 > /proc/self/oom_score_adj
// 2. 禁止被 cgroup 限制(容器环境)
// 3. 构造 bytecode(磁盘文件或内存)
stvm::BytecodeProgram prog;
std::string err;
prog.readFromFile("plc.bytecode", err);
// 4. 配置 Scheduler
stvm::Scheduler sched;
sched.addTask("PLC_Main", prog, 1000 /* 1ms 周期 */, 50000);
// 5. 绑定到 CPU 1(isolcpus=1 已隔离)
stvm::osal::set_thread_affinity(1);
// 6. 提升调度优先级到 SCHED_FIFO 50
stvm::osal::set_thread_priority(
stvm::osal::SchedPolicy::Fifo, 50);
// 7. 主循环(PREEMPT_RT 下 1ms 周期抖动 < 10μs)
while (sched.runOnce()) { /* 纯计算,无阻塞 */ }
return 0;
}
6.3 预期性能
| 场景 | 内核 | 1ms 周期抖动 | 最大延迟 |
|---|---|---|---|
| 普通 Ubuntu | 5.15-generic | ±100-300μs | 不确定 |
| PREEMPT_RT | 5.10-rt-amd64 | ±5-15μs | < 50μs |
| Xenomai | ipipe 双内核 | ±1-5μs | < 20μs |
7. 后端横向对比
| 后端 | 时基 | 文件 IO | CPU 亲和性 | 调度优先级 | 编译条件 |
|---|---|---|---|---|---|
| Linux 普通 | CLOCK_MONOTONIC |
✅ fopen/fread | ✅ pthread_setaffinity_np | ⚠️ 可设但非实时 | __linux__ |
| Linux PREEMPT_RT | CLOCK_MONOTONIC_RAW |
✅ | ✅ | ✅ SCHED_FIFO 真实生效 | 运行时检测 |
| Linux Xenomai | CLOCK_MONOTONIC(RTDM) |
✅ | ✅ | ✅ SCHED_FIFO | __XENO_SKIN__ |
| Windows | QPC ~200ns | ✅ fopen | ✅ SetThreadAffinityMask | ❌ false | _WIN32 |
| FreeRTOS | tick * 1000 |
可选 FatFs | ❌ false | ❌ false | __has_include(<FreeRTOS.h>) |
| RT-Thread | tick * 1000 |
✅ dfs POSIX | v5.x 可选 | ✅ rt_thread_set_priority | __has_include(<rt-thread.h>) |
| SylixOS | clock_gettime |
✅ POSIX | ✅ pthread_setaffinity_np | ✅ pthread_setschedparam | CMake SYLIXOS 分支 |
| VxWorks 6 | tickGet |
✅ fopen | ❌ false | ✅ taskPrioritySet(翻转) | __has_include(<vxWorks.h>) |
| VxWorks 7 | tickGet |
✅ | ✅ taskCpuSetAffinity | ✅ taskPrioritySet(翻转) | VX_VERSION >= 0x70000000 |
| 默认空 | 返回 0 | INVALID_FILE | false | false | 无后端条件满足 |
8. 新增后端移植指南
宿主新增一个 OS 后端的 5 步流程:
#mermaid-svg-uJ4Papb7Dy180xiJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uJ4Papb7Dy180xiJ .error-icon{fill:#552222;}#mermaid-svg-uJ4Papb7Dy180xiJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uJ4Papb7Dy180xiJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uJ4Papb7Dy180xiJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uJ4Papb7Dy180xiJ .marker.cross{stroke:#333333;}#mermaid-svg-uJ4Papb7Dy180xiJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uJ4Papb7Dy180xiJ p{margin:0;}#mermaid-svg-uJ4Papb7Dy180xiJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ .cluster-label text{fill:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ .cluster-label span{color:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ .cluster-label span p{background-color:transparent;}#mermaid-svg-uJ4Papb7Dy180xiJ .label text,#mermaid-svg-uJ4Papb7Dy180xiJ span{fill:#333;color:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ .node rect,#mermaid-svg-uJ4Papb7Dy180xiJ .node circle,#mermaid-svg-uJ4Papb7Dy180xiJ .node ellipse,#mermaid-svg-uJ4Papb7Dy180xiJ .node polygon,#mermaid-svg-uJ4Papb7Dy180xiJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uJ4Papb7Dy180xiJ .rough-node .label text,#mermaid-svg-uJ4Papb7Dy180xiJ .node .label text,#mermaid-svg-uJ4Papb7Dy180xiJ .image-shape .label,#mermaid-svg-uJ4Papb7Dy180xiJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-uJ4Papb7Dy180xiJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uJ4Papb7Dy180xiJ .rough-node .label,#mermaid-svg-uJ4Papb7Dy180xiJ .node .label,#mermaid-svg-uJ4Papb7Dy180xiJ .image-shape .label,#mermaid-svg-uJ4Papb7Dy180xiJ .icon-shape .label{text-align:center;}#mermaid-svg-uJ4Papb7Dy180xiJ .node.clickable{cursor:pointer;}#mermaid-svg-uJ4Papb7Dy180xiJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uJ4Papb7Dy180xiJ .arrowheadPath{fill:#333333;}#mermaid-svg-uJ4Papb7Dy180xiJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uJ4Papb7Dy180xiJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uJ4Papb7Dy180xiJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uJ4Papb7Dy180xiJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uJ4Papb7Dy180xiJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uJ4Papb7Dy180xiJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uJ4Papb7Dy180xiJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uJ4Papb7Dy180xiJ .cluster text{fill:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ .cluster span{color:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uJ4Papb7Dy180xiJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uJ4Papb7Dy180xiJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-uJ4Papb7Dy180xiJ .icon-shape,#mermaid-svg-uJ4Papb7Dy180xiJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uJ4Papb7Dy180xiJ .icon-shape p,#mermaid-svg-uJ4Papb7Dy180xiJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uJ4Papb7Dy180xiJ .icon-shape .label rect,#mermaid-svg-uJ4Papb7Dy180xiJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uJ4Papb7Dy180xiJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uJ4Papb7Dy180xiJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uJ4Papb7Dy180xiJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 创建 osal_xxx.cpp
2. #ifdef 保护
没有对应 OS 头文件时
fallback 到空实现
3. 实现 4 类 13 个函数
时基/文件/亲和性/调度
4. CMakeLists.txt 加
elseif _OSAL_BACKEND STREQUAL XXX
- list APPEND osal_xxx.cpp
- 宿主交叉编译
-DSTVM_OSAL_BACKEND=XXX
附录:验证结果
| 项目 | 结果 |
|---|---|
| 7 后端编译(Linux host) | 全部 ✅ |
| test_vm(Linux 后端) | 74/74 |
| test_bytecode(Linux 后端) | 33/33 |
| bench_perf(Linux 后端) | 0 failures |
| BARE 后端 | test_vm ✅ / test_bytecode ⚠️ 预期失败(无文件系统) |
| ASAN 检查 | 0 UB(Phase 1 已验证) |