第四十一天:Linux内核栈

   linux3.5内核中为所有进程(包括内核进程和用户进程)分配8k或4k的内核栈(可以在内核编译的时候选择),在模块代码中分配的栈内存就是在内核栈中,写模块代码如果要在堆中分配内存,则要使用kmalloc或vmalloc来分配,这是后话。

  内核栈的栈底存放这thread_info, 通过获取内核栈,以得到thread_info的信息,thread_info里面有一个指向task_struct (进程描述符, 里面放着进程的各种信息)的指针, 通过这个指针, 就可以获取进程的各种信息了。

  技术分享

  先编写获取当前进程名的程序,来更好的了解内核栈。

 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <asm/thread_info.h>
 4 #include <linux/sched.h>
 5 
 6 MODULE_LICENSE("GPL");
 7 MODULE_AUTHOR("BUNFLY");
 8 
 9 int test_init()
10 {
11         int i = 0;
12         struct thread_info *p = NULL;
13         p = (struct thread_info *)((unsigned long)&i & ~0x1fff);
14         struct task_struct *t = p->task;
15         printk("task name is %s\n", t->comm);
16 
17         return 0;
18 }
19 
20 void test_exit()
21 {
22         printk("bye bye\n");
23 }
24 
25 module_init(test_init);
26 module_exit(test_exit);

  编译成模块,在开发板运行结果如下;

 技术分享

  下面来解释下关键代码:

  第十一行;在内核栈上定义一个整型变量i 

   第十二行,定义指向thread_info结构体指针p

   第十三行:根据上图所示 ,已知thread_info结构体在内核栈的栈底,整型变量i在栈上,可以获得i的地址,内核栈的大小是8k。求thread_info结构体的地址。方法就是第十三行代码:将i强制转换成unsigned long 型,再将后面13位置零,再强转为thread_info结构体指针。要理解为什么这样并不难。联想下内存的段页式存储,内存地址中前面为基地址,后面是偏移量,内核栈的大小是8k。说明是以8k大小作为偏移量的。后13位置零就是求出基地址,而thread_info结构体是在栈底的,也就是说,基地址就是thread_info结构体的地址。

  第十四行定义内存描述符task_struct结构体指针t,并保存thread_info结构体中task的地址。

  第十五行输出进程名称。

 系统中所有的进程连成一个双向循环链表,现在我们就通过已经找到进程描述符来输出系统中所有的进程名。  

 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <asm/thread_info.h>
 4 #include <linux/sched.h>
 5 
 6 MODULE_LICENSE("GPL");
 7 MODULE_AUTHOR("BUNFLY");
 8 
 9 int test_init()
10 {
11     //printk("name is %s\n", current->comm);
12     struct thread_info *p = NULL;
13     p = (struct thread_info *)((unsigned long)&p  & ~(8192 - 1));
14     
15     struct task_struct *head = p->task;
16     struct task_struct *tmp = head;
17     do{
18         printk("name is %s\n", tmp->comm);
19         tmp = container_of(tmp->tasks.next, struct task_struct, tasks);
20     }while(tmp != head);
21 
22 
23     return 0;
24 }
25 
26 void test_exit()
27 {
28     printk("bye bye\n");
29 }
30 
31 module_init(test_init);
32 module_exit(test_exit);
技术分享

container_of宏在内核中应用很广,一定要看懂。

  

  

 

  

 

  

   

   

  

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。