中断相关一【转】

简介:
 
Linux中断编程:
  申请irq:
   int request_irq(unsigned int irq,  \
      void (*handler)(int irq,void *dev_id,struct pt_regs *regs), \
 unsigned long irqflags,const char * devname,void *dev_id);
  其中irq是申请的软件中断号,
  handler是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。
  irqflags是中断处理的属性,若设置了SA_INTERRUPT,则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了SA_SHIRQ,则表示多个设备
  共享中断,dev_id在中断共享时会用到,一半设置为这个设备的设备结构体或者NULL。
  request_irq()返回0表示成功,返回-INVAL表示中断号无效或者处理函数指针为NULL,返回-EBUSY表示中断已经被占用并且不能共享。
 
  释放irq:
    void free_irq(unsigned int irq,void *dev_id);
 
 使能和屏蔽中断:
     void disable_irq(int irq);
     void disable_irq_nosync(int irq);
     void enbale_irq(int irq);
    disable_irq_nosync()与disable_irq()的区别在于前者立即返回,而后者等待目前的中   断处理完成。注意,这3个函数作用于可编程中断控制器,因此,对系统内的所有CPU都生效。
 
 以下两个函数将屏蔽本CPU的所有中断:
void local_irq_save(unsigned long flags);
void local_irq_disable(void);
  前者将目前的中断状态保留在flags中,注意,flags被直接传递,而不是通过指针传递,后者直接禁止中断。
 
  与上述两个禁止中断对应的恢复中断的方法:
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
  以上因为开头是local,所以作用范围是本CPU。
 
 
  底半部机制:
  Linux系统实现底半部的机制主要有tasklet,工作队列,和软中断。
1.tasklet:
void my_tasklet_func(unsigned long);/*定义一个处理函数*/
DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);
/*定义一个tasklet结构my_tasklet,与my_tasklet_fun(data)相关联*/
  代码DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)实现了my_tasklet的tasklet并将其与my_taskletlet_func()这个函数绑定,而传入这个函数的参数是data.
  在需要调度tasklet的时候引用一个tasklet_schedule()函数就能使系统在适当时候进行调度运行,如下所示:
    tasklet_shedule(*my_tasklet);
  使用tasklet作为底半部处理中断的设备驱动程序模板如下:(仅包含与中断相关的部分)
 
    /*定义tasklet和底半部函数并关联*/
void xxx_do_tasklet(unsigned long);
DECLARE(xxx_tasklet,xxx_do_tasklet,0);
 
    /*中断处理底半部*/
void xxx_do_tasklet(unsigned long)
{
...
}
 
    /*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
...
tasklet_schedule(&xxx_tasklet);
...
}
 
    /*设备驱动模块加载函数*/
int __init xxx_init(void)
{
...
/*申请中断*/
result=request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,"xxx",NULL);   
...                                                                                                                                                                                       
}
 
     /*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq,xxx_interrupt);
...
}
 
  其中irqreturn_t返回类型的定义int,中断处理程序顶半部一般返回IRQ——HANDLED.
 
  2.工作队列
  工作队列的使用方法和tasklet非常相似,下面的代码用于定义一个工作队列和一个底半部执行函数
struct work_struct my_wq; /*定义一个工作队列*/
void my_wq_func(unsigned long);  /*定义一个处理函数*/
  通过INIT_WORK()可以初始化这个工作队列并将工作队列与处理函数绑定,如下所示:
INIT_WORK(&my_wq,(void(*)(void *))my_wq_func,NULL);
/*初始化工作队列并将其与处理函数绑定*/
  与tasklet_schedule()对应的使用工作队列执行的函数为shedule_work():
shedule_work(&my_wq);/*调度工作队列执行*/
 
  使用工作队列实现中断底半部的设备驱动程序模板如下:
/*定义工作队列和关联函数*/
struct work_struct xxx_wq;
void xxx_do_work(unsigned long);
/*中断处理底半部*/
void xxx_do_work(unsigned long)
{
...
}
/*中断处理的顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
...
schedule_work(&xxx_wq);
...
}
 
/*设备驱动模块加载函数*/
int xxx_init(void)
{
 ...
/*申请中断*/
result=request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,"xxx",NULL);
...
/*初始化工作队列*/
INIT_WORK(&xxx_wq,(void(*)(void*)) xxx_do_work,NULL);
...
}
 
