Linux内核学习笔记 -29 动手实践 - 中断下半部的代码分析与应用

本文介绍了Linux内核中断处理的上下半部概念,重点讲解了tasklet机制的使用,包括tasklet_init、tasklet_schedule和tasklet_kill函数的详细分析。通过实例展示了tasklet在内核驱动中的应用,并探讨了如何通过调整中断亲和性在多CPU系统中优化中断处理。最后,文章提到了系统启动过程、中断管理和性能优化的相关文档资料。
摘要由CSDN通过智能技术生成

Linux将中断处理分为上下两部分,上半部分主要处理紧急的,必须马上处理的事情,下半部分处理不那么紧急的事情,linux内核也提供了相应的机制,这里使用理论课中的tasklet机制来进行实验。

本节代码是在上节的基础上稍微增加一部分代码即可。

首先在中断服务例程,即上半部分中添加tasklet的init函数,即将下半部分函数进行注册。最主要的是要将下半部分处理函数挂载上去。最后调用tasklet_schedule函数进行调度

最后用到tasklet_kill,用来注销掉我们的tasklet

book@100ask:~/Mooc/CH06$ cat interrupt2.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>

static int irq;
static char * devname;

module_param(irq,int,0644);
module_param(devname,charp,0644);

struct myirq
{
        int devid;
};

struct myirq mydev={1119};

static struct tasklet_struct mytasklet;

static void mytasklet_handler(unsigned long data)
{
        printk("I am mytasklet_handler");
}

static irqreturn_t myirq_handler(int irq,void * dev)
{
//      struct myirq mydev;
//      static int count=1;
        static int count=0;
//      mydev = *(struct myirq*)dev;
//      printk("key: %d..\n",count);
//      printk("devid:%d ISR is working..\n",mydev.devid);
//      printk("ISR is leaving......\n");
        printk("count:%d\n",count+1);
        printk("I am myirq_handler\n");
        printk("The most of the interrupt work will be done by folling tasks\n");
        tasklet_init(&mytasklet,mytasklet_handler,0);
        tasklet_schedule(&mytasklet);
        count++;
        return IRQ_HANDLED;
}

static int __init myirq_init(void)
{
        printk("Module is working...\n");
        if(request_irq(irq,myirq_handler,IRQF_SHARED,devname,&mydev)!=0)
        {
                printk("%s request IRQ: %d failed...\n",devname,irq);
                return -1;
        }
        printk("%s request IRQ:%d success...\n",devname,irq);
        return 0;
}

static void __exit myirq_exit(void)
{
        printk("Module is leaving...\n");
        free_irq(irq,&mydev);
        tasklet_kill(&mytasklet);
        printk("Free the irq: %d..\n",irq);
}

MODULE_LICENSE("GPL");
module_init(myirq_init);
module_exit(myirq_exit);
book@100ask:~/Mooc/CH06$ cat Makefile 
# Makefile文件注意:加入前面的.c文件起名为first.c,那么这里的Makefile文件中的.o文件就要起名first.o
# # 只有root用户才能加载和卸载模块
obj-m:=interrupt2.o                                     # 产生first模块的目标文件
# #目标文件   文件       要与模块名字相同
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
#
all:
        make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules     # 编译模块
#       #[TAB]            内核的路径       当前目录编译完放哪里?    表明编译的是内核模块
#
clean:
        make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean     # 清理模块
book@100ask:~/Mooc/CH06$ make
make -C /usr/src/linux-headers-5.4.0-42-generic M=/home/book/Mooc/CH06 modules     # 编译模块
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-42-generic'
  CC [M]  /home/book/Mooc/CH06/interrupt2.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC [M]  /home/book/Mooc/CH06/interrupt2.mod.o
  LD [M]  /home/book/Mooc/CH06/interrupt2.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-42-generic'

插入模块,还是使用1号中断线,

book@100ask:~/Mooc/CH06$ sudo insmod interrupt2.ko irq=1 devname=myirq

查看中断情况,发现设备已被正确插入

book@100ask:~/Mooc/CH06$ cat /proc/interrupts 
            CPU0       CPU1       
   0:         11          0   IO-APIC    2-edge      timer
   1:          0        226   IO-APIC    1-edge      i8042, myirq
   8:          1          0   IO-APIC    8-edge      rtc0
   9:          0          0   IO-APIC    9-fasteoi   acpi
  12:       3945          0   IO-APIC   12-edge      i8042
  14:          0          0   IO-APIC   14-edge      ata_piix
  15:          0          0   IO-APIC   15-edge      ata_piix
  16:       9386       2064   IO-APIC  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值