news 2026/7/22 21:58:34

中断下半部分-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/7/19 2:09:17

Keil编译器下载v5.06:项目创建与编译设置实战案例

Keil编译器下载v5.06实战指南&#xff1a;从零搭建STM32开发环境在嵌入式系统的世界里&#xff0c;一个稳定高效的开发工具链&#xff0c;往往决定了项目成败。对于使用ARM Cortex-M系列MCU的工程师而言&#xff0c;Keil MDK&#xff08;Microcontroller Development Kit&#…

作者头像 李华
网站建设 2026/7/20 20:10:03

别再用旧标准了!GCC 14已支持C++26这7个并发新特性

第一章&#xff1a;GCC 14对C26并发特性的整体支持概览GCC 14作为GNU编译器集合的重要版本更新&#xff0c;在C标准支持方面迈出了关键一步&#xff0c;尤其在面向C26草案的并发编程特性上提供了初步但具有前瞻性的实现。尽管C26标准尚未最终定稿&#xff0c;GCC 14已基于当前委…

作者头像 李华
网站建设 2026/7/20 20:24:31

C++26核心特性实测(Clang 17编译器验证结果震惊业界)

第一章&#xff1a;C26核心特性概述与Clang 17支持现状C26作为C标准的下一个重要演进版本&#xff0c;正处于积极的提案整合与技术验证阶段。尽管尚未正式发布&#xff0c;多个核心特性已在ISO WG21委员会中达成初步共识&#xff0c;并逐步被主流编译器试验性支持。Clang 17作为…

作者头像 李华
网站建设 2026/7/20 20:10:03

ZeRO十年演进(2015–2025)

ZeRO十年演进&#xff08;2015–2025&#xff09; 一句话总论&#xff1a; ZeRO&#xff08;Zero Redundancy Optimizer&#xff09;从2019年Microsoft内部研究的“分布式训练内存优化技术”&#xff0c;到2025年已进化成“万亿级多模态大模型训练标配量子混合精度自进化分片具…

作者头像 李华
网站建设 2026/7/19 15:44:03

从零搭建C++分布式AI调度平台,资深架构师的10年经验总结

第一章&#xff1a;从零构建C分布式AI调度平台的背景与意义随着人工智能模型规模的持续扩大&#xff0c;单机计算资源已无法满足训练与推理任务的需求。分布式架构成为支撑大规模AI任务的核心技术路径。在此背景下&#xff0c;构建一个高效、可扩展且低延迟的AI任务调度平台显得…

作者头像 李华
网站建设 2026/7/21 18:57:58

谐波减速器十年演进(2015–2025)

谐波减速器十年演进&#xff08;2015–2025&#xff09; 一句话总论&#xff1a; 2015年谐波减速器还是“Harmonic Drive&#xff08;HD&#xff09;日本垄断刚性高背隙2–5万元单价”的工业时代&#xff0c;2025年已进化成“中国超薄零背隙纳米级精度一体化关节量子级自愈补偿…

作者头像 李华