当前位置:首页>Linux>Linux 中断机制与下半部设计

Linux 中断机制与下半部设计

  • 2026-08-19 02:15:43
Linux 中断机制与下半部设计

Linux 驱动开发中,中断机制是最核心、最基础,也最容易暴露设计问题的部分之一。外设产生中断后,CPU 需要立即暂停当前工作,进入中断处理流程;但中断处理又要求尽可能快,否则会影响系统实时性,甚至造成中断丢失。因此,Linux 将中断处理拆分为“上半部”和“下半部”:上半部快速响应硬件,下半部延后处理复杂逻辑。

围绕这一思想,Linux 提供了多种机制:硬中断处理函数、softirq、tasklet、工作队列、线程化中断等。

文章以 Linux 内核通用驱动模型为基础进行说明,适用于字符设备驱动、平台驱动、GPIO 中断、I2C/SPI 设备中断等常见场景。


一、Linux 中断机制的含义与总体流程

1.1 中断是什么

中断是硬件或软件向 CPU 发出的一种异步事件通知。典型硬件中断来自外设,例如:

  • UART 接收到数据;
  • GPIO 引脚电平变化;
  • 网卡收到报文;
  • 定时器到期;
  • DMA 传输完成;
  • 按键按下或释放。

CPU 收到中断后,会暂停当前正在执行的代码,保存现场,然后跳转到对应的中断处理入口。处理完成后,再恢复原来的执行流程。

在 Linux 中,中断通常用 IRQ 号表示。IRQ 号并不一定直接等于硬件引脚号,而是经过中断控制器、设备树、irqchip 框架映射后的 Linux 虚拟中断号。

一个典型的中断传递路径如下:

外设  |  v中断控制器(GIC / APIC / GPIO irqchip 等)  |  vCPU 中断入口  |  vLinux 中断核心框架  |  virq_desc / irq_chip / irqaction  |  v驱动注册的 ISR

1.2 中断上下文与进程上下文

Linux 内核代码运行在不同上下文中:

  • 进程上下文:运行在内核线程或系统调用中,可以睡眠、可以阻塞、可以访问用户空间;
  • 中断上下文:运行在中断处理路径中,不能睡眠,不能长时间执行,不能调用可能阻塞的函数;
  • 软中断上下文:介于硬中断和进程上下文之间,也不能睡眠。

中断上下文中不允许调用以下类型函数:

  • msleep()
  • schedule()
  • mutex_lock()
  • copy_from_user()
  • copy_to_user()
  • 可能阻塞的内存分配,例如普通 GFP_KERNEL
  • 可能睡眠的等待函数。

中断处理函数必须短小、快速、确定性强。

1.3 上半部与下半部

Linux 将中断处理划分为两个阶段:

+----------------------+|      硬件中断        ||      上半部          ||  快速响应硬件        |+----------------------+           |           v+----------------------+|      下半部          ||  延后处理复杂逻辑    |+----------------------+

上半部通常只做最少量的工作:

  • 读取中断状态寄存器;
  • 判断中断是否属于本设备;
  • 清除中断源;
  • 读取少量关键数据;
  • 调度下半部;
  • 返回。

下半部负责后续复杂处理:

  • 解析数据;
  • 上报输入事件;
  • 网络包处理;
  • 文件写入;
  • 唤醒进程;
  • 启动 DMA;
  • 调用可能睡眠的函数。

常见下半部机制包括:

  • softirq;
  • tasklet;
  • 工作队列;
  • 线程化中断;
  • 软中断相关的 ksoftirqd 内核线程。

二、Linux 中断基本 API 与申请流程

2.1 获取中断号

在平台驱动中,中断号通常来自设备树。常见获取方式:

int irq;irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;

platform_get_irq() 返回 Linux IRQ 号,失败时返回负错误码。

其他获取方式还包括:

int irq = platform_get_irq_byname(pdev, "event");int irq = of_irq_get(np, index);int irq = gpio_to_irq(gpio);

