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
相关推荐
切糕师学AI20 小时前
NuttX RTOS是什么?
嵌入式·rtos
aspirestro三水哥3 天前
6.2POSIX线程间通信
rtos·xenomai
鸿蒙小白龙4 天前
OpenHarmony轻量系统(Hi3861)RTOS API开发详解
openharmony·rtos·liteos·轻量系统
无聊到发博客的菜鸟13 天前
STM32 手册寄存器属性
stm32·单片机·嵌入式·rtos·寄存器
aspirestro三水哥13 天前
5.3RTDM用户层驱动
rtos·xenomai
无聊到发博客的菜鸟13 天前
STM32 RTC时钟不准的问题
stm32·嵌入式·rtc·rtos
aspirestro三水哥16 天前
4.7POSIX进程与线程实例
rtos·xenomai
无聊到发博客的菜鸟16 天前
使用STM32对SD卡进行性能测试
stm32·单片机·rtos·sd卡·fatfs
切糕师学AI18 天前
Azure RTOS ThreadX 简介
microsoft·嵌入式·azure·rtos