使用软中断也可以实现中断编程。使用Linux底半部机制存在以下两大缺点: 一:在任意时刻,系统中只能有一个CPU可以执行底半部的代码,以防止两个或多个CPU同时来执行底半部代码而相互干扰;因此,底半部代码的执行必须是严格"串行化"的; 二:底半部函数不允许嵌套。 这两个缺点在单CPU系统中是无关紧要的,但是在SMP系统中却是非常致命的。因为,底半部机制的严格串行化执行显然没有充分利用SMP系统的多CPU特点。为此,Linux内核在底半部机制的基础上进行了扩展,那就是所谓的"软中断"(softirq)机制。 Linux的软中断机制是与SMP紧密联系而不可分的。为此,整个软中断机制的设计与实现,自始至终都贯彻了一个思想:“谁触发,谁执行”。也就是说,触发中断的那个CPU负责执行它所触发的软中断,而且,每个CPU都有自己的软中断触发与控制机制。这个设计思想也使得软中断机制充分利用了SMP系统的性能和特点。 软中断运行于中断上下文,它所调用的函数都是内核函数,因此使用软中断机制的驱动不允许编译成模块,只能编译进内核。 使用软中断机制编写驱动程序,实现在串口终端定时打印一条语句。 在kernel/drivers/char/x4412目录下新建驱动程序x4412-softirq.c文件,编辑内容如下: - #include <linux/module.h>
- #include <linux/version.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/jiffies.h>
- #include <linux/delay.h>
- #include <linux/sched.h>
- #include <linux/kthread.h>
- #include <linux/err.h>
- #include <linux/interrupt.h>
- //STEP1:在linux/interrupt.h中自定义软中断索引X4412_SOFTIRQ
- static int flag = 0;
- //STEP2:实现软中断处理函数;
- void x4412_ibox_softirq(struct softirq_action* sa)
- {
- flag = 1;
- printk("%s. \n", __FUNCTION__);
- }
- static int thread_process(void* param)
- {
- while(1)
- {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if(kthread_should_stop())
- {
- printk("kernel thread should stop;file:%s;line:%d\n", __FILE__, __LINE__);
- break;
- }
- mdelay(10*HZ);
- if(0 == flag)
- {
- raise_softirq(X4412_SOFTIRQ); //STEP4:触发软中断;
- }
- else
- {
- flag = 0;
- }
- }
- return 1;
- }
- static struct task_struct* x4412_thread = NULL;
- static int __init x4412_softirq_init(void)
- {
- int err = 0;
- printk("%s\n", __PRETTY_FUNCTION__);
- open_softirq(X4412_SOFTIRQ, x4412_ibox_softirq); //STEP3:注册软中断
- x4412_thread = kthread_create(thread_process, NULL, "x4412_thread");
- if(IS_ERR(x4412_thread))
- {
- err = PTR_ERR(x4412_thread);
- x4412_thread = NULL;
- printk(KERN_ERR "unable to start kernel thread:%d\n", err);
- return err;
- }
- wake_up_process(x4412_thread);
- printk("x4412 kernel thread start;file:%s;line:%d\n", __FILE__, __LINE__);
- return 0;
- }
- static void __exit x4412_softirq_exit(void)
- {
- int ret = -1;
- if(x4412_thread)
- {
- ret = kthread_stop(x4412_thread);
- x4412_thread = NULL;
- }
- printk("kernel thread stop,exit code is %d;file:%s;line:%d\n",ret, __FILE__, __LINE__);
- }
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("www.9tripod.com");
- module_init(x4412_softirq_init);
- module_exit(x4412_softirq_exit);
复制代码 在linux/interrupt.h中添加自定义的中断号: - enum
- {
- HI_SOFTIRQ=0,
- TIMER_SOFTIRQ,
- NET_TX_SOFTIRQ,
- NET_RX_SOFTIRQ,
- BLOCK_SOFTIRQ,
- BLOCK_IOPOLL_SOFTIRQ,
- TASKLET_SOFTIRQ,
- SCHED_SOFTIRQ,
- HRTIMER_SOFTIRQ,
- X4412_SOFTIRQ, /*自定义的中断*/
- RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
-
- NR_SOFTIRQS
- };
复制代码 编辑kernel/drivers/char/x4412/Kconfig文件,添加内容如下: - config X4412_SOFTIRQ_DRIVER
- tristate "x4412 softirq driver"
- default y
- help
- compile for x4412 softirq driver,y for kernel,no for dismod.
复制代码 编辑kernel/drivers/char/x4412/Makefile文件,添加内容如下: - obj-$(CONFIG_X4412_SOFTIRQ_DRIVER) += x4412-softirq.o
复制代码 编译内核,在kernel/drivers/char/x4412目录下将会生成x4412-softirq.o文件,同时它将会被打包到内核映像zImage中。更新开发板的内核,观察系统启动后串口终端的打印信息。 - [root@x4412 ~]#
- [ 23.945014] x4412_ibox_softirq.
- [ 27.940013] x4412_ibox_softirq.
- [ 31.940013] x4412_ibox_softirq.
- [ 35.940013] x4412_ibox_softirq.
复制代码 可见,每隔约4秒将会打印一次信息。 结合源码,可以得出软中断的编程步骤。 第一步:在linux/interrupt.h中添加自定义的中断号: - enum
- {
- HI_SOFTIRQ=0,
- ……
- X4412_SOFTIRQ,
- RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
-
- NR_SOFTIRQS
- };
复制代码 第二步:实现软中断处理函数: - void x4412_ibox_softirq(struct softirq_action* sa)
- {
- ……
- };
复制代码 第三步:在驱动初始化函数或open函数中注册软中断: - open_softirq(X4412_SOFTIRQ, x4412_ibox_softirq);
复制代码 这里第一个参数对应前面我们自定义的软中断号,第二个参数为中断处理函数名。 第四步:触发软中断: - raise_softirq(X4412_SOFTIRQ);
复制代码 同样,形式参数仍然是自定义的软中断号。
编译好的内核映像:
zImage.part1.rar
(1.9 MB, 下载次数: 8)
zImage.part2.rar
(1.75 MB, 下载次数: 8)
|