6.4非POSIXskin进程间通信

6.4 非POSIX skin进程间通信

Xenomai 实现的实时API,不仅包括 POSIX skin,还包括Alchemy‌ skinVxWorks skinpSOS skin

这些非POSIX skin,支持进程间通信的前提,是在编译 Xenomai 用户层的时候,必须打开 --enable-pshared 选项!

6.4.1 原理

--enable-pshared 启用后,会定义 CONFIG_XENO_PSHARED 宏。此选项允许不同进程间共享资源,像共享内存、信号量等。启用 --enable-pshared 后,脚本会检查系统是否支持 shm_open 函数,若不支持则报错。

回顾用户层 RTOS API章节,针对非 POSIX skin,使用 xeno-config 获取链接标识时,会增加 -lcopperplatelibcopperplate库实现了一个接口转换层copperplate interface,其初始化接口为 copperplate_init

复制代码
copperplate_init
  -> get_session_root: 
  -> heapobj_pkg_init_private: initialize main private heap
    -> mem = malloc(size);
    -> ret = heapmem_init(&heapmem_main, mem, size);
  -> heapobj_pkg_init_shared: initialize main shared heap
    -> create_main_heap: Bind to (and optionally create) the main session's heap
      -> fd = shm_open(hobj->fsname, O_RDWR|O_CREAT, 0660); 
      -> m_heap = __STD(mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0));

copperplate interface 会为实时应用在用户态创建私有堆内存 heapmem_main,和共享堆内存:

  • 共同点:二者都没有从 Cobalt 内核系统堆 sys heap 中分配内存,而是在用户态独立申请一块内存,使用各自的用户态内存分配器管理。
  • 不同点:私有堆通过 malloc 分配,共享堆通过 shm_open 打开共享内存,并通过 mmap 映射到应用程序。

首先介绍一下有堆内存 heapmem_main

针对私有堆内存 heapmem_main,在用户层由三个分配器,默认使用 heapmem 分配器:

  • heapobj-malloc.c:本质上是 Linux 的 malloc。
  • heapobj-heapmem.c:heapmem 分配器(默认)。
  • heapobj-tlsf.c:tlsf 分配器。

下面详细介绍一下共享堆内存的创建原理:

  • 创建共享堆内存的函数 heapobj_pkg_init_shared,由 --enable-pshared 选项控制。
    • 如果没有打开 --enable-pshared 选项,heapobj_pkg_init_shared 仅仅是一个空函数。

      复制代码
      static inline int heapobj_pkg_init_shared(void)
      {
        return 0;
      }
    • 如果打开了 --enable-pshared 选项,则 heapobj_pkg_init_shared 定义在 lib/copperplate/heapobj-pshared.c

  • 共享堆内存本质上基于POSIX共享内存实现的
    • 通过 shm_open 打开共享内存,通过 mmap 映射到应用程序。
    • 只要确保 shm_open 的共享内存名称相同,那么不同的进程将会使用同一块内存。O_CREAT 确保了要么新建,要么使用已经创建的同名共享内存。
  • 每个进程的共享堆内存的名称,被称为 session,提前在 get_session_root 初始化。
    • 应用启动时,传入 --session=<label>[/<group>] ,可以指定 session 名称。
    • 如果没有指定,默认情况下,session 的值为 anon@线程ID,例如 anon@12656

综上,不同进程在启动时,通过 --session=<label>[/<group>] 传入相同的 session 名称,则各个进程会使用同一块内存作为共享堆内存。在进程运行过程中,申请共享对象时,会从共享堆内存中申请内存空间。

Alchemy‌ skin 中的 rt_queue_create 为例:

复制代码
rt_queue_create
  -> heapobj_init
    -> 如果没有打开 `--enable-pshared` 选项
      -> __heapobj_init_private: 从私有堆内存申请
    -> 如果打开了 `--enable-pshared` 选项
      -> sheapmem_alloc: 从共享堆内存申请

最后,需要指出,只有链接了 libcopperplate 库的应用程序,才支持如下参数:

  • --mem-pool-size=<size[K|M|G]>

  • --shared-registry

  • --registry-root=

  • --session=[/]

    static void copperplate_help(void)
    {
    fprintf(stderr, "--mem-pool-size=<size[K|M|G]> size of the main heap\n");
    fprintf(stderr, "--no-registry suppress object registration\n");
    fprintf(stderr, "--shared-registry enable public access to registry\n");
    fprintf(stderr, "--registry-root=<path> root path of registry\n");
    fprintf(stderr, "--session=<label>[/<group>] enable shared session\n");
    }

    static struct setup_descriptor copperplate_interface = {
    .name = "copperplate",
    .init = copperplate_init,
    .options = copperplate_options,
    .parse_option = copperplate_parse_option,
    .help = copperplate_help,
    };

    copperplate_setup_call(copperplate_interface);

根据 copperplate_help 函数可知,只有链接了 libcopperplate 库的应用程序才能解析上述参数。换个角度来说,使用 POSIX skin 实现的应用程序并不支持这些参数,例如 Xenomai 自带的 latency 工具。

6.4.2 查看实时对象的信息

在编译 Xenomai 用户层的时候,打开 --enable-registry[=/registry-root-path] 选项,可以通过 FUSE 导出进程的注册表状态,可以通过读取这些文件来获取有关现有实时对象的信息,例如任务、信号量、消息队列等。导出的默认路径为/var/run/xenomai