现代驱动更推荐使用 platform_get_irq() 或 platform_get_irq_byname(),而不是直接解析设备树或手动转换 GPIO。

2.2 request_irq 与 devm_request_irq

注册中断处理函数最经典的 API 是:

int request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev_id);

资源管理版本为:

int devm_request_irq(struct device *dev,unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev_id);

devm_request_irq() 会在设备生命周期结束时自动释放中断,适合大多数平台驱动。

中断处理函数原型为:

typedef irqreturn_t (*irq_handler_t)(int irq, void *dev_id);

返回值类型为:

irqreturn_t

常见返回值:

返回值
含义
IRQ_NONE
当前中断不是本设备产生,常见于共享中断
IRQ_HANDLED
中断已处理
IRQ_WAKE_THREAD
请求唤醒线程化中断处理线程

2.3 flags 参数

常见 flags:

flags
说明
IRQF_SHARED
允许多个设备共享同一个中断号
IRQF_TRIGGER_RISING
上升沿触发
IRQF_TRIGGER_FALLING
下降沿触发
IRQF_TRIGGER_HIGH
高电平触发
IRQF_TRIGGER_LOW
低电平触发
IRQF_ONESHOT
线程化中断执行期间保持中断关闭
IRQF_NO_SUSPEND
系统挂起期间不关闭该中断

触发方式通常由设备树或硬件平台决定,驱动中不建议随意硬编码,除非明确硬件要求。

2.4 name 与 dev_id

name 通常用于 /proc/interrupts 中显示:

cat /proc/interrupts

dev_id 在共享中断中非常关键。共享中断下,多个设备可能注册同一个 IRQ,内核需要依靠 dev_id 区分不同设备。

释放共享中断时,必须传入与注册时相同的 dev_id

free_irq(irq, dev_id);

因此,dev_id 通常传入设备私有结构体指针。

2.5 中断申请基本流程

一个标准中断申请流程如下:

1. 获取 IRQ 号2. 初始化设备私有数据3. 编写中断处理函数4. 调用 request_irq / devm_request_irq5. 注册成功后等待硬件中断6. 驱动卸载时释放中断

示例:

#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/slab.h>struct demo_dev {struct device *dev;int irq;};static irqreturn_t demo_isr(int irq, void *dev_id){struct demo_dev *dev = dev_id;/*     * 实际驱动中需要读取硬件状态寄存器,     * 判断中断是否由本设备产生。     */if (!device_has_pending_event(dev))return IRQ_NONE;/* 清除中断源 */    ack_device_event(dev);/* 调度下半部 */return IRQ_HANDLED;}static int demo_probe(struct platform_device *pdev){struct demo_dev *dev;int irq;int ret;    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);if (!dev)return -ENOMEM;    irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;    dev->dev = &pdev->dev;    dev->irq = irq;    ret = devm_request_irq(&pdev->dev, irq, demo_isr,                           IRQF_SHARED, "demo_irq", dev);if (ret)return ret;    platform_set_drvdata(pdev, dev);return 0;}

2.6 共享中断注意事项

共享中断下,中断处理函数必须能够判断中断是否来自本设备。如果无法判断,就可能出现以下问题:

  • 其他设备的中断被误认为已处理;
  • 本设备中断被忽略;
  • 系统出现中断风暴;
  • 内核统计大量 IRQ_NONE

共享中断处理函数的一般写法:

static irqreturn_t demo_isr(int irq, void *dev_id){struct demo_dev *dev = dev_id;if (!is_my_device_interrupt(dev))return IRQ_NONE;    clear_my_device_interrupt(dev);return IRQ_HANDLED;}

2.7 中断释放

非 devm 方式注册的中断需要手动释放:

free_irq(dev->irq, dev);

如果使用 devm_request_irq(),通常不需要显式调用 free_irq()。但需要注意:如果驱动中还使用了 tasklet、工作队列、定时器等机制,应在 remove 函数中先停止这些异步任务,避免访问已释放资源。

