当前位置: 首页 > news >正文

Linux 内核 Workqueue 原理与实现及其在 KFD SVM功能的应用

1. 前言

在 Linux 内核开发中,workqueue(工作队列)是一种极为重要的异步任务处理机制。它允许内核模块和驱动程序将需要在进程上下文(而非中断上下文)中执行的任务延后、异步地交由内核线程处理,从而实现中断处理与复杂/耗时操作的解耦,提升系统实时性和健壮性。

KFD(Kernel Fusion Driver),广泛使用 workqueue 机制来处理异步事件、内存管理、SVM(共享虚拟内存)区间管理、GPU 迁移等复杂任务。本文将系统介绍 workqueue 的原理、实现、API、典型用法,并结合 KFD 驱动源码进行深入分析。

2. Workqueue 的基本概念

2.1 为什么需要 Workqueue

  • 中断上下文限制:在中断处理函数(ISR)中,不能执行阻塞、耗时或可能睡眠的操作,只能做快速判定和简单处理。

  • 异步任务需求:许多内核任务(如 IO、内存回收、设备管理等)需要在进程上下文中异步完成,不能阻塞关键路径。

  • 解耦与性能:workqueue 机制将复杂操作延后到内核线程中执行,提升中断响应速度,避免系统卡顿。

2.2 Workqueue 的基本原理

  • 工作项(work item):用 struct work_struct 或 struct delayed_work 描述的任务单元,包含待执行的回调函数和上下文。

  • 工作队列(workqueue):内核维护的任务队列,负责调度和执行工作项。可以是全局队列(system_wq)、专用队列,也可以是延迟队列。

  • 内核线程:workqueue 由内核线程(如 kworker/*)驱动,负责从队列中取出工作项并调用其回调函数。

2.3 Workqueue 的优势

  • 支持异步、延迟、定时任务

  • 自动并发调度,可根据 CPU 数量自动扩展 worker 线程。

  • 支持多队列、优先级、绑定 CPU 等高级特性

  • API 简单,易于集成到驱动和内核模块中

3. Workqueue 的实现机制

3.1 关键数据结构

  • struct work_struct:普通工作项,适合立即执行的任务。

  • struct delayed_work:延迟工作项,适合定时/延后执行的任务。

  • struct workqueue_struct:工作队列对象,描述一个 workqueue 的属性和状态。

  • struct worker:内核 worker 线程,负责实际执行工作项。

3.2 工作项的生命周期

  1. 初始化:使用 INIT_WORK() 或 INIT_DELAYED_WORK() 宏初始化工作项,指定回调函数。

  2. 调度:调用 schedule_work() 或 queue_delayed_work() 将工作项加入队列。

  3. 执行:内核 worker 线程从队列中取出工作项,调用其回调函数。

  4. 完成/复用:工作项执行完毕后可复用或释放。可通过 cancel_work_sync() 等 API 取消未执行的工作项。

3.3 工作队列的类型

  • system_wq:全局普通工作队列,适合大多数场景。

  • system_highpri_wq:高优先级队列。

  • system_long_wq:适合长时间运行任务。

  • system_unbound_wq:不绑定 CPU,可跨 NUMA 节点调度。

  • 自定义 workqueue:驱动可通过 alloc_workqueue() 创建专用队列,支持更多定制。

3.4 典型 API

API 名称作用说明
INIT_WORK()初始化普通工作项
INIT_DELAYED_WORK()初始化延迟工作项
schedule_work()调度普通工作项到 system_wq
queue_delayed_work()调度延迟工作项到队列
flush_work()等待指定工作项完成
cancel_work_sync()取消并同步等待工作项
alloc_workqueue()创建自定义工作队列
destroy_workqueue()销毁自定义工作队列

4. Workqueue 的实现细节

4.1 工作队列的调度机制

  • 内核为每个 workqueue 维护一个任务队列和若干 worker 线程。

  • 当有工作项被调度时,worker 线程会被唤醒,从队列中取出工作项并执行其回调。

  • 对于延迟工作项,内核使用定时器机制,在到期后将其加入队列。

4.2 并发与同步

  • 多个 worker 线程可并发处理不同的工作项,提升吞吐。

  • 同一工作项不能被重复调度,内核通过 work->data 字段防止重复入队。

  • 可通过 flush_work() 等 API 等待工作项完成,保证同步。

4.3 取消与回收

  • cancel_work_sync() 可取消未执行的工作项,并等待正在执行的工作项完成。

  • flush_workqueue() 可等待整个队列的所有工作项完成。

4.4 性能与扩展性

  • 支持 NUMA、CPU 亲和性、优先级等高级特性。

  • 可根据系统负载自动扩展 worker 线程数量,避免瓶颈。

5. Workqueue 在 KFD 驱动中的应用

KFD 驱动作为 AMD ROCm 平台的核心组件,广泛使用 workqueue 机制来处理异步事件、内存管理、SVM 区间管理、GPU 迁移等复杂任务。下面结合 KFD 源码,简要分析SVM中的应用场景。

5.1 SVM 区间管理中的 deferred work

5.1.1 deferred_list_work

INIT_WORK(&svms->deferred_list_work, svm_range_deferred_list_work);
  • 用途
    • 处理 SVM 区间的延迟操作,如区间拆分、合并、unmap、notifier 更新等。

    • 保证复杂区间操作在进程上下文中安全完成,避免死锁和竞态。

  • 典型流程
    1. 某些操作(如 unmap、属性变更)将区间加入 deferred_range_list

    2. 调用 schedule_work(&svms->deferred_list_work) 异步处理。

    3. svm_range_deferred_list_work 回调中遍历 deferred list,依次处理每个区间的具体操作(如 unlink、free、notifier 更新等)。

5.1.2 restore_work

INIT_DELAYED_WORK(&svms->restore_work, svm_range_restore_work);
  • 用途
    • 处理 SVM 区间被驱逐(evict)后的恢复操作,如重新映射、迁移、恢复 GPU 队列等。

    • 支持延迟重试机制,保证恢复操作在资源可用时自动重试。

  • 典型流程
    1. 区间被 evict 后,调用 queue_delayed_work(system_freezable_wq, &svms->restore_work, delay)

    2. svm_range_restore_work 回调中遍历所有被驱逐区间,尝试恢复映射和队列。

    3. 如果恢复失败,自动再次调度自身,直到成功。

5.2 VRAM BO 驱逐与释放

5.2.1 eviction_work

INIT_WORK(&svm_bo->eviction_work, svm_range_evict_svm_bo_worker);
  • 用途
    • 当 VRAM buffer object 需要被驱逐时,异步迁移数据到系统内存,并释放相关资源。

    • 保证驱逐操作不会阻塞关键路径,提升系统响应能力。

  • 典型流程
    1. 触发驱逐时,调用 schedule_work(&svm_bo->eviction_work)

    2. svm_range_evict_svm_bo_worker 回调中完成数据迁移、资源释放等操作。

5.2.2 release_work

INIT_WORK(&svm_bo->release_work, svm_range_bo_wq_release);
  • 用途
    • 异步释放 VRAM BO 相关资源,避免在关键路径中直接释放导致死锁或性能抖动。

5.3 其他典型应用

KFD 中断处理:KFD 的中断处理采用“快速判定 + 工作队列”模式,ISR 只做判定,复杂事件推送到工作队列异步处理(interrupt_work)

CRIU 检查点/恢复:部分 SVM 区间的恢复、属性设置等操作也通过 workqueue 机制异步完成。


6. KFD SVM 区间管理中的 Workqueue 代码分析

以 SVM 区间属性设置为例,流程如下:

  1. 属性设置请求
    用户空间通过 ioctl 发起 SVM 区间属性设置请求,驱动进入 svm_range_set_attr

  2. 区间拆分/合并/克隆
    调用 svm_range_add,根据新属性和现有区间关系,拆分、克隆、合并区间,生成 insert_list、update_list、remove_list、remap_list。

  3. 事务性应用

    • insert_list:通过 svm_range_add_to_svms 和 svm_range_add_notifier_locked 插入区间和注册 notifier。

    • update_list:应用新属性,必要时触发迁移和映射。

    • remove_list:通过 svm_range_unlinksvm_range_remove_notifiersvm_range_free 异步移除和释放区间。

  4. 延迟操作
    某些操作(如 unmap、notifier 更新)通过 svm_range_add_list_work 加入 deferred_list,调用 schedule_work(&svms->deferred_list_work) 异步处理。

  5. 驱逐与恢复
    区间被驱逐时,通过 queue_delayed_work(&svms->restore_work) 异步恢复,保证系统健壮性。

 

http://www.dtcms.com/a/351280.html

相关文章:

  • LeetCode - 844. 比较含退格的字符串
  • LeetCode 438. 找到字符串中所有的字母异位词
  • 微算法科技(NASDAQ:MLGO)通过修改 Grover 算法在可重构硬件上实现动态多模式搜索
  • LeetCode - 946. 验证栈序列
  • 智慧园区:从技术赋能到价值重构,解锁园区运营新范式
  • 透视光合组织大会:算力生态重构金融AI落地新实践
  • 亚马逊类目合规风暴:高压清洗机品类整顿背后的运营重构与风险防御
  • 便携屏选购指南:常见作用、移动性优势及多场景应用详解
  • 前端性能优化新维度:渲染流水线深度解析
  • 【前端开发实战】从零开始开发Chrome浏览器扩展 - 快乐传播者项目完整教程
  • DeepSeek分析
  • spring如何通过实现BeanPostProcessor接口计算并打印每一个bean的加载耗时
  • 【数据结构】树和二叉树——二叉树
  • pytorch_grad_cam 库学习笔记—— Ablation-CAM 算法的基类 AblationCAM 和 AblationLayer
  • OneCode RAD:揭秘前端开发的配置化魔法
  • 【RAGFlow代码详解-14】知识图谱处理
  • Linux之SELinux 概述、SSH 密钥登录、服务器初始化
  • IUV5G专网排障(下)
  • 开源大模型本地部署
  • [Mysql数据库] 知识点总结3
  • 基于Android的电影院订票选座系统、基于Android的电影院管理系统app#基于Android的电影在线订票系统
  • 玩转QEMU硬件模拟器 - vexpress-a9开发板模拟开发
  • 深入浅出理解支持向量机:从原理到应用,解锁分类算法的核心密码
  • 宝石组合(蓝桥杯)
  • UX 设计入门终章:让洞察落地!用用户流程图、IA 和旅程图,设计用户与产品的互动故事
  • 介绍一下 bev fusion 网络结构
  • 微服务-27.配置管理-什么是配置管理
  • FULL OUTER JOIN 的作用与使用场景(检查表与表是否存在不同记录)
  • UML 时序图中交互片段操作符的详细解析与 C/C++ 实现示例
  • 五、VSCODE SSH连接linux服务器免密登录