news 2026/5/9 4:42:25

中断下半部分-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/5/6 23:25:28

Keil uVision5下载资源获取渠道:官方与镜像站点对比说明

如何安全高效地下载 Keil uVision5&#xff1f;官方与国内镜像的实战选择指南 在嵌入式开发的世界里&#xff0c;如果你用的是 STM32、NXP 或者任何一款基于 ARM Cortex-M 内核的微控制器&#xff0c; Keil uVision5 几乎是你绕不开的名字。 它不是最炫的 IDE&#xff0c;也…

作者头像 李华
网站建设 2026/4/30 13:44:26

为什么你的AIGC推理吞吐上不去?C++级优化方案全公开

第一章&#xff1a;C AIGC 推理吞吐量的瓶颈本质在现代AIGC&#xff08;AI Generated Content&#xff09;系统中&#xff0c;C常用于实现高性能推理引擎。尽管其具备接近硬件的执行效率&#xff0c;实际部署中仍面临吞吐量受限的问题。根本原因并非单一因素所致&#xff0c;而…

作者头像 李华
网站建设 2026/4/16 16:45:07

人物面部细节保留技巧:关键特征提取的训练策略

人物面部细节保留技巧&#xff1a;关键特征提取的训练策略 在数字人、虚拟偶像和个性化内容创作日益普及的今天&#xff0c;如何让 AI 准确“记住”一个人的脸&#xff0c;成了生成式模型落地的关键挑战。我们常遇到这样的问题&#xff1a;输入几十张某位明星的照片进行微调&am…

作者头像 李华
网站建设 2026/5/6 9:45:18

【性能飞跃】:如何用Rust重构C++模块并实现无缝绑定?

第一章&#xff1a;性能飞跃的起点——Rust与C融合的必要性 在现代系统级编程领域&#xff0c;性能与安全的平衡成为核心挑战。C以其高效的内存控制和广泛的硬件支持长期占据主导地位&#xff0c;然而其对指针操作和内存管理的手动处理机制也带来了潜在的运行时风险。与此同时&…

作者头像 李华