例如:

static int demo_remove(struct platform_device *pdev){struct demo_dev *dev = platform_get_drvdata(pdev);    tasklet_kill(&dev->rx_tasklet);    cancel_work_sync(&dev->work);return 0;}

2.8 线程化中断

除了传统下半部机制,Linux 还支持线程化中断。线程化中断将复杂处理放到内核线程中执行,可以睡眠。

注册接口:

int request_threaded_irq(unsigned int irq,irq_handler_t handler,irq_handler_t thread_fn,unsigned long irqflags,const char *devname,void *dev_id);

devm 版本:

int devm_request_threaded_irq(struct device *dev,unsigned int irq,irq_handler_t handler,irq_handler_t thread_fn,unsigned long irqflags,const char *devname,void *dev_id);

示例:

static irqreturn_t demo_isr(int irq, void *dev_id){struct demo_dev *dev = dev_id;if (!device_has_pending_event(dev))return IRQ_NONE;    ack_device_event(dev);return IRQ_WAKE_THREAD;}static irqreturn_t demo_thread_fn(int irq, void *dev_id){struct demo_dev *dev = dev_id;/*     * 这里运行在进程上下文中,     * 可以睡眠、可以加 mutex、可以分配 GFP_KERNEL 内存。     */return IRQ_HANDLED;}static int demo_probe(struct platform_device *pdev){struct demo_dev *dev;int irq;int ret;    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);if (!dev)return -ENOMEM;    irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;    dev->irq = irq;    ret = devm_request_threaded_irq(&pdev->dev, irq,                                    demo_isr,                                    demo_thread_fn,                                    IRQF_SHARED | IRQF_ONESHOT,"demo_irq",                                    dev);if (ret)return ret;    platform_set_drvdata(pdev, dev);return 0;}

线程化中断非常适合 I2C、SPI 等总线设备,因为这些设备的中断后续处理往往需要访问寄存器,而寄存器访问可能睡眠。


三、下半部机制之一:tasklet

3.1 tasklet 的基本含义

tasklet 是 Linux 中一种基于 softirq 的延迟处理机制。它运行在软中断上下文,不能睡眠,但比工作队列更轻量,延迟更低。

tasklet 的特点:

  • 运行在软中断上下文;
  • 不能睡眠;
  • 适合短小、快速、不需要阻塞的处理;
  • 同一个 tasklet 实例不会并发执行;
  • 不同 tasklet 实例可以在不同 CPU 上并发执行;
  • 可以在硬中断处理函数中调度。

tasklet 本质上属于 softirq 的一种,对应:

TASKLET_SOFTIRQ

因此,在 /proc/softirqs 中可以看到 TASKLET 相关计数。

3.2 tasklet 常用 API

较新的内核推荐使用:

void tasklet_setup(struct tasklet_struct *t,void (*callback)(struct tasklet_struct *));void tasklet_schedule(struct tasklet_struct *t);void tasklet_hi_schedule(struct tasklet_struct *t);void tasklet_kill(struct tasklet_struct *t);

旧内核中常见:

DECLARE_TASKLET(name, func, data);tasklet_init(&tasklet, func, data);

新接口中,tasklet 回调函数参数为:

struct tasklet_struct *

驱动通常使用 container_of() 获取私有数据。

3.3 tasklet 示例

下面给出一个完整结构示例。

