百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Linux内核中断顶半部和底半部的理解

toyiye 2024-07-09 22:44 12 浏览 0 评论

@[toc]

中断上半部、下半部的概念

??设备的中断会打断内核进程中的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽量短小精悍。但是,这个良好的愿望往往与现实并不吻合。在大多数真实的系统中,当中断到来时,要完成的工作往往并不会是短小的,它可能要进行较大量的耗时处理。??下图描述了Linux内核的中断处理机制。为了在中断执行时间尽量短和中断处理需完成的工作尽量大之间找到一个平衡点,Linux将中断处理程序分解为两个半部:顶半部和底半部。

??顶半部用于完成尽量少的比较紧急的功能,它往往只是简单地读取寄存器中的中断状态,并在清除中断标志后就进行“登记中断”的工作。“登记中断”意味着将底半部处理程序挂到该设备的底半部执行队列中去。这样,顶半部执行的速度就会很快,从而可以服务更多的中断请求。

??现在,中断处理工作的重心就落在了底半部的头上,需用它来完成中断事件的绝大多数任务。底半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断,这也是底半部和顶半部的最大不同,因为顶半部往往被设计成不可中断。底半部相对来说并不是非常紧急的,而且相对比较耗时,不在硬件中断服务程序中执行。

??尽管顶半部、底半部的结合能够善系统的响应能力,但是,僵化地认为Linux设备驱动中的中断处理一定要分两个半部则是不对的。如果中断要处理的工作本身很少,则完全可以直接在顶半部全部完成

??其他操作系统中对中断的处理也采用了类似于 Linux的方法,真正的硬件中断服务程序都斥尽量短。因此,许多操作系统都提供了中断上下文和非中断上下文相结合的机制,将中断的耗时工作保留到非中断上下文去执行。

实现中断下半部的三种方法

软中断

??软中断( Softirq)也是一种传统的底半部处理机制,它的执行时机通常是顶半部返回的时候, tasklet是基于软中断实现的,因此也运行于软中断上下文。

??在Linux内核中,用 softing_action结构体表征一个软中断,这个结构体包含软中断处理函数指针和传递给该函数的参数。使用 open_softirq()函数可以注册软中断对应的处理函数,而 raise_softirq()函数可以触发一个软中断。

??软中断和 tasklet运行于软中断上下文,仍然属于原子上下文的一种,而工作队列则运行于进程上下文。因此,在软中断和 tasklet处理函数中不允许睡眠,而在工作队列处理函数中允许睡眠

??local_bh_disable()和 llocal_bh_enable()是内核中用于禁止和使能软中断及 tasklet底半部机制的函数

软中断模版

asmlinkage void do_softirq(void)
{
    __u32 pending;
    unsigned long flags;

    /* 判断是否在中断处理中,如果正在中断处理,就直接返回 */
    if (in_interrupt())
        return;

    /* 保存当前寄存器的值 */
    local_irq_save(flags);

    /* 取得当前已注册软中断的位图 */
    pending = local_softirq_pending();

    /* 循环处理所有已注册的软中断 */
    if (pending)
        __do_softirq();

    /* 恢复寄存器的值到中断处理前 */
    local_irq_restore(flags);
}

tasklet

??tasklet的使用较简单,它的执行上下文是软中断,执行时机通常是顶半部返回的时候。我们只需要定义 tasklet及其处理函数,并将两者关联则可,例如

void my_tasklet_func(unsigned long); /*定义一个处理函数*/
DECLARE_TASKLET(my_tasklet, my_tasklet_func, data);
/*定义一个tasklet结构my_tasklet,与my_tasklet_func(data)函数相关联*/

??代码DECLARE_TASKLET(my_tasklet,my_tasklet_func,data)实现了定义名称为my_tasklet的tasklet,并将其与my_tasklet_func()这个函数绑定,而传入这个函数的参数为data。在需要调度tasklet的时候引用一个tasklet_schedule()函数就能使系统在适当的时候进行调度运行:

tasklet_schedule(&my_tasklet);

??使用tasklet作为底半部处理中断的设备驱动程序模板下所示(仅包含与中断相关的部分)。

tasklet函数模版

/* 定义tasklet和底半部函数并将它们关联 */
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);

/* 中断处理底半部 */
void xxx_do_tasklet(unsigned long)

...


/* 中断处理顶半部 */
 irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
 ...
 tasklet_schedule(&xxx_tasklet);
 ...
}

/* 设备驱动模块加载函数 */
 int __init xxx_init(void)
{
 ...
 /* 申请中断 */
 result = request_irq(xxx_irq, xxx_interrupt,
 0, "xxx", NULL);
 ...
 return IRQ_HANDLED;
}

/* 设备驱动模块卸载函数 */
 void __exit xxx_exit(void)
{
 ...
 /* 释放中断 */
 free_irq(xxx_irq, xxx_interrupt);
 ...
}

??上述程序在模块加载函数中申请中断(第24~25行),并在模块卸载函数free_irq(xxx_irq, xxx_interrupt);中释放它。对应于xxx_irq的中断处理程序被设置为xxx_interrupt()函数,在这个函数中,tasklet_schedule(&xxx_tasklet)调度被定义的tasklet函数xxx_do_tasklet()在适当的时候执行。

