跳到主要内容

系统服务 · 共享内存

1. 模块概述

  • 主要功能:基于 Linux DMA-HEAP 的共享内存分配库,提供跨进程零拷贝传输能力,支持 DMA-BUF 文件描述符传递和 cache 同步操作,与 libdma 配合实现高效数据传输
  • 规格或特性:
    • 支持 DMA-HEAP 分配,可指定物理连续、非缓存等属性
    • 支持 cache 同步操作(TO_DEVICE / FROM_DEVICE)
    • shm_transport:基于 Unix Domain Socket 的 fd 传输框架,支持发布/订阅模式
    • 支持多种内存域:POSIX 共享内存、DMA-BUF、物理内存
  • 相关目录结构:
components/system/shm/
├── include/
│ ├── shm.h # 共享内存分配 API
│ └── shm_transport.h # 跨进程传输 API
├── src/ # 库实现源码
├── test/
│ ├── shm_transport_pub_test.c # 发布端测试
│ └── shm_transport_sub_test.c # 订阅端测试
├── CMakeLists.txt # 构建配置
└── README.md # 模块说明

2. 环境准备

前置条件

  • 运行环境:Linux 内核(支持 DMA-HEAP)、CMake ≥ 3.16、gcc/clang 编译器
  • 依赖与外部资源:
    • 内核需支持 DMA-HEAP(/dev/dma_heap/* 设备节点存在)
    • 无额外外部依赖,仅依赖标准 C 库和 pthread
  • 环境变量与初始化:若通过 SDK 编译,需先执行 source build/envsetup.shlunch <target>
  • 硬件与连接:目标板需支持 DMA-HEAP,确认 /dev/dma_heap/ 目录存在
  • 工具与权限:访问 /dev/dma_heap/* 设备节点需相应权限(通常需 root 或加入对应用户组)

构建编译

  • 获取代码:代码位于 SDK 的 components/system/shm 目录
  • 本模块编译:

独立编译方式:

cd components/system/shm
mkdir build && cd build
cmake ..
cmake --build .

通过 SDK mm 编译:

source build/envsetup.sh
lunch <target>
cd components/system/shm
mm clean && mm -v
  • 产物:
    • 用户态库:libshm.solibshm.a
    • 测试程序:build/output/shm_transport_pub_testbuild/output/shm_transport_sub_test

3. 示例使用(从 0 跑通)

本节为读者按步骤复现的主线:命令可复制、路径写绝对或写明工作目录、每步给出预期现象(终端输出片段、退出码、界面或日志关键字)。

3.1 跨进程共享内存传输

前置:已编译 libshm,目标板已上电并可通过串口或 SSH 访问

步骤 1:确认 DMA-HEAP 设备节点存在

ls -l /dev/dma_heap/

预期现象:显示可用的 heap 设备,如 systemcma

步骤 2:启动发布端(终端 1)

cd components/system/shm/build/output
./shm_transport_pub_test

预期现象:程序启动并等待订阅者连接,输出类似:

[INFO] Publisher opened: /tmp/shm_trans_test.sock
[INFO] Waiting for subscribers...

步骤 3:启动订阅端(终端 2)

cd components/system/shm/build/output
./shm_transport_sub_test test

预期现象:订阅端连接成功,开始接收数据帧,输出类似:

[INFO] Subscriber connected to: test
[INFO] Received frame: seq=0, size=4096, timestamp=...
[INFO] Data verification passed

发布端同时显示:

[INFO] Subscriber connected
[INFO] Publishing frame: seq=0, size=4096

3.2 共享内存分配与 cache 同步

前置:见 §2

步骤 1:编写测试代码分配共享内存(参考 test/ 目录示例)

步骤 2:分配物理连续的 DMA buffer

struct shm_domain *domain = shm_create_domain_dmabuf("system");
struct shm_buffer buf;
shm_alloc(domain, 1024*1024, SHM_FLAG_CONTIGUOUS, &buf);

预期现象:分配成功,buf.vaddr 指向可用内存,buf.fd 为有效文件描述符

步骤 3:执行 cache 同步操作

// CPU 写入数据后,同步到设备
shm_sync_cache(domain, &buf, SHM_SYNC_TO_DEVICE);

预期现象:cache 刷新完成,数据对 DMA 设备可见

4. 应用开发

  • 对外 API 或接口形态

    • 头文件:include/shm.h(共享内存分配)、include/shm_transport.h(跨进程传输)
    • 库名:libshm.solibshm.a
    • 主要 API(shm.h):
      • shm_create_domain_dmabuf() - 创建 DMA-BUF 内存域
      • shm_alloc() - 分配共享内存
      • shm_import_fd() - 导入已有的 fd
      • shm_sync_cache() - cache 同步操作
      • shm_free_buffer() - 释放 buffer
      • shm_destroy_domain() - 销毁内存域
    • 主要 API(shm_transport.h):
      • shm_trans_pub_open() - 打开发布端
      • shm_trans_pub_add_buffer() - 添加 buffer 到传输池
      • shm_trans_pub_acquire() - 获取可写 buffer
      • shm_trans_pub_publish() - 发布数据帧
      • shm_trans_sub_open() - 打开订阅端
      • shm_trans_sub_recv() - 接收数据帧
      • shm_trans_sub_release() - 释放数据帧
  • 调用方式与注意点

    • 线程安全:单个 domain/pub/sub 对象不支持多线程并发,需上层加锁
    • 权限:需确保 /dev/dma_heap/* 设备节点可访问
    • 资源释放:必须按顺序释放:先 shm_free_buffer(),再 shm_destroy_domain()
    • fd 生命周期:shm_buffer.fd 在 buffer 释放前保持有效,可用于跨进程传递
    • cache 同步:使用 DMA 传输前后需调用 shm_sync_cache() 确保数据一致性
    • transport 模式:发布端需先 add_buffer()acquire(),订阅端 recv() 后必须 release()
  • 参考 demo 或示例路径components/system/shm/test/shm_transport_pub_test.cshm_transport_sub_test.c

5. 调试指南

  • 内核日志查看:dmesg | grep dma_heap 可查看 DMA-HEAP 相关日志
  • 用户态日志:可在代码中添加 printf 或使用 strace 跟踪系统调用
  • 常见调试步骤:
    1. 确认 DMA-HEAP 设备存在:ls -l /dev/dma_heap/
    2. 检查权限:sudo chmod 666 /dev/dma_heap/*(测试用)
    3. 检查 socket 文件:ls -l /tmp/shm_trans_*.sock
    4. 使用 lsof 查看 fd 泄漏:lsof -p <pid> | grep dma_heap
    5. 使用 strace 跟踪:strace -e ioctl,mmap ./test_program
  • 与硬件/内核同事分工时的信息收集清单:
    • 内核版本和 DMA-HEAP 配置(cat /proc/config.gz | gunzip | grep DMA_HEAP
    • 可用 heap 列表(ls /dev/dma_heap/
    • 分配失败时的 dmesg 日志
    • 内存使用情况(cat /proc/meminfo

6. 常见问题

现象可能原因处理
/dev/dma_heap/ 不存在内核未启用 DMA-HEAP检查内核配置,重新编译内核
shm_alloc() 返回失败内存不足或 heap 不支持请求的属性减小分配大小,或使用其他 heap
shm_import_fd() 失败fd 无效或已关闭确认 fd 来源正确且未被关闭
跨进程传输数据错误cache 未同步在 DMA 传输前后调用 shm_sync_cache()
shm_trans_sub_recv() 超时发布端未发送数据或 socket 断开检查发布端状态,确认 socket 连接正常
socket 连接失败socket 文件不存在或权限不足确认发布端已启动,检查 /tmp/ 权限

附录:性能与测试数据

指标数值测试条件
跨进程传输延迟~100 μs4KB 数据帧,本地 Unix socket
零拷贝吞吐量~2.5 GB/s1MB 数据帧,连续传输
fd 传递开销~20 μs单次 fd 传递延迟

测试方法:使用 shm_transport_pub_testshm_transport_sub_test 在目标板上测试,硬件平台为 SPACEMIT K1 芯片,Linux 内核 5.10,单发布端单订阅端,统计 1000 次平均值。测试命令:

# 终端 1
./shm_transport_pub_test --benchmark --frames 1000

# 终端 2
./shm_transport_sub_test test --benchmark