#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/slab.h>struct demo_dev {struct device *dev;int irq;struct tasklet_struct rx_tasklet;int event_count;};static void demo_tasklet_fn(struct tasklet_struct *t){struct demo_dev *dev = container_of(t, struct demo_dev, rx_tasklet);/*     * tasklet 运行在软中断上下文,     * 不能睡眠,不能调用 mutex_lock、msleep 等函数。     */    dev->event_count++;/* 做少量快速处理 */}static irqreturn_t demo_isr(int irq, void *dev_id){struct demo_dev *dev = dev_id;if (!device_has_pending_event(dev))return IRQ_NONE;    ack_device_event(dev);/* 调度 tasklet 下半部 */    tasklet_schedule(&dev->rx_tasklet);return IRQ_HANDLED;}static int demo_probe(struct platform_device *pdev){struct demo_dev *dev;int irq;int ret;    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);if (!dev)return -ENOMEM;    irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;    dev->dev = &pdev->dev;    dev->irq = irq;    tasklet_setup(&dev->rx_tasklet, demo_tasklet_fn);    ret = devm_request_irq(&pdev->dev, irq, demo_isr,                           IRQF_SHARED, "demo_irq", dev);if (ret)return ret;    platform_set_drvdata(pdev, dev);return 0;}static int demo_remove(struct platform_device *pdev){struct demo_dev *dev = platform_get_drvdata(pdev);/*     * 确保 tasklet 不再运行,     * 防止释放设备结构后 tasklet 仍访问内存。     */    tasklet_kill(&dev->rx_tasklet);return 0;}

3.4 tasklet 使用注意事项

tasklet 虽然使用简单,但有几个限制必须注意:

  1. 不能睡眠;
  2. 不能访问用户空间;
  3. 不能调用可能阻塞的函数;
  4. 不适合长时间运行;
  5. 共享数据需要使用自旋锁保护;
  6. 驱动卸载前必须调用 tasklet_kill() 确保 tasklet 停止。

如果 tasklet 中需要访问进程上下文和软中断上下文共享的数据,通常使用:

spin_lock_bh(&lock);...spin_unlock_bh(&lock);

如果数据还会被硬中断访问,则应使用:

unsigned long flags;spin_lock_irqsave(&lock, flags);...spin_unlock_irqrestore(&lock, flags);

四、下半部机制之二:softirq

4.1 softirq 的基本含义

softirq 是 Linux 内核中更底层的软中断机制。tasklet 就是建立在 softirq 之上的封装。

softirq 的特点:

  • 静态定义,数量有限;
  • 不能动态创建新类型;
  • 运行在软中断上下文;
  • 不能睡眠;
  • 可以在多个 CPU 上并发执行;
  • 性能高,延迟低;
  • 通常用于内核核心子系统,不建议普通驱动随意使用。

内核中常见的 softirq 类型包括:

HI_SOFTIRQTIMER_SOFTIRQNET_TX_SOFTIRQNET_RX_SOFTIRQBLOCK_SOFTIRQIRQ_POLL_SOFTIRQTASKLET_SOFTIRQSCHED_SOFTIRQHRTIMER_SOFTIRQRCU_SOFTIRQ

可以通过以下命令查看 softirq 统计:

cat /proc/softirqs

4.2 softirq 的执行时机

softirq 通常在以下时机执行:

  1. 硬中断返回前;
  2. local_bh_enable() 被调用时;
  3. ksoftirqd 内核线程中。

当 softirq 数量过多或持续触发时,内核会交给 ksoftirqd 线程处理,避免长时间占用 CPU 导致用户态任务饿死。

4.3 softirq 常用 API

softirq 相关 API 包括:

void open_softirq(int nr, void (*action)(struct softirq_action *));void raise_softirq(unsigned int nr);

查看 softirq 状态:

cat /proc/softirqs

禁止/恢复软中断执行:

local_bh_disable();local_bh_enable();

需要注意:local_bh_disable() 并不会禁止硬中断,它只是推迟当前 CPU 上的 softirq/tasklet 执行。

4.4 softirq 示例

softirq 的编号是静态分配的,主线内核中常见 softirq 编号基本已被核心子系统使用。普通驱动通常不应该随意注册或替换 softirq。

下面给出一个原理性示例,用于说明 softirq 的注册和触发方式。实际产品中,除非内核中确实存在空闲 softirq 编号,或者经过内核源码修改,否则不应这样使用。

