在linux 内核中有一宏 : current (获取当前正在运行的进程)
linux 2.4.0
- struct task_struct;
- static inline struct task_struct * get_current(void)
- {
- struct task_struct *current;
- __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
- return current;
- }
- #define current get_current()
- union task_union {
- struct task_struct task;
- unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
- };
对于linux 2.6之前的内核采用的模式是:进程的PCB和进程的系统空间一块分配。对于linux2.4 来讲给进程分配系统空间和PCB用到的结构体是 union task_union .
如图: esp ------------------------------ 高地址
| 系统 |
| 空间 |
| |
| |
| -----------------------------|
| task_struct |
PCB |------------------------------ 低地址
进程的创建是在内核态的,在内核态需要用到栈和PCB ,为了方便管理将PCB和系统空间一块分配了两个连续的页面(8k),其中PCB大约为1K,进程的系统空间大约是7K。但是每次切换到内核态进程的系统栈都是空的。对于 struct task_union 分配空间都是8k的整数倍,因此在每个struct task_union首地址的后13位都是0 。因此一个进程的PCB的地址和该进程的系统的 esp 的地址除低13位都相等-------------->sp 可以移动的范围实在以PCB 为基址的条件下,以8K为跨度的偏移。
因此可以将esp 和 0xffffffe0(地址为32位)的值进行相与,得到struct task_struct 的地址。
因为对于系统的地址范围不缺定,因此内核使用: (~8191UL)
8191------>1 1111 1111 1111 B
linux 2.6.0- struct thread_info {
- struct task_struct *task;
- struct exec_domain *exec_domain;
- __u32 flags;
- __u32 cpu;
- mm_segment_t addr_limit;
- __s32 preempt_count;
- struct restart_block restart_block;
- };
- static inline struct thread_info *current_thread_info(void)
- {
- register unsigned long sp asm ("sp");
- return (struct thread_info *)(sp & ~0x1fff);
- }
- static inline struct task_struct * get_current(void)
- {
- return current_thread_info()->task;
- }
- #define current get_current()
从linux 2.6 开始之后内核代码有了很大的改版,因为进程的PCB中要存储的东西又增加了很多,由于进程的系统空加不能动态变化,因此是的进程的系统空间足够使用,将PCB中的一部分信息进行提取(thread_info)取代2.4内核的PCB,使得系统空间和thread_info 一块分配。
如图: esp ------------------------------ 高地址
| 系统 |
| 空间 |
| |
| |
| -----------------------------|
| thread_info |------------> -------------------------
|------------------------------ 低地址 | PCB |
| |
--------------------------
同2.4内核一样先获得thread_info 的地址。(加粗下划线)然后根据thread_info 的结构体获得进程的pid的struct task_struct 地址。
注:0x1fff = 8191
阅读(1277) | 评论(0) | 转发(0) |