【linux内核分析与应用-陈莉君】中断程序的下半部分动手实践

目录

 

0.中断程序的下半部分

1.实验程序源码

2.task_init等源码

3.内核源码中驱动如何使用tasklet

4.通过内核开发者给的文档进行内核学习

5.将中断按需求分布到各CPU上


0.中断程序的下半部分

中断的上半部分处理的是紧急事件,下半部分处理不那么紧急的事件.

1.实验程序源码

#include 
#include 
#include 
#include static int irq;
static char * devname;//定义设备名称
module_param(irq,int,0644);// 让我们可以在命令行中传入参数
module_param(devname,charp,0644);// 让我们可以在命令行中传入参数,charp相当于char*,是字符指针// 用在共享irq中
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\n");
}static irqreturn_t myirq_handler(int irq,void* dev)
{static int count = 0;printk("count:%d..\n",count+1);printk("I am myirq_handler\n");printk("The most of the interrupt work will be done by following tasklet\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 succeed ..\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("GLP");
module_init(myirq_init);
module_exit(myirq_exit);

2.task_init等源码

1.tasklet_init
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\kernel\softirq.c
字段的赋值和函数的钩子
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
{t->next = NULL;t->state = 0;atomic_set(&t->count, 0);t->func = func;t->data = data;
}2.tasklet_schedule
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\include\linux\interrupt.h
static inline void tasklet_schedule(struct tasklet_struct *t)
{if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))__tasklet_schedule(t);
}3.__tasklet_schedule
它的调度就是把我们传入的tasklet加入到链表的尾部,调度不等于执行,
对于TASKLET_SOFTIRQ类型的中断,真正的执行是tasklet_action函数进行执行.
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\kernel\softirq.c
void __tasklet_schedule(struct tasklet_struct *t)
{unsigned long flags;local_irq_save(flags);t->next = NULL;*__this_cpu_read(tasklet_vec.tail) = t;__this_cpu_write(tasklet_vec.tail, &(t->next));raise_softirq_irqoff(TASKLET_SOFTIRQ);local_irq_restore(flags);
}
EXPORT_SYMBOL(__tasklet_schedule);4.tasklet_action的函数在
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\kernel\softirq.c中
static __latent_entropy void tasklet_action(struct softirq_action *a)
{struct tasklet_struct *list;local_irq_disable();list = __this_cpu_read(tasklet_vec.head);__this_cpu_write(tasklet_vec.head, NULL);__this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head));local_irq_enable();while (list) // 遍历tasklet链表{struct tasklet_struct *t = list;list = list->next;if (tasklet_trylock(t)) {if (!atomic_read(&t->count)) {if (!test_and_clear_bit(TASKLET_STATE_SCHED,&t->state))BUG();t->func(t->data);// 真正处理中断的函数tasklet_unlock(t);continue;}tasklet_unlock(t);}local_irq_disable();t->next = NULL;*__this_cpu_read(tasklet_vec.tail) = t;__this_cpu_write(tasklet_vec.tail, &(t->next));__raise_softirq_irqoff(TASKLET_SOFTIRQ);local_irq_enable();}
}

3.内核源码中驱动如何使用tasklet

1.D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\net\mac802154\main.c
中的
tasklet_init(&local->tasklet,ieee802154_tasklet_handler,(unsigned long)local);
此处对应的下半部分处理函数是ieee802154_tasklet_handler.2.ieee802154_tasklet_handler的定义D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\net\mac802154\main.c中,
static void ieee802154_tasklet_handler(unsigned long data)
{struct ieee802154_local *local = (struct ieee802154_local *)data;struct sk_buff *skb;while ((skb = skb_dequeue(&local->skb_queue))) {switch (skb->pkt_type) {case IEEE802154_RX_MSG:/* Clear skb->pkt_type in order to not confuse kernel* netstack.*/skb->pkt_type = 0;ieee802154_rx(local, skb);break;default:WARN(1, "mac802154: Packet is of unknown type %d\n",skb->pkt_type);kfree_skb(skb);break;}}
}3.tasklet的调度
ieee802154_tasklet_handler的调度函数在
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\net\mac802154\rx.c中.tasklet_schedule对其进行调度.4.tasklet的注销
在D:\005-代码\001-开源项目源码\004-内核源码\linux4.15.1\linux4.15.1\net\mac802154\main.c中的
tasklet_kill(&local->tasklet);