#include <linux/interrupt.h>#include <linux/module.h>#include <linux/atomic.h>static atomic_t demo_softirq_count = ATOMIC_INIT(0);/* * DEMO_SOFTIRQ 为示意编号。 * 主线内核 softirq 编号静态定义, * 普通模块通常不应占用已有 softirq。 */static void demo_softirq_fn(struct softirq_action *h){atomic_inc(&demo_softirq_count);}static int __init demo_softirq_init(void){    open_softirq(DEMO_SOFTIRQ, demo_softirq_fn);return 0;}static void demo_trigger_softirq(void){    raise_softirq(DEMO_SOFTIRQ);}module_init(demo_softirq_init);

更现实的 softirq 使用方式是观察内核已有 softirq:

watch -n 1 cat /proc/softirqs

例如网络收发包、块设备、定时器、tasklet 等都会体现在 softirq 统计中。

4.5 softirq 的并发模型

softirq 的并发模型比 tasklet 更复杂。

同一个 softirq 可以在多个 CPU 上同时执行:

CPU0: NET_RX_SOFTIRQ runningCPU1: NET_RX_SOFTIRQ runningCPU2: NET_RX_SOFTIRQ running

因此,softirq 处理函数必须可重入,必须自行处理并发保护。

常见保护方式:

static DEFINE_SPINLOCK(demo_lock);static void demo_softirq_fn(struct softirq_action *h){unsigned long flags;    spin_lock_irqsave(&demo_lock, flags);/* 访问共享数据 */    spin_unlock_irqrestore(&demo_lock, flags);}

4.6 softirq 使用注意事项

softirq 适合内核核心路径,不适合普通外设驱动。原因包括:

  1. softirq 编号静态固定;
  2. 不能动态扩展;
  3. 并发模型复杂;
  4. 调试难度较高;
  5. 容易影响系统整体延迟;
  6. 普通驱动很难比 tasklet 或工作队列获得明显收益。

因此,驱动开发中如果需要 softirq 级别的延迟,通常优先考虑 tasklet;如果需要睡眠,则选择工作队列或线程化中断。


五、下半部机制之三:工作队列

5.1 工作队列的基本含义

工作队列将任务交给内核工作线程执行。工作线程运行在进程上下文中,因此工作队列可以睡眠、可以阻塞、可以调用可能睡眠的函数。

工作队列特点:

  • 运行在进程上下文;
  • 可以睡眠;
  • 可以调用 mutex_lock()
  • 可以使用 GFP_KERNEL 分配内存;
  • 可以访问用户空间,但通常需要合理场景;
  • 延迟比 softirq/tasklet 高;
  • 适合复杂、耗时、可能阻塞的任务。

常见内核工作线程名称:

ps -ef | grep kworker

例如:

kworker/0:1kworker/1:2kworker/u8:3

5.2 工作队列常用 API

基本 API:

INIT_WORK(work, func);schedule_work(work);queue_work(wq, work);flush_work(work);cancel_work_sync(work);

延迟工作:

INIT_DELAYED_WORK(dwork, func);schedule_delayed_work(dwork, delay);queue_delayed_work(wq, dwork, delay);cancel_delayed_work_sync(dwork);

创建工作队列:

struct workqueue_struct *alloc_workqueue(const char *fmt,unsigned int flags,int max_active, ...);

常用系统默认工作队列:

system_wqsystem_long_wqsystem_unbound_wq

普通驱动简单任务可以直接使用:

schedule_work(&dev->work);

5.3 工作队列示例

