#实时 #中间件 #无锁 #嵌入式 #消息队列 #有限状态机

bin+lib rust-rsm

RSM: 实时软件中间件框架。异步、事件驱动框架

8 个版本

0.3.2 2022年12月16日
0.3.1 2022年11月12日
0.3.0 2022年8月28日
0.2.4 2022年7月28日

#593 in 异步

每月 22 下载

Apache-2.0

390KB
10K SLoC

RSM: Rust 实时系统中间件

简介

实时系统定义为能够在特定确定时间内响应用户请求的系统。为了在通用计算机系统中实现这一目标,我们必须在软件系统上采用实时调度策略,并避免一些耗时操作,如同步 I/O 操作、内存垃圾回收和锁。

RSM 是用 Rust 编写的轻量级实时中间件实现,支持事件驱动、消息导向的无锁编程原则。在 RSM 中,每个软件模块都是一个 组件,通常是一个有限状态机,主要处理事件循环。每个组件可以实例化为多个任务,每个任务映射到一个专用的 OS 线程,并拥有自己的消息队列。

开发者可以分别设置任务的调度优先级和它们的消息队列长度,通常基于服务模型和性能 & 延迟要求。

RSM 适用于以下应用

  • 网络设备控制平面,例如路由协议、服务控制
  • 嵌入式系统应用
  • 遥控系统
  • 实时遥测和仪表

编程

概念

每个 RSM 组件都必须实现 rsm::Runnable trait 并提供一个任务创建回调函数。

main.rs 中的代码是一个 RSM 应用程序实现的示例。

pub trait Runnable {

fn on_init(&mut self,cid:&rsm_component_t);

fn on_timer(&mut self,cid:&rsm_component_t,timer_id:rsm_timer_id_t,timer_data:usize);

fn on_socket_event(&mut self,cid:&rsm_component_t,event:rsm_socket_event_t);

fn on_message(&mut self,cid:&rsm_component_t,msg_id:rsm_message_id_t,msg:&rsm_message_t);

fn on_close(&mut self,cid:&rsm_component_t);

}

type rsm_new_task = fn(cid: &rsm_component_t) -> &'static mut dyn Runnable

初始化 RSM

使用 rsm_init 函数初始化 rsm 系统,然后应用程序可以将它们的组件注册到 RSM。

rsm_init_cfg_t 是 RSM 的配置文件,它以 json 格式存在。rsm_init(conf: &config::rsm_init_cfg_t) -> errcode::RESULT

pub fn registry_component(cid: u32, attrs: &component_attrs_t, callback: rsm_new_task) -> errcode::RESULT

组件注册完成后,应调用 start_rsm() 函数来启动系统。

运行时

每个运行任务都可以通过 rsm_component_t 唯一标识

任务可以相互发送消息,包括普通消息或高优先级消息 pub fn send_asyn_msg(dst:&rsm_component_t,msg:rsm_message_t)->errcode::RESUL

pub fn send_asyn_priority_msg(dst:&rsm_component_t,msg:rsm_message_t)->errcode::RESULT

对于接收方,应用程序必须使用 msg.decode::(v) 来将消息恢复为应用程序定义的类型

RSM 还提供定时器服务,应用程序可以通过调用 set_timer 函数来设置定时器,一旦定时器设置并到期,rsm 任务将收到一个 on_timer 事件,该事件在 Runnable 特性中定义。

pub fn set_timer(dur_msec:u64,loop_count:u64,timer_data:usize)->Option<rsm_timer_id_t> pub fn kill_timer_by_id(timer_id:rsm_timer_id_t)->errcode::RESULT

调度优先级

RSM 支持几个预定义的任务优先级,它们映射到底层操作系统线程调度策略或优先级。

对于 Linux OS,实时优先级映射到 schedule_policy=SCHED_RR,非实时优先级映射到 policy=SCHED_OTHER。

对于 Windows,RSM 使用 THREAD_PRIORITY_TIME_CRITICAL 常量表示实时优先级。

pub enum E_RSM_TASK_PRIORITY { THREAD_PRI_LOW = 0, THREAD_PRI_NORMAL = 1, THREAD_PRI_HIGH = 2,
THREAD_PRI_REALTIME = 3, THREAD_PRI_REALTIME_HIGH = 4, THREAD_PRI_REALTIME_HIGHEST = 5, }

异步套接字 API

从 0.3.0 版本开始,RSM 组件 Runnable 特性中添加了套接字事件方法

fn on_socket_event(&mut self,cid:&rsm_component_t,event:rsm_socket_event_t);

并且 RSM 提供了几个 API 对象来实现异步套接字编程。应用程序可以初始化一个套接字,然后处理 RSM 发送的套接字事件(新的 TCP 套接字或可读套接字)

TCPListener

应用程序可以启动 TCPListener,设置负载均衡策略。

如果 tcplistener 的发起者组件有 4 个任务,RSM 将通过哈希算法将客户端连接分配给 4 个任务,并确保每个客户端连接仅由一个任务处理。

这是默认行为,应用程序可以通过设置不同的 LB_POLICY 来更改此行为

pub enum SOCKET_LB_POLICY { ///通过哈希结果将 TCP 客户端连接分配到所有组件实例 SOCK_LB_ALL_INSTANCE=0, ///TCP 连接仅由调用实例处理 SOCK_LB_CALLER_INSTANCE=1, ///将 TCP 连接分配到除了调用者之外的所有组件实例 SOCK_LB_EXCLUDE_CALLER_INSTANCE=2, }

TCPSocket

一个 Tcp 客户端套接字 API 对象,不持有任何套接字运行时状态

对于 RSM 消息接口,默认使用 socket_id,应用程序可以将此 ID 转换为 Socket API 对象,例如。

let mut sock=socket::TcpSocket::get_socket_by_id(event.socket_id);

UDPSocket

一个 UDP 套接字,无连接的套接字 API 包装器,其余部分与 TCPSocket 相似。

您可以使用以下方法从 socket_id 获取套接字实例。

let mut sock=socket::UdpSocket::get_socket_by_id(event.socket_id);

诊断

开发人员和用户可以使用 REST API 获取 RSM 的运行状态和统计信息。

内置 API

help,curl http://127.0.0.1:12000/rsm/help 获取任务运行状态, curl http://127.0.0.1:12000/rsm/task?1:2 获取组件配置,curl http://127.0.0.1:12000/rsm/component?1

应用程序定义的 OAM API

应用程序模块必须实现 OamReqCallBack 函数,并调用 RegisterOamModule 来注册自己 OamReqCallBack=fn(op:E_RSM_OAM_OP,url:&String,param:&String)->oam_cmd_resp_t

///注册模块回调,urls 是 REST API URL 的列表,不包括前缀 /rsm 和随后的 "?" 后的 id RegisterOamModule(urls:&[String], callback:OamReqCallBack)

其他服务 & 库函数

xlog 服务

xlog 服务基于客户端/服务器架构,客户端简单地将日志消息发送到服务器,服务器负责日志文件操作,在应用程序的上下文中避免写入磁盘,这对于实时应用非常重要。

let log = rsm::new_xlog(module_name:&str)->xlog::xlogger_t;

log.Errorf(postion, err, logDesc);

其他线程安全算法和数据结构

  • spin_lock_t,基于自旋锁的原子操作锁。
  • AtomicQueue,基于spin_lock
  • TsIdAllocator,线程安全ID分配器
  • 位图
  • 以太网数据包解析器
  • IP路由表
  • 其他几个网络功能和方法包装器

如果您有任何问题,请发送电子邮件至:[email protected]

依赖关系

~4-18MB
~232K SLoC