内核中如何得到进程描述符的地址

来源:互联网 发布:手机端淘宝链接转化 编辑:程序博客网 时间:2024/05/16 21:18

1.几个重要的结构:
<进程描述符>:struct task_struct 描述一个进程的所有信息的结构,包含众多描述进程属性的字段,以及指向其他与进程相关的结构体的指针

这里写图片描述

从上图可以得知,struct task_struct结构中存在如下重要的字段

thread_info:struct thread_info,线程描述符,里面包含了指向进程描述符的指针mm: struct mm_struct,指向进程虚拟地址空间的结构fs: struct fs,包含进程的当前目录和根目录以及文件创建屏蔽字等信息的结构files: struct files_struct, 打开文件对象描述符结构signal: struct signal_struct, 与信号处理相关的结构

<线程描述符>:struct thread_info 其中包含指向进程描述符的指针,进程描述符地址的获取就是通过先得到thread_info的地址,再通过指针的引用得到task_struct的地址的,即thread_info->task

struct thread_info {    struct task_struct  *task;      /* main task structure */    struct exec_domain  *exec_domain;   /* execution domain */    unsigned long       flags;      /* low level flags */    unsigned long       status;     /* thread-synchronous flags */    __u32           cpu;        /* current CPU */    __s32           preempt_count; /* 0 => preemptable, <0 => BUG */    mm_segment_t        addr_limit;    struct restart_block    restart_block;    unsigned long           previous_esp;    __u8            supervisor_stack[0];};

2.获取struct thread_info结构的地址:

thread_info结构是存放到内核栈中的,一般情况下,内核栈是2页大小,即8k.而且内核栈的第一个页的页框起始地址是2^13的倍数. thread_info结构存放到内核栈的最低的地址处,大概有几十个字节的大小, 而内核栈的使用是从高地址向低地址延伸的.如下图所示:

这里写图片描述

上述情况的实现,在代码中的体现就是把线程描述符thread_info和内核栈的结构体放在一个联合体结构中,这样内核栈和thread_info就共用一个地址区域了

union thread_union {        struct thread_info thread_info;        unsigned long stack[THREAD_SIZE/sizeof(long)];         //内核栈的大小: sizeof(unsigned long)*(THREAD_SIZE/sizeof(long)) 即4×(8192/4) = 8192字节,即8k};

因为线程描述符的起始地址是位于内核栈的最低地址处,那么如果得到了内核栈的最低地址就得到了thread_info结构的地址,也就可以得到进程描述符的地址了

因为内核栈的第一页的起始地址是2^13的倍数,那么把内核栈的栈指针的最后13位屏蔽掉,也就得到了内核栈的最低地址(假设起始地址是2^13,那么内核栈的地址范围是2^13 ~ 2^14 - 1,则屏蔽最后13位后,结果为2^13,即内核栈的起始地址). 内核栈的栈指针保存在esp寄存器中.

static inline struct thread_info *current_thread_info(void){    return (struct thread_info *)        (current_stack_pointer & ~(THREAD_SIZE - 1));}

在上面的代码中,当前的栈指针current_stack_pointer就是esp,
THREAD_SIZE为8K,二进制的表示为0000 0000 0000 0000 0010 0000 0000 0000.

~(THREAD_SIZE-1)的结果刚好为1111 1111 1111 1111 1110 0000 0000 0000,第十三位是全为零,也就是刚好屏蔽了esp的低十三位,最终得到的是thread_info的地址.

内核中经常是通过current宏来得到当前进程描述符的:

    #define get_current()  (current_thread_info()->task)    #define current get_current()

本文引述自:
http://www.360doc.com/content/13/0905/13/7377734_312388669.shtml
http://edsionte.com/techblog/archives/2198

0 0