#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/slab.h>#include <linux/workqueue.h>struct demo_dev {struct device *dev;int irq;struct work_struct work;int event_count;};static void demo_work_fn(struct work_struct *work){struct demo_dev *dev = container_of(work, struct demo_dev, work);/*     * 工作队列运行在进程上下文,     * 可以睡眠,可以加 mutex,     * 可以使用 GFP_KERNEL 分配内存。     */    dev->event_count++;    msleep(10);    mutex_lock(&some_mutex);/* 复杂处理 */    mutex_unlock(&some_mutex);}static irqreturn_t demo_isr(int irq, void *dev_id){struct demo_dev *dev = dev_id;if (!device_has_pending_event(dev))return IRQ_NONE;    ack_device_event(dev);/* 调度工作队列下半部 */    schedule_work(&dev->work);return IRQ_HANDLED;}static int demo_probe(struct platform_device *pdev){struct demo_dev *dev;int irq;int ret;    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);if (!dev)return -ENOMEM;    irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;    dev->dev = &pdev->dev;    dev->irq = irq;    INIT_WORK(&dev->work, demo_work_fn);    ret = devm_request_irq(&pdev->dev, irq, demo_isr,                           IRQF_SHARED, "demo_irq", dev);if (ret)return ret;    platform_set_drvdata(pdev, dev);return 0;}static int demo_remove(struct platform_device *pdev){struct demo_dev *dev = platform_get_drvdata(pdev);/*     * 等待工作队列任务结束,     * 防止 remove 后工作函数继续访问 dev。     */    cancel_work_sync(&dev->work);return 0;}

5.4 延迟工作示例

struct demo_dev {struct delayed_work dwork;};static void demo_delayed_work_fn(struct work_struct *work){struct delayed_work *dwork = to_delayed_work(work);struct demo_dev *dev = container_of(dwork, struct demo_dev, dwork);/* 延迟任务处理 */}static void demo_start_delayed(struct demo_dev *dev){    schedule_delayed_work(&dev->dwork, msecs_to_jiffies(100));}

初始化:

INIT_DELAYED_WORK(&dev->dwork, demo_delayed_work_fn);

取消:

cancel_delayed_work_sync(&dev->dwork);

5.5 工作队列使用注意事项

工作队列虽然灵活,但也需要注意:

  1. 同一个 work_struct 不应在未取消时重复修改;
  2. queue_work() 如果任务已经 pending,会返回 false;
  3. flush_work() 只等待完成,不会取消任务;
  4. cancel_work_sync() 可能睡眠,不能在中断上下文调用;
  5. 工作函数可以睡眠,但不应无限阻塞;
  6. 驱动卸载前必须取消或 flush 工作队列任务;
  7. 高优先级任务可考虑专用工作队列或 WQ_HIGHPRI

六、tasklet、softirq、工作队列的区别

6.1 三者关系

三者关系可以这样理解:

softirq  |  +-- tasklet 是 softirq 的一种封装  |workqueue  |  +-- 独立于 softirq,运行在内核线程中

tasklet 基于 softirq,但比 softirq 更易用。工作队列则完全运行在进程上下文中。

6.2 核心区别表

维度
softirq
tasklet
工作队列
运行上下文
软中断上下文
软中断上下文
进程上下文
是否可睡眠
是否可动态创建
否,静态编号
是,可动态初始化
是,可动态创建 work
并发模型
同一 softirq 可在多 CPU 并发
同一 tasklet 实例不并发
由工作队列配置决定
延迟
很低
相对较高
编程复杂度
是否适合普通驱动
通常不适合
适合短小快速任务
适合复杂可阻塞任务
典型场景
网络、块设备、定时器核心路径
驱动简单下半部
需要睡眠、I/O、复杂处理
常用 API
open_softirq()
raise_softirq()
tasklet_setup()
tasklet_schedule()
INIT_WORK()
schedule_work()

6.3 运行上下文差异

softirq 和 tasklet 都运行在软中断上下文:

硬中断返回    |    v检查 pending softirq    |    v执行 softirq / tasklet

工作队列不同:

硬中断中调用 schedule_work()    |    v唤醒 kworker 内核线程    |    v进程上下文执行 work 函数

因此,工作队列可以调用:

msleep(10);mutex_lock(&lock);kmalloc(size, GFP_KERNEL);

而 softirq/tasklet 中不能这样做。

6.4 并发差异