打开 --enable-registry[=/registry-root-path] 选项,构建 Xenomai 库时需要工具链中提供 FUSE 开发库,并且目标内核中必须启用 CONFIG_FUSE_FS

针对应用程序来说,在链接时还必须增加 -lcopperplate 链接 libcopperplate 库。当然,对于非 POSIX skin,使用 xeno-config 获取链接标识时,总会自动增加 -lcopperplate

导出的原理如下:

复制代码
copperplate_init
    ->get_session_root
    ->registry_pkg_init
        ->connect_regd
            ->socket
            ->spawn_daemon
              -> sbin/sysregd
        ->__registry_pkg_init
            ->registry_add_dir("/");	/* Create the fs root. */
  • registry_pkg_init 函数
    • 打开 --enable-registry[=/registry-root-path] 选项,会生成 CONFIG_XENO_REGISTRY 宏定义,registry_pkg_init 函数定义在 lib/copperplate/registry.c
    • 如果没有打开,则 registry_pkg_init 函数仅为一个空函数。
  • sysregd 守护进程
    • sysregd 守护进程负责在用户层挂载并构建 /var/run/xenomai/ 目录。
    • registry_pkg_init 如果通过 socket 无法连接到 sysregd 守护进程,则会自己发起此守护进程。
    • 可以自己手动发起 sysregd 守护进程
      • sysregd --root=/var/run/xenomai --shared --anon --daemonize --linger

以 Xenomai 源码自带的 altency 为例,它是 latencyAlchemy‌ skin 重新实现版本,默认会链接 libcopperplate 库。 Xenomai 源码编译完成后,altency 位于 xenomai-v3.2.4-build/demo/alchemy 目录,默认安装到 /usr/xenomai/demo 目录。

复制代码
# ./altency
== Sampling period: 1000 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|     70.585|    480.700|   1342.298|       4|     0|     70.585|   1342.298
RTD|     71.925|    544.017|   1402.927|       8|     0|     70.585|   1402.927
RTD|     80.641|    457.550|   1388.125|      10|     0|     70.585|   1402.927

altency 启动后,可以看到进程 PID 为 18839,同时启动了 sysregd 守护进程。

复制代码
# cat /proc/xenomai/sched/threads
CPU  PID    CLASS  TYPE      PRI   TIMEOUT       STAT       NAME
  0  0      idle   core       -1   -             R          [ROOT/0]
  1  0      idle   core       -1   -             R          [ROOT/1]
  2  0      idle   core       -1   -             R          [ROOT/2]
  3  0      idle   core       -1   -             R          [ROOT/3]
  0  18839  rt     cobalt      0   -             X          altency
  0  18855  rt     cobalt      0   -             X          sysregd
  0  18857  rt     cobalt      0   -             X          sysregd
  0  18858  rt     cobalt      0   -             X          altency
  0  18859  rt     cobalt      0   -             W          alt-display-18839
  0  18860  rt     cobalt     99   -             Wt         alt-sampling-18839

查看 /var/run/xenomai 目录,可以看到 session 的默认名称为 anon\@18839

复制代码
# tree /var/run/xenomai/root/anon\@18839/
/var/run/xenomai/root/anon@18839/
|-- 18839
|   `-- alchemy
|       |-- semaphores
|       |   `-- dispsem-18839
|       `-- tasks
|           |-- alt-display-18839
|           `-- alt-sampling-18839
`-- system
    |-- heaps
    |-- threads
    `-- version

5 directories, 6 files

如果使用命令 ./altency --session=test 指定 session 的名字,那么session 的名称会变为指定的 test

复制代码
# tree /var/run/xenomai/root/test/
/var/run/xenomai/root/test/
|-- 18912
|   `-- alchemy
|       |-- semaphores
|       |   `-- dispsem-18912
|       `-- tasks
|           |-- alt-display-18912
|           `-- alt-sampling-18912
`-- system
    |-- heaps
    |-- threads
    `-- version
相关推荐
aspirestro三水哥1 小时前
9.2向社区寻求帮助
rtos·xenomai
aspirestro三水哥2 天前
8.5CPU隔离与亲和性
rtos·xenomai
帅得不敢出门3 天前
MacOS安装VSCode在QEMU上模拟跑FreeRtos
ide·vscode·macos·freertos·rtos
liu_endong3 天前
RTOS基于7840——任务创建、启动、切换、删除
mcu·rtos·杰发科技·autochips·车规芯片
香水5只用六神6 天前
【RTOS快速入门】05_动态_静态创建任务(2)
c语言·stm32·单片机·嵌入式硬件·freertos·rtos·嵌入式软件
香水5只用六神6 天前
【RTOS快速入门】06_任务状态理论讲解(1)
c语言·stm32·单片机·嵌入式硬件·freertos·rtos·嵌入式软件
香水5只用六神7 天前
【RTOS快速入门】07_同步互斥与通信概述
单片机·嵌入式硬件·学习·操作系统·freertos·rtos·嵌入式软件
香水5只用六神7 天前
【RTOS快速入门】05_动态_静态创建任务(1)
c语言·开发语言·单片机·嵌入式硬件·freertos·rtos·嵌入式软件
混分巨兽龙某某2 个月前
基于STM32的嵌入式操作系统RT-Thread移植教学(HAL库版本)
stm32·嵌入式硬件·rt-thread·rtos
aspirestro三水哥2 个月前
7.2实时进程如何打印输出
rtos·xenomai