您的位置:首页 > 其它

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

2015-07-21 17:55 351 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息