linux的fd传递实现

fd从一个进程传到另一个进程涉及到socket通信,具体来说是通过UNIX domain socket的辅助数据(ancillary data)机制实现的。这是一种在进程间传递文件描述符的标准方法。

1. fd传递的核心原理

在Linux中,文件描述符只在单个进程内有效。不同进程的文件描述符表是独立的,因此不能直接将一个进程的fd值传给另一个进程使用。但内核提供了一种特殊机制,允许通过UNIX domain socket传递文件描述符的"所有权"。这里我们用dma-buf共享机制为案例来分析。

进程A (exporter) 进程B (importer) │ │ ├─ 创建 dma-buf │ │ dmabuf = dma_buf_export(...) │ │ fd_A = dma_buf_fd(dmabuf, ...) │ │ │ ├─ 通过 UNIX socket 发送 fd_A │ │ sendmsg(sock, msg, SCM_RIGHTS) │ │ │ │ │ └───────────────────────────>├─ 接收 fd │ │ recvmsg(sock, msg, ...) │ │ fd_B = extract_fd_from_msg(msg) │ │ │ ├─ 使用 fd_B 获取 dma-buf │ │ dmabuf = dma_buf_get(fd_B) │ │ │ ├─ 进行后续操作 │ │ dma_buf_attach(...) │ │ dma_buf_map_attachment(...)

2. fd传递的实现细节

1. UNIX Domain Socket准备

两个进程需要先建立UNIX domain socket连接。通常有两种方式:

方式一:命名socket

// Server端 (可能是exporter或专门的管理服务)intsock=socket(AF_UNIX,SOCK_STREAM,0);structsockaddr_unaddr;addr.sun_family=AF_UNIX;strcpy(addr.sun_path,"/tmp/dma_buf_socket");bind(sock,(structsockaddr*)&addr,sizeof(addr));listen(sock,5);intclient=accept(sock,NULL,NULL);// Client端intsock=socket(AF_UNIX,SOCK_STREAM,0);structsockaddr_unaddr;addr.sun_family=AF_UNIX;strcpy(addr.sun_path,"/tmp/dma_buf_socket");connect(sock,(structsockaddr*)&addr,sizeof(addr));

方式二:socketpair(适用于父子进程)

intsv[2];socketpair(AF_UNIX,SOCK_STREAM,0,sv);// sv[0] 和 sv[1] 是一对连接的socket

2. 发送端 (Exporter) 代码示例

// 假设已经创建了 dma-buf 并获得了 fdintdmabuf_fd=dma_buf_fd(dmabuf,O_CLOEXEC);// 准备发送消息structmsghdrmsg={0};structioveciov[1];charbuf[1]={'X'};// 必须发送至少一个字节的数据iov[0].iov_base=buf;iov[0].iov_len=1;msg.msg_iov=iov;msg.msg_iovlen=1;// 准备辅助数据(这是关键!)union{charbuf[CMSG_SPACE(sizeof(int))];structcmsghdralign;}u;msg.msg_control=u.buf;msg.msg_controllen=sizeof(u.buf);structcmsghdr*cmsg=CMSG_FIRSTHDR(&msg);cmsg->cmsg_level=SOL_SOCKET;cmsg->cmsg_type=SCM_RIGHTS;// 表示传递文件描述符cmsg->cmsg_len=CMSG_LEN(sizeof(int));// 将 fd 复制到辅助数据中memcpy(CMSG_DATA(cmsg),&dmabuf_fd,sizeof(int));// 发送if(sendmsg(socket_fd,&msg,0)<0){perror("sendmsg failed");return-1;}

3. 接收端 (Importer) 代码示例

// 准备接收消息structmsghdrmsg={0};structioveciov[1];charbuf[1];iov[0].iov_base=buf;iov[0].iov_len=1;msg.msg_iov=iov;msg.msg_iovlen=1;// 准备接收辅助数据union{charbuf[CMSG_SPACE(sizeof(int))];structcmsghdralign;}u;msg.msg_control=u.buf;msg.msg_controllen=sizeof(u.buf);// 接收if(recvmsg(socket_fd,&msg,0)<0){perror("recvmsg failed");return-1;}// 提取文件描述符structcmsghdr*cmsg=CMSG_FIRSTHDR(&msg);if(cmsg==NULL||cmsg->cmsg_type!=SCM_RIGHTS){fprintf(stderr,"No fd received\n");return-1;}intreceived_fd;memcpy(&received_fd,CMSG_DATA(cmsg),sizeof(int));// 现在可以使用 received_fd 来访问 dma-buf 了structdma_buf*dmabuf=dma_buf_get(received_fd);

