说明:
current宏,是一个全局指针,指向当前进程的struct task_struct结构体,即表示当前进程。
例如current->pid就能得到当前进程的pid,current-comm就能得到当前进程的名称。
每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。
当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;
当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。
在陷入内核后,系统调用中也是存在函数调用和自动变量,这些都需要栈支持。、
当进程因为中断或者系统调用而陷入内核态时,进程所使用的堆栈也要从用户栈转到内核栈。
程序一:urrent宏的使用
创建文件夹/nfsroot/kern/2012-04-16/01/。
创建文件/nfsroot/kern/2012-04-16/01/test.c,内容如下:
说明:要使用current宏,必须声明头文件linux/sched.h。
上面的test_exit()函数的返回值应改为void。
创建文件/nfsroot/kern/2012-04-16/01/Makefile,内容如下:
在主机端编译模块,过程如下:
在开发板端载入和卸载模块,过程如下:
说明:
模块运行的时候,有两种形式:
第一种,代表其他应用程序在运行,称作进程上下文。主要是通过程序调用模块实现的。
第二种,代表中断在运行,称作中断上下文。主要是通过(外部)硬件中断调用模块实现的。
显然,现在此模块是通过程序调用的,属于进程上下文。
可见current宏的使用效果表面,current就表示当前进程。
载入模块的时候,代表insmod程序在运行,所以打印出来的程序名为insmod。
卸载模块的时候,代表rmmod程序在运行,所以打印出来的程序名为rmmod。
程序二:实现自己的current。
参考文档:http://wenku.baidu.com/view/51337c1ab7360b4c2e3f64ce.html
每个进程运行的时候,都会分配8k的内核栈,此内核栈的分配是按8k对齐的,内核栈顶放置一个struct thread_info thread_info的结构体,而thread_info里面有个struct task_struct *task的指针,指向代表当前进程的task_struct。当进程调用模块的时候,模块声明的所有局部变量就会在此进程的内核栈中有一份,所以即使多个进程调用同一个模块,也不会造成混淆。
如果我们要获得当前进程的current宏,只要随便定义个局部变量,然后把其地址按8k对齐(即把低13bit置0),就能得到thread_info的地址,则其task指针即为current!
分析内核代码如何获取current:
current --> get_current() --> current_thread_info() --> sp & ~(THREAD_SIZE - 1),过程如下:
1 static inline struct task_struct *get_current(void) 2 { 3 return current_thread_info()->task; 4 } 5 6 #define current (get_current())
1 static inline struct thread_info *current_thread_info(void) 2 { 3 register unsigned long sp asm ("sp"); 4 return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); 5 }
1 #define THREAD_SIZE 8192 2 #define THREAD_START_SP (THREAD_SIZE - 8)
自己实现current宏:
修改上面的文件/nfsroot/kern/2012-04-16/01/test.c,内容如下:
在主机端重新编译模块,过程如下:
在开发板端,载入和卸载模块,过程如下:
说明:可见mycurrent和current的输出完全一致,表示我们实现的自己的current宏了。
最后说明:
current宏定义在<asm/current.h>,但通过<linux/sched.h>就可以使用current宏。
thread_info结构体和汇编级操作函数定义在<asm/thread_info.h>。
task_struct结构定义在<linux/sched.h>中。