工作队列

??工作队列的使用方法和tasklet非常相似,但是工作队列的执行上下文是内核线程,因此可以调度和睡眠。下面的代码用于定义一个工作队列和一个底半部执行函数

struct work_struct my_wq; /* 定义一个工作队列 */
void my_wq_func(struct work_struct *work); /* 定义一个处理函数 */

??通过INIT_WORK()可以初始化这个工作队列并将工作队列与处理函数绑定:

INIT_WORK(&my_wq, my_wq_func);
/* 初始化工作队列并将其与处理函数绑定 */

??与tasklet_schedule()对应的用于调度工作队列执行的函数为schedule_work(),如:

schedule_work(&my_wq); /* 调度工作队列执行 */

工作队列函数模版

/* 定义工作队列和关联函数 */
struct work_struct xxx_wq;
void xxx_do_work(struct work_struct *work);

/* 中断处理底半部 */
void xxx_do_work(struct work_struct *work)

...


/*中断处理顶半部*/
 irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
 ...
 schedule_work(&xxx_wq);
 ...
 return IRQ_HANDLED;
}

/* 设备驱动模块加载函数 */
 int xxx_init(void)
{
 ...
 /* 申请中断 */
 result = request_irq(xxx_irq, xxx_interrupt,
 0, "xxx", NULL);
 ...
 /* 初始化工作队列 */
 INIT_WORK(&xxx_wq, xxx_do_work);
 ...
}

/* 设备驱动模块卸载函数 */
 void xxx_exit(void)
{
 ...
 /* 释放中断 */
 free_irq(xxx_irq, xxx_interrupt);
 ...
}

??工作队列早期的实现是在每个CPU核上创建一个worker内核线程,所有在这个核上调度的工作都在该worker线程中执行,其并发性显然差强人意。在Linux 2.6.36以后,转而实现“Concurrency-managedworkqueues”,简称cmwq,cmwq会自动维护工作队列的线程池以提高并发性,同时保持了API的向后兼容。

进程上下文和中断上下文

谈谈进程上下文、中断上下文及原子上下文的一些概念

软中断和硬中断的区别

硬中断:

??1. 硬中断是由硬件产生的,比如,像磁盘,网卡,键盘,时钟等。每个设备或设备集都有它自己的IRQ(中断请求)。基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上(注:硬件驱动通常是内核中的一个子程序,而不是一个独立的进程)。

??2. 处理中断的驱动是需要运行在CPU上的,因此,当中断产生的时候,CPU会中断当前正在运行的任务,来处理中断。在有多核心的系统上,一个中断通常只能中断一颗CPU(也有一种特殊的情况,就是在大型主机上是有硬件通道的,它可以在没有主CPU的支持下,可以同时处理多个中断。)。

??3. 硬中断可以直接中断CPU。它会引起内核中相关的代码被触发。对于那些需要花费一些时间去处理的进程,中断代码本身也可以被其他的硬中断中断。

??4. 对于时钟中断,内核调度代码会将当前正在运行的进程挂起,从而让其他的进程来运行。它的存在是为了让调度代码(或称为调度器)可以调度多任务。

软中断:

??1. 软中断的处理非常像硬中断。然而,它们仅仅是由当前正在运行的进程所产生的。

??2. 通常,软中断是一些对I/O的请求。这些请求会调用内核中可以调度I/O发生的程序。对于某些设备,I/O请求需要被立即处理,而磁盘I/O请求通常可以排队并且可以稍后处理。根据I/O模型的不同,进程或许会被挂起直到I/O完成,此时内核调度器就会选择另一个进程去运行。I/O可以在进程之间产生并且调度过程通常和磁盘I/O的方式是相同。

??3. 软中断仅与内核相联系。而内核主要负责对需要运行的任何其他的进程进行调度。一些内核允许设备驱动的一些部分存在于用户空间,并且当需要的时候内核也会调度这个进程去运行。

??4. 软中断并不会直接中断CPU。也只有当前正在运行的代码(或进程)才会产生软中断。这种中断是一种需要内核为正在运行的进程去做一些事情(通常为I/O)的请求。有一个特殊的软中断是Yield调用,它的作用是请求内核调度器去查看是否有一些其他的进程可以运行。

硬中断、软中断和信号的区别

??硬中断是外部设备对CPU的中断,软中断是中断底半部的一种处理机制,而信号则是由内核(或其他进程)对某个进程的中断。在涉及系统调用的场合,人们也常说通过软中断(例如ARM为swi)陷入内核,此时软中断的概念是指由软件指令引发的中断,和我们这个地方说的softirq是两个完全不同的概念,一个是software,一个是soft。??需要特别说明的是,软中断以及基于软中断的tasklet如果在某段时间内大量出现的话,内核会把后续软中断放入ksoftirqd内核线程中执行。总的来说,中断优先级高于软中断软中断又高于任何一个线程。软中断适度线程化,可以缓解高负载情况下系统的响应。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码