3. 内核层面的处理

当通过SCM_RIGHTS发送fd时,内核做了以下关键操作:

  1. 发送端处理(scm_send->scm_fp_copy):

    • 检查发送进程是否有权访问该fd
    • 增加对应file结构的引用计数(get_file()
    • 将file指针存储在socket缓冲区中
  2. 接收端处理(scm_recv->scm_detach_fds):

    • 在接收进程的文件描述符表中分配新的fd(get_unused_fd_flags()
    • 将file结构安装到新fd上(fd_install()
    • 接收进程现在拥有指向同一file对象的新fd

关键代码路径(内核):

// net/core/scm.cint__scm_send(structsocket*sock,structmsghdr*msg,structscm_cookie*p){...if(cmsg->cmsg_type==SCM_RIGHTS){err=scm_fp_copy(cmsg,&p->fp);// 复制文件描述符...}...}voidscm_detach_fds(structmsghdr*msg,structscm_cookie*scm){...for(i=0;i<fdnum;i++){intnew_fd=get_unused_fd_flags(O_CLOEXEC);// 分配新fd...fd_install(new_fd,fp[i]);// 安装file到新fd...}...}

4. 为什么需要这种机制?

  1. 安全性

    • fd不能被猜测或伪造
    • 只有通过显式传递才能共享
    • 发送方必须有对该fd的访问权限
  2. 正确的引用计数

    • 内核自动管理file对象的引用计数
    • 防止资源泄漏和悬空指针
  3. 跨进程地址空间隔离

    • 每个进程有自己的fd表和地址空间
    • 通过内核中介实现安全共享
  4. 灵活性

    • 支持任意类型的文件描述符(dma-buf、eventfd、socket等)
    • 可以一次传递多个fd

5.实际应用场景

场景1:Wayland compositor 和 客户端

// Wayland compositor (exporter)intdmabuf_fd=create_dmabuf_for_scanout();wl_buffer_send_dmabuf_fd(client,dmabuf_fd);// 内部使用 sendmsg + SCM_RIGHTS// Wayland client (importer)intreceived_fd=wl_buffer_receive_dmabuf_fd();// 内部使用 recvmsg// 将 fd 传给 GPU 驱动做纹理导入

场景2:Android GraphicBuffer 共享

// SurfaceFlinger (exporter)intion_fd=ion_alloc(...);// 或 dma_heap_alloc()android::Parcel parcel;parcel.writeDupFileDescriptor(ion_fd);// 内部通过 binder + SCM_RIGHTSsend_parcel_to_app(parcel);// App (importer)intfd=parcel.readFileDescriptor();// 映射或传给GPU使用

场景3:多媒体Pipeline(Camera -> GPU -> Display)

Camera驱动 (V4L2) │ ├─ dma_buf_export() → fd1 │ └──> [UNIX socket + SCM_RIGHTS] ──> GPU进程 │ ├─ dma_buf_get(fd1) ├─ 渲染到另一个 dma-buf → fd2 │ └──> [SCM_RIGHTS] ──> Display进程 │ └─ dma_buf_get(fd2) drm_mode_addfb2(fd2)

6. 注意事项

  1. fd的生命周期

    • 发送fd后,发送方应该close(fd)自己的副本(如果不再需要)
    • 接收方负责close()接收到的fd
    • 内核会正确管理底层file对象的引用计数
  2. 权限检查

    • 发送方必须对fd有访问权限
    • SELinux/AppArmor 可能施加额外限制
  3. 限制

    • 每次sendmsg可传递的fd数量有限制(通常是SCM_MAX_FD = 253
    • socket缓冲区大小限制可能影响大量fd的传递
  4. 错误处理

    • 如果接收方未能及时处理接收到的fd,可能导致资源泄漏
    • 需要有超时和清理机制

7. 内核视角的完整流程

发送进程 内核 接收进程 │ │ │ ├─ sendmsg(fd=5) │ │ │ │ │ │ │ └─────────────────>├─ scm_send() │ │ │ └─ scm_fp_copy() │ │ │ ├─ fcheck(5) → file │ │ │ ├─ get_file(file) │ │ │ └─ 存储 file* │ │ │ │ │ ├─ socket buffer 中传递 │ │ │ │ │ │ [时间流逝] │ │ │ │ │ │<─────────────── recvmsg() ├─ │ │ │ │ ├─ scm_detach_fds() │ │ │ ├─ get_unused_fd() → 7 │ │ │ └─ fd_install(7, file) │ │ │ │ │ │──────────────────────────>├─ 得到 fd=7 │ │ │ (指向同一file) │ │ │

现在接收进程的fd 7和发送进程的fd 5指向内核中的同一个struct file对象,而该file的private_data指向struct dma_buf,从而实现了dma-buf的共享。

8. 小结

fd的传递是dma-buf跨进程共享的关键环节。通过UNIX domain socket的SCM_RIGHTS机制:

  • Exporter导出dma-buf为fd,通过socket发送
  • Importer接收fd,在内核中获取到同一个dma-buf对象
  • 内核确保引用计数正确、访问安全

这种设计优雅地解决了跨进程共享内核对象的问题,是Linux IPC的重要组成部分,不仅用于dma-buf,也广泛应用于eventfd、pidfd、bpf fd等现代内核特性中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1153581.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MediaPipe Hands实战:手部追踪系统搭建详细步骤

MediaPipe Hands实战&#xff1a;手部追踪系统搭建详细步骤 1. 引言 1.1 AI 手势识别与追踪 随着人机交互技术的不断发展&#xff0c;手势识别正逐渐成为智能设备、虚拟现实、增强现实和智能家居等场景中的核心感知能力。相比传统的触控或语音输入&#xff0c;手势操作更加自…

Z-Image提示词宝典:配合云端GPU快速迭代,1小时出百图

Z-Image提示词宝典&#xff1a;配合云端GPU快速迭代&#xff0c;1小时出百图 1. 为什么需要云端GPU加速提示词测试 作为提示词工程师&#xff0c;最痛苦的莫过于灵感爆发时却被生成速度拖后腿。传统本地生成方式通常面临三个典型问题&#xff1a; 等待时间过长&#xff1a;生…

高性能异步编程新思路:用std::future打造可组合任务链

第一章&#xff1a;高性能异步编程新思路概述在现代软件系统中&#xff0c;异步编程已成为提升吞吐量与响应速度的核心手段。传统的回调模式虽能解决阻塞问题&#xff0c;但易导致“回调地狱”&#xff0c;降低代码可维护性。随着语言层面的支持增强&#xff0c;基于协程与Prom…

没显卡怎么做姿态估计?人体关键点检测云端方案2元起

没显卡怎么做姿态估计&#xff1f;人体关键点检测云端方案2元起 1. 为什么你需要云端姿态估计方案 最近抖音上各种AI体态分析视频火了&#xff0c;作为健身教练的你肯定也注意到了。这些工具能精准识别学员的关节角度、脊柱曲度甚至肌肉发力模式&#xff0c;简直是私教课的神…

APACHE FESOD vs 传统开发:效率对比实测

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个对比测试项目&#xff0c;分别用传统方式和APACHE FESOD实现相同的企业审批流程系统。要求&#xff1a;1.设计相同的功能需求文档&#xff1b;2.记录两种方式的开发时间、…

开源AI手势识别模型发展:MediaPipe Hands实战指南

开源AI手势识别模型发展&#xff1a;MediaPipe Hands实战指南 1. 引言&#xff1a;人机交互的新范式——AI手势识别与追踪 在智能硬件、虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和人机交互&#xff08;HCI&#xff09;快速发展的今天&#x…

揭秘契约编程中的设计陷阱:3个常见错误及避坑指南

第一章&#xff1a;契约编程的核心概念与价值契约编程&#xff08;Design by Contract&#xff09;是一种软件设计方法论&#xff0c;强调在组件交互中明确定义责任与义务。它通过前置条件、后置条件和不变式来规范函数或方法的行为&#xff0c;提升代码的可维护性与可靠性。契…

9款AI论文工具隐藏技巧:知网维普查重一把过,无AIGC痕迹

90%的学生都不知道这个隐藏功能&#xff1a; 你以为AI写论文就是简单的“CtrlC&#xff0c; CtrlV”&#xff1f;大错特错&#xff01;导师和查重系统背后&#xff0c;藏着一套你从未了解的“潜规则”和“黑科技”。今天&#xff0c;我就要揭露那些能让你的论文在知网、维普面前…

DeepPose实战指南:5分钟部署骨骼检测,云端GPU按秒计费

DeepPose实战指南&#xff1a;5分钟部署骨骼检测&#xff0c;云端GPU按秒计费 引言&#xff1a;为什么选择DeepPose&#xff1f; 想象一下&#xff0c;你正在开发一个健身APP&#xff0c;需要自动识别用户的运动姿势是否正确。或者你是一个游戏开发者&#xff0c;想让虚拟角色…

AI手势识别支持中文文档吗?开发者友好性评测教程

AI手势识别支持中文文档吗&#xff1f;开发者友好性评测教程 1. 引言&#xff1a;AI手势识别与追踪的现实意义 随着人机交互技术的不断演进&#xff0c;AI手势识别正逐步从实验室走向消费级应用。无论是智能穿戴设备、AR/VR交互系统&#xff0c;还是远程会议控制和无障碍操作…

YOLO姿态估计保姆级教程:没GPU也能跑,学生党必备

YOLO姿态估计保姆级教程&#xff1a;没GPU也能跑&#xff0c;学生党必备 引言 研究生阶段最怕什么&#xff1f;导师突然布置任务要求复现最新论文&#xff0c;而实验室GPU资源排队要等两周&#xff0c;自己手头只有一台MacBook笔记本&#xff0c;组会汇报却近在眼前。这种场景…

2024北大中文核心期刊目录解析:学术发表必看指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个学术期刊查询系统&#xff0c;包含2024年北大中文核心期刊目录的完整数据。系统应支持按学科分类检索、期刊影响因子查询、投稿指南查看等功能。要求界面简洁&#xff0c;…

没8G显存怎么办?Z-Image云端方案轻松应对大图生成

没8G显存怎么办&#xff1f;Z-Image云端方案轻松应对大图生成 引言&#xff1a;游戏开发者的材质贴图困境 作为一名游戏开发者&#xff0c;你是否经常遇到这样的困扰&#xff1a;当需要生成4K高清材质贴图时&#xff0c;家用显卡的8G显存根本不够用&#xff0c;导致生成过程卡…

OpenCore Legacy Patcher显示修复与多屏输出解决方案大全

OpenCore Legacy Patcher显示修复与多屏输出解决方案大全 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 老旧Mac升级新版macOS后&#xff0c;外接投影仪或多显示器时经常…

手势交互系统优化:MediaPipe Hands性能测试

手势交互系统优化&#xff1a;MediaPipe Hands性能测试 1. 引言&#xff1a;AI 手势识别与追踪的工程价值 随着人机交互技术的演进&#xff0c;非接触式手势控制正逐步从科幻走向现实。在智能硬件、AR/VR、远程会议和无障碍交互等场景中&#xff0c;精准、低延迟的手势识别能…

Windows 11安装终极指南:一键绕过硬件限制的完整解决方案

Windows 11安装终极指南&#xff1a;一键绕过硬件限制的完整解决方案 【免费下载链接】MediaCreationTool.bat Universal MCT wrapper script for all Windows 10/11 versions from 1507 to 21H2! 项目地址: https://gitcode.com/gh_mirrors/me/MediaCreationTool.bat 还…

AI生图新选择:Z-Image云端体验比Stable Diffusion更省心

AI生图新选择&#xff1a;Z-Image云端体验比Stable Diffusion更省心 1. 为什么选择Z-Image云端镜像&#xff1f; 如果你已经使用Stable Diffusion&#xff08;SD&#xff09;一段时间&#xff0c;可能已经遇到过这些问题&#xff1a; 每次更新都要手动安装依赖包&#xff0c…

5分钟快速验证:你的项目受废弃API影响有多大

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个极简的在线检测工具&#xff0c;用户只需粘贴代码或上传文件&#xff0c;立即获得&#xff1a;1) 受影响API列表 2) 严重程度评估 3) 快速修复建议。输出结果可视化展示&a…

PMX转VRM完整实战指南:从模型导入到完美转换

PMX转VRM完整实战指南&#xff1a;从模型导入到完美转换 【免费下载链接】VRM-Addon-for-Blender VRM Importer, Exporter and Utilities for Blender 2.93 or later 项目地址: https://gitcode.com/gh_mirrors/vr/VRM-Addon-for-Blender 想要将MMD模型无缝转换为VRM格式…

Windows任务栏美化革命:TaskbarX让你的桌面焕然一新

Windows任务栏美化革命&#xff1a;TaskbarX让你的桌面焕然一新 【免费下载链接】TaskbarX Center Windows taskbar icons with a variety of animations and options. 项目地址: https://gitcode.com/gh_mirrors/ta/TaskbarX 在数字工作时代&#xff0c;我们每天面对电…