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

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.xdnf.cn/news/18731.html

相关文章:

  • Linux--seLinux的概述
  • 数据结构07(Java)-- (堆,大根堆,堆排序)
  • 常见的设计模式
  • 博士招生 | 南洋理工大学 PINE Lab 招收全奖博士
  • [新启航]新启航激光频率梳 “光量子透视”:2μm 精度破除遮挡,完成 130mm 深孔 3D 建模
  • 【国密证书】CentOS 7 安装 GmSSL 并生成国密证书
  • Docker移动安装目录的两种实现方案
  • 微硕WINSOK高性能MOS管WSF90N10,助力洗衣机能效与可靠性升级
  • Java:IO流——基础篇
  • Redis高级篇:在Nginx、Redis、Tomcat(JVM)各环节添加缓存以实现多级缓存
  • 一文丝滑使用Markdown:从写作、绘图到转换为Word与PPT
  • MongoDB /redis/mysql 界面化的数据查看页面App
  • M3-Agent:让AI拥有长期记忆的新尝试
  • UML 时序图中交互片段操作符的详细解析与 C/C++ 实现示例
  • React 高阶组件
  • 服务器初始化
  • APM 系列(一):Skywalking 与 Easyearch 集成
  • 如何在项目中集成XXL-JOB
  • 在线提取维基百科Wikipedia文章页面及离线批处理Wikipedia XML Dump文件
  • 通信中间件 Fast DDS(二) :详细介绍
  • 安卓Android低功耗蓝牙BLE连接异常报错133
  • 计算机实习经历包装/编写
  • 嵌入式系统学习Day22(进程)
  • STL——vector的使用(快速入门详细)
  • Ansible自动化运维介绍与安装
  • 信贷模型域——清收阶段模型(贷后模型)
  • 简述mysql中索引类型有哪些,以及对数据库的性能的影响?
  • QML中的QtObject
  • C# NX二次开发:绘图区控件和指定矢量控件详解
  • vscode--快捷键