/*设备驱动模块卸载函数*/
void xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq,xxx_interrupt);
...
}
  上述程序在设计驱动模块加载函数中增加了初始化工作队列的代码。
  尽管LINUX专家们多建议在设备第一次打开是才申请设备的中断并在最后一次关闭时释放中断以尽量减少中断被这个设备的占用的时间,但是,在多数情况下,为求省事,大多数驱动工程师还
  是将中断申请和释放的工作放在了设备驱动的模块加载和卸载函数中。
 
  3软中断
  软中断是用软件方式模拟硬件中断的概念,实现宏观上的异步执行效果,tasklet也是基于软件中断实现的。
 
  硬中断,软中断和信号的区别:
  硬中断是外部设备对CPU的中断,软中断通常是硬中断服务程序对内核的中断,而信号则是有内核(或其他程序)对某个进程的中断。
 
  在内核中,用softirq_action结构体表征一个软中断,这个结构体包含软中处理函数指针和传递给该函数的参数,使用open_softirq()函数可以注册软中对应的处理函数,而raise_softirq()函数可以出发一个软中断。
 
  软中断和tasklet仍然运行于中断上下文,而工作队列则运行与进程的上下文。因此,软中断和tasklet处理函数中不能睡眠,而工作队列处理函数中允许睡眠。
 
  local_bh_disable()和local_bh_enable()是内核中用于禁止和使能软中断和tasklet底半部机制的函数。









本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5063443.html ,如需转载请自行联系原作者

相关文章
|
SQL 关系型数据库 数据库
|
存储 缓存 网络安全
在局域网内访问项目时遇到了OSS路径错误的问题
在局域网内访问项目时遇到了OSS路径错误的问题
1007 2
|
26天前
|
网络协议 NoSQL API
转转客服IM系统的WebSocket集群架构设计和部署方案
客服IM系统是转转自研的在线客服系统,是用户和转转客服沟通的重要工具,主要包括机器人客服、人工客服、会话分配、技能组管理等功能。在这套系统中,我们使用了很多开源框架和中间件,今天讲一下客服IM系统中WebSocket集群的的实践和应用。
93 0
|
12月前
TO B产品经理:每个阶段的学习与提升之路
对于TO B产品经理来说,每个阶段都是一次学习和提升的机会。从建立基础到深化专业知识,再到提升战略眼光和持续创新与学习,每一步都需要付出努力和汗水。但正是这样的不断学习和提升,让TO B产品经理能够在竞争激烈的市场中脱颖而出,成为企业和商业世界之间的优秀桥梁。
|
网络协议 安全 Linux
Windows电脑如何使用固定TCP公网地址远程连接内网Deepin深度操作系统
Windows电脑如何使用固定TCP公网地址远程连接内网Deepin深度操作系统
241 3
|
网络协议 Java Go
【Go语言专栏】Go语言中的WebSocket实时通信应用
【4月更文挑战第30天】Go语言(Golang)是Google开发的编程语言,适用于云计算、微服务等领域。本文介绍了WebSocket,一种实现浏览器与服务器全双工通信的协议,其特点是实时性、全双工和轻量级。在Go中实现WebSocket,可以使用gorilla/websocket库。示例展示了如何创建服务器端和客户端,实现消息的收发。WebSocket广泛应用于聊天、游戏、通知推送和实时数据同步等场景。学习Go语言中的WebSocket对于开发实时通信应用至关重要。
439 0
|
安全 开发者
《源于支付宝的人脸认证:速度快、体验好、通过率高》
《源于支付宝的人脸认证:速度快、体验好、通过率高》
590 1
|
存储 PyTorch 调度
https://developer.aliyun.com/article/1564927(7)
Transformers 4.37 中文文档(十九)
365 2
|
存储 弹性计算 编解码
阿里云8核32G云服务器多少钱?2024年阿里云8核32G云服务器配置价格及性能评测
2024年阿里云8核32G云服务器的价格为7543.01元一年。该价格基于特定的配置和促销活动,可能因时间、活动政策、地域等因素而有所变动。关于阿里云8核32G云服务器的性能测评,该服务器配备了32GB的内存和8核的CPU,具有出色的计算能力和处理速度,可以轻松应对大型应用、高并发场景和复杂计算任务。同时,服务器提供了多种带宽选择,从1M到5M不等,可以满足不同用户的网络需求。40GB ESSD云盘提供了高速且稳定的存储性能,有助于提升数据读写效率。
1111 0
|
Java Spring
SpringBoot中多Profile使用与切换
SpringBoot中多Profile使用与切换
238 0