4.通过内核开发者给的文档进行内核学习

D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\Documentation
这里的文件都是很重要的,我们可以看到很多有意思有帮助的文件.比如说:
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\Documentation\x86\boot.txt
有关于启动的一些说明内存一开始的分配:|			 |
0A0000	+------------------------+|  Reserved for BIOS	 |	Do not use.  Reserved for BIOS EBDA.
09A000	+------------------------+|  Command line		 ||  Stack/heap		 |	For use by the kernel real-mode code.
098000	+------------------------+	|  Kernel setup		 |	The kernel real-mode code.
090200	+------------------------+|  Kernel boot sector	 |	The kernel legacy boot sector.
090000	+------------------------+|  Protected-mode kernel |	The bulk of the kernel image.
010000	+------------------------+|  Boot loader		 |	<- Boot sector entry point 0000:7C00
001000	+------------------------+|  Reserved for MBR/BIOS |
000800	+------------------------+|  Typically used by MBR |
000600	+------------------------+ |  BIOS use only	 |
000000	+------------------------+D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\Documentation\
Changes可以看到编译内核需要的条件(我的这个版本里好像没有)解释什么是IRQ--开发人员解释
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\Documentation\IRQ.txt对IRQ的一些介绍核心接口的一些介绍
D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\Documentation\core-api\genericirq.rst

5.将中断按需求分布到各CPU上

D:\005-代码\001-开源项目源码\004-内核源码\linux-4.15.1\linux-4.15.1\Documentation\IRQ-affinity.txt在centos上
[root@localhost 010_interrupt_tasklet]# ps -ef | grep irqbalance
root       9187      1  0 00:22 ?        00:00:05 /usr/sbin/irqbalance --foreground
root      32078  12510  0 11:30 pts/0    00:00:00 grep --color=auto irqbalance会发现有这个服务,这个服务就是将中断平衡到各个CPU的服务,会对我们的实验测试有所
影响,所以要先把它停了.我的这里这个--foreground啥意思呢?
查了下.
前后台系统 (Foreground/Background System)
这种系统可称为前后台系统或超循环系统(Super-Loops)。应用程序是一个无限的循环,循环中调用相
应的函数完成相应的操作,这部分可以看成后台行为(background)。中断服务程序处理异步事件,这
部分可以看成前台行为(foreground)。后台也可以叫做任务级。前台也叫中断级。时间相关性很强
的关键操作(Critical operation)一定是靠中断服务来保证的。因为中断服务提供的信息一直要等到
后台程序走到该处理这个信息这一步时才能得到处理,这种系统在处理信息的及时性上,比实际可以
做到的要差。这个指标称作任务级响应时间。最坏情况下的任务级响应时间取决于整个循环的执行时
间。因为循环的执行时间不是常数,程序经过某一特定部分的准确时间也是不能确定的。进而,如果
程序修改了,循环的时序也会受到影响。实验课中的哥们用的ubuntu,直接用的
/etc/init.d/irqbalance stop
我这里这个命令不行.我准备用kill -9了cat /proc/interrupts | grep ens160
查看网卡ens60上的中断情况[root@localhost 58]# cat /proc/irq/58/smp_affinity
00000000,00000000,00000000,00000004
[root@localhost 58]# cat /proc/irq/59/smp_affinity
00000000,00000000,00000000,00000040
[root@localhost 58]# cat /proc/irq/60/smp_affinity
00000000,00000000,00000000,00000008
[root@localhost 58]# cat /proc/irq/61/smp_affinity
00000000,00000000,00000000,00000010
[root@localhost 58]# cat /proc/irq/62/smp_affinity
00000000,00000000,00000000,00000020
[root@localhost 58]# cat /proc/irq/63/smp_affinity
00000000,00000000,00000000,00000040
[root@localhost 58]# cat /proc/irq/64/smp_affinity
00000000,00000000,00000000,00000080
[root@localhost 58]# cat /proc/irq/65/smp_affinity
00000000,00000000,00000000,00000010
[root@localhost 58]# cat /proc/irq/66/smp_affinity
00000000,00000000,00000000,00000001


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部