news 2026/3/28 1:45:15

中断下半部分-tasklet/workqueue

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
中断下半部分-tasklet/workqueue

tasklet

  • tasklet机制是内核定义的几种softirq之一(常用)

根据优先级不同内核将tasklet分成两种:TASKLET_SOFTIRQ 和 HI_SOFTIRQ (后者优先级高)

执行时机通常是上半部分返回的时候。

1.1 tasklet机制初始化

在linux系统内核初始化的时候,通过调用softirq_init( )为TASKLET_SOFTIRQ 和 HI_SOFTIRQ
安装了执行函数。

1.2 相关的操作

struct tasklet_struct
{
struct tasklet_struct *next; //用来将系统中tasklet链接成链表
unsigned long state; //记录在系统中tasklet的状态
atomic_t count; //如果为0,则不可被调度执行
void (*func)(unsigned long); //在tasklet上执行函数或者延迟函数
unsigned long data; //将data传递给fun指向的函数
};

1.2.1 初始化tasklet

声明并初始化一个静态的tasklet对象;

//struct tasklet_struct name;

//void func(unsigned long);

//unsingned long data;

DECLARE_TASKLET(name, func, data);

动态初始化tasklet对象

void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)

–>tasklet_init(&name, fun, data);

1.2.2 提交一个tasklet

在声明和初始化一个tasklet对象之后,
驱动程序需要调用tasklet_schedule来向系统提交tasklet(一般在中断处理程序中提交)

void tasklet_schedule(struct tasklet_struct *t)

tasklet_schedule(name);

工作队列

使用内核自己带的工作队列

  • 工作队列执行的上下文是内核线程,因此可以调度和睡眠

  • 在Workqueue机制中,Linux系统在初始化的时候通过init_workqueues(void)函数创建了一个workqueue队列——events,

  • 用户可以直接初始化一个work_struct对象,然后在该队列中进行调度,使用更加方便。

//定义一个工作节点structwork_sturctmy_wrok;//定一个处理函数voidmy_wq_func(structwork_struct*work);/*初始化工作节点,并和处理函数绑定*/INIT_WORK(&my_work,my_wq_func)/*使用内核自己创建的工作队列-events和处理线程, 提交工作节点(一般在中断处理函数中)*/schedule_work(&my_wq)--->queue_work(system_wq,work);

使用自己创建工作队列

首先创建工作队列:
#define create_workqueue(name)
alloc_workqueue((name), WQ_MEM_RECLAIM, 1)

—>struct workqueue_struct* myworkqueue = create_workqueue(“mywq”); /创建工作队列和处理线程/

提交工作:
int queue_work(struct workqueue_struct *wq, struct work_struct *work)

–>queue_work(myworkqueue, &my_work);