softirq 并发最强:

CPU0: softirq handler runningCPU1: softirq handler runningCPU2: softirq handler running

tasklet 对单个实例更友好:

同一个 tasklet 实例不会同时执行两次

但不同 tasklet 实例仍可能并发:

tasklet A on CPU0tasklet B on CPU1

工作队列并发取决于工作队列类型和配置:

bound workqueue:通常绑定 CPUunbound workqueue:不绑定 CPUmax_active:控制并发数量

6.5 选型建议

实际驱动开发中,可以按以下原则选择:

  1. 中断处理必须极快,只做确认和清中断;
  2. 如果后续处理很短且不能睡眠,选择 tasklet;
  3. 如果后续处理需要睡眠、加 mutex、访问 I2C/SPI 寄存器,选择工作队列或线程化中断;
  4. 如果是网络、块设备等核心高性能路径,且具备充分理由,才考虑 softirq;
  5. 普通外设驱动不建议直接注册 softirq;
  6. 新驱动设计中,线程化中断和工作队列往往比 tasklet 更易维护。

七、一个综合示例:中断 + tasklet + 工作队列

下面示例展示一个驱动同时使用 tasklet 和工作队列的设计思路。

#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/slab.h>#include <linux/workqueue.h>struct demo_dev {struct device *dev;int irq;struct tasklet_struct fast_tasklet;struct work_struct slow_work;int fast_events;int slow_events;};static void demo_tasklet_fn(struct tasklet_struct *t){struct demo_dev *dev = container_of(t, struct demo_dev, fast_tasklet);    dev->fast_events++;/*     * 快速处理少量数据。     * 如果后续需要复杂处理,可以再调度工作队列。     */    schedule_work(&dev->slow_work);}static void demo_work_fn(struct work_struct *work){struct demo_dev *dev = container_of(work, struct demo_dev, slow_work);    dev->slow_events++;/*     * 进程上下文中可以做复杂处理:     * - 睡眠     * - 加 mutex     - - GFP_KERNEL 分配     * - 访问 I2C/SPI 设备     */}static irqreturn_t demo_isr(int irq, void *dev_id){struct demo_dev *dev = dev_id;if (!device_has_pending_event(dev))return IRQ_NONE;    ack_device_event(dev);    tasklet_schedule(&dev->fast_tasklet);return IRQ_HANDLED;}static int demo_probe(struct platform_device *pdev){struct demo_dev *dev;int irq;int ret;    dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);if (!dev)return -ENOMEM;    irq = platform_get_irq(pdev, 0);if (irq < 0)return irq;    dev->dev = &pdev->dev;    dev->irq = irq;    tasklet_setup(&dev->fast_tasklet, demo_tasklet_fn);    INIT_WORK(&dev->slow_work, demo_work_fn);    ret = devm_request_irq(&pdev->dev, irq, demo_isr,                           IRQF_SHARED, "demo_irq", dev);if (ret)return ret;    platform_set_drvdata(pdev, dev);return 0;}static int demo_remove(struct platform_device *pdev){struct demo_dev *dev = platform_get_drvdata(pdev);    tasklet_kill(&dev->fast_tasklet);    cancel_work_sync(&dev->slow_work);return 0;}

该结构适合以下场景:

  • 硬中断中快速清中断;
  • tasklet 中做低延迟简单处理;
  • 工作队列中做耗时或可睡眠处理。

八、调试与观测方法

8.1 查看中断统计

cat /proc/interrupts

输出示例:

           CPU0       CPU1  29:      12345          0     GICv3  29 Level     timer  33:        100          0     GICv3  33 Level     demo_irq

可以观察:

  • 中断是否触发;
  • 中断是否集中在某个 CPU;
  • 是否存在中断风暴;
  • 共享中断是否有多个设备注册。

8.2 查看 softirq 统计

cat /proc/softirqs

可以观察:

  • NET_RX;
  • NET_TX;
  • TIMER;
  • SCHED;
  • TASKLET;
  • RCU。

如果 TASKLET 计数持续增长,说明 tasklet 被频繁调度。

8.3 查看工作线程

ps -ef | grep kworker

可以观察工作队列线程是否活跃。

8.4 常见问题

常见问题包括:

  1. 中断没有触发;
  2. IRQ 号错误;
  3. 设备树 interrupts 属性配置错误;
  4. 中断触发方式错误;
  5. 共享中断未正确返回 IRQ_NONE
  6. 中断源未清除;
  7. tasklet 或工作队列访问已释放资源;
  8. 在中断上下文中调用睡眠函数;
  9. 锁使用错误导致死锁;
  10. 下半部处理时间过长导致系统卡顿。

Linux 中断机制的核心目标是快速响应硬件事件,同时避免长时间占用 CPU。为此,内核将中断处理拆分为上半部和下半部。上半部运行在硬中断上下文,必须短小快速;下半部用于延后处理复杂逻辑。

本文梳理了中断机制的关键内容:

  1. 中断是硬件事件通知机制,Linux 通过 IRQ 号、中断控制器、irq_desc 和驱动 ISR 完成中断响应;
  2. request_irq()devm_request_irq()request_threaded_irq() 是注册中断的核心 API;
  3. 中断申请流程包括获取 IRQ、编写 ISR、注册中断、释放中断;
  4. tasklet 是基于 softirq 的轻量下半部机制,运行在软中断上下文,不能睡眠,适合短小快速任务;
  5. softirq 是更底层的软中断机制,静态编号、并发能力强,主要用于内核核心子系统,普通驱动不建议直接使用;
  6. 工作队列运行在进程上下文,可以睡眠,适合复杂、耗时、可能阻塞的任务;
  7. 三者选型关键看是否需要睡眠、延迟要求、并发模型和处理复杂度。

实际驱动开发中,推荐遵循以下原则:

硬中断中只做最少工作;短小不可睡眠的延迟任务用 tasklet;需要睡眠或复杂处理用工作队列或线程化中断;softirq 仅在内核核心高性能路径中谨慎使用。

掌握这些机制,有助于设计出既稳定又高效的 Linux 驱动,也能在调试中断丢失、系统卡顿、死锁、资源释放异常等问题时快速定位根因。

阅读其他文章

Linux 内核互斥技术
读写锁和RCU
OpenWrt的动态库与静态库

OpenWrt 补丁(Patch)机制详解

OpenWrt 启动过程深度解析

LuCI的Web UI开发实践

丢包?连接失败?如何对嵌入式Linux做网络诊断

内网穿透 -- 公网访问OpenWRT

OpenWrt的Makefile构建体系

ESP32解析GPS 定位数据

WSL:Windows下的Linux开发利器

OpenWrt 启动过程深度解析

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-21 13:34:57 HTTP/2.0 GET : https://f.mffb.com.cn/a/510635.html
  2. 运行时间 : 0.459393s [ 吞吐率:2.18req/s ] 内存消耗:4,741.40kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=fec2afd658991193f0edabc4962ead0e
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000986s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001420s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.001622s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.068630s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001341s ]
  6. SELECT * FROM `set` [ RunTime:0.018953s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001688s ]
  8. SELECT * FROM `article` WHERE `id` = 510635 LIMIT 1 [ RunTime:0.006317s ]
  9. UPDATE `article` SET `lasttime` = 1787290497 WHERE `id` = 510635 [ RunTime:0.025767s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.008118s ]
  11. SELECT * FROM `article` WHERE `id` < 510635 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.094967s ]
  12. SELECT * FROM `article` WHERE `id` > 510635 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001178s ]
  13. SELECT * FROM `article` WHERE `id` < 510635 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.058107s ]
  14. SELECT * FROM `article` WHERE `id` < 510635 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001739s ]
  15. SELECT * FROM `article` WHERE `id` < 510635 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.006485s ]
0.462895s