#definecreate_workqueue(name)\alloc_workqueue("%s",__WQ_LEGACY|WQ_MEM_RECLAIM,1,(name))structworkqueue_struct*alloc_workqueue(constchar*fmt,unsignedintflags,intmax_active,...){size_ttbl_size=0;va_list args;structworkqueue_struct*wq;structpool_workqueue*pwq;/* * Unbound && max_active == 1 used to imply ordered, which is no * longer the case on NUMA machines due to per-node pools. While * alloc_ordered_workqueue() is the right way to create an ordered * workqueue, keep the previous behavior to avoid subtle breakages * on NUMA. */if((flags&WQ_UNBOUND)&&max_active==1)flags|=__WQ_ORDERED;/* see the comment above the definition of WQ_POWER_EFFICIENT */if((flags&WQ_POWER_EFFICIENT)&&wq_power_efficient)flags|=WQ_UNBOUND;/* allocate wq and format name */if(flags&WQ_UNBOUND)tbl_size=nr_node_ids*sizeof(wq->numa_pwq_tbl[0]);wq=kzalloc(sizeof(*wq)+tbl_size,GFP_KERNEL);if(!wq)returnNULL;if(flags&WQ_UNBOUND){wq->unbound_attrs=alloc_workqueue_attrs();if(!wq->unbound_attrs)gotoerr_free_wq;}va_start(args,max_active);vsnprintf(wq->name,sizeof(wq->name),fmt,args);va_end(args);max_active=max_active?:WQ_DFL_ACTIVE;max_active=wq_clamp_max_active(max_active,flags,wq->name);/* init wq */wq->flags=flags;wq->saved_max_active=max_active;mutex_init(&wq->mutex);atomic_set(&wq->nr_pwqs_to_flush,0);INIT_LIST_HEAD(&wq->pwqs);INIT_LIST_HEAD(&wq->flusher_queue);INIT_LIST_HEAD(&wq->flusher_overflow);INIT_LIST_HEAD(&wq->maydays);wq_init_lockdep(wq);INIT_LIST_HEAD(&wq->list);if(alloc_and_link_pwqs(wq)<0)gotoerr_unreg_lockdep;if(wq_online&&init_rescuer(wq)<0)gotoerr_destroy;if((wq->flags&WQ_SYSFS)&&workqueue_sysfs_register(wq))gotoerr_destroy;/* * wq_pool_mutex protects global freeze state and workqueues list. * Grab it, adjust max_active and add the new @wq to workqueues * list. */mutex_lock(&wq_pool_mutex);mutex_lock(&wq->mutex);for_each_pwq(pwq,wq)pwq_adjust_max_active(pwq);mutex_unlock(&wq->mutex);list_add_tail_rcu(&wq->list,&workqueues);mutex_unlock(&wq_pool_mutex);returnwq;err_unreg_lockdep:wq_unregister_lockdep(wq);wq_free_lockdep(wq);err_free_wq:free_workqueue_attrs(wq->unbound_attrs);kfree(wq);returnNULL;err_destroy:destroy_workqueue(wq);returnNULL;}EXPORT_SYMBOL_GPL(alloc_workqueue);
  • queue_work
/* not bound to any CPU, prefer the local CPU */,//WORK_CPU_UNBOUND = NR_CPUS,staticinlineboolqueue_work(structworkqueue_struct*wq,structwork_struct*work){returnqueue_work_on(WORK_CPU_UNBOUND,wq,work);}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 5:27:27

C++物理引擎碰撞检测实战指南(从零搭建高精度检测系统)

第一章&#xff1a;C物理引擎碰撞检测概述在开发高性能的C物理引擎时&#xff0c;碰撞检测是实现真实交互的核心模块之一。它负责判断两个或多个物体在虚拟空间中是否发生接触或穿透&#xff0c;从而触发后续的响应计算&#xff0c;如反弹、摩擦或形变。基本原理与挑战 碰撞检测…

作者头像 李华
网站建设 2026/3/27 12:23:01

从零构建C++ AIGC推理框架,实现超高吞吐量的实战路径

第一章&#xff1a;从零构建C AIGC推理框架的必要性在人工智能生成内容&#xff08;AIGC&#xff09;快速发展的背景下&#xff0c;高性能、低延迟的推理系统成为实际落地的关键。尽管Python生态提供了丰富的深度学习框架&#xff0c;但在生产环境中&#xff0c;尤其是在对性能…

作者头像 李华
网站建设 2026/3/27 19:00:56

vue+uniapp+ssm农副产品交易系统原生小程序vue

文章目录摘要主要技术与实现手段系统设计与实现的思路系统设计方法java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;摘要 基于Vue.js、Uniapp和SSM框架的农副产品交易系统原生小程序&#xff0c;旨在为农户和消…

作者头像 李华
网站建设 2026/3/24 10:42:39

Keil5编辑器字符编码设置从零实现

彻底解决Keil5中文注释乱码&#xff1a;从编码原理到实战配置 你有没有遇到过这样的场景&#xff1f;在Keil5里辛辛苦苦写了一段中文注释&#xff0c;回头一看——满屏方块、问号&#xff0c;甚至变成一堆看不懂的“火星文”&#xff1f;而同事用VS Code打开同一个文件却显示正…

作者头像 李华
网站建设 2026/3/18 15:31:19

国内访问HuggingFace困难?试试这些稳定镜像网站

国内访问HuggingFace困难&#xff1f;试试这些稳定镜像网站 在AI研发的日常中&#xff0c;你是否也遇到过这样的场景&#xff1a;满怀期待地打开终端&#xff0c;准备下载一个热门的Stable Diffusion模型或LLM权重&#xff0c;结果git clone命令卡在10%一动不动&#xff1f;再刷…

作者头像 李华