内核中如何得到进程描述符的地址
2015-07-21 17:55
351 查看
1.几个重要的结构:
<进程描述符>:struct task_struct 描述一个进程的所有信息的结构,包含众多描述进程属性的字段,以及指向其他与进程相关的结构体的指针
从上图可以得知,struct task_struct结构中存在如下重要的字段:
<线程描述符>:struct thread_info 其中包含指向进程描述符的指针,进程描述符地址的获取就是通过先得到thread_info的地址,再通过指针的引用得到task_struct的地址的,即thread_info->task
2.获取struct thread_info结构的地址:
thread_info结构是存放到内核栈中的,一般情况下,内核栈是2页大小,即8k.而且内核栈的第一个页的页框起始地址是2^13的倍数. thread_info结构存放到内核栈的最低的地址处,大概有几十个字节的大小, 而内核栈的使用是从高地址向低地址延伸的.如下图所示:
上述情况的实现,在代码中的体现就是把线程描述符thread_info和内核栈的结构体放在一个联合体结构中,这样内核栈和thread_info就共用一个地址区域了
因为线程描述符的起始地址是位于内核栈的最低地址处,那么如果得到了内核栈的最低地址就得到了thread_info结构的地址,也就可以得到进程描述符的地址了
因为内核栈的第一页的起始地址是2^13的倍数,那么把内核栈的栈指针的最后13位屏蔽掉,也就得到了内核栈的最低地址(假设起始地址是2^13,那么内核栈的地址范围是2^13 ~ 2^14 - 1,则屏蔽最后13位后,结果为2^13,即内核栈的起始地址). 内核栈的栈指针保存在esp寄存器中.
在上面的代码中,当前的栈指针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宏来得到当前进程描述符的:
本文引述自:
http://www.360doc.com/content/13/0905/13/7377734_312388669.shtml
http://edsionte.com/techblog/archives/2198
<进程描述符>: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
相关文章推荐
- Linux内核-进程内核栈、用户栈
- Linux报错-bash: fork: retry: Resource temporarily unavailable和进程描述符之间的关系
- task_struct结构描述
- Linux进程描述符task_struct结构体简析
- task_struct(进程描述符)
- task_struct结构体成员详解
- 浅析task_struct结构体
- Linux内核之进程管理
- task_struct结构
- 个人学习笔记---Linux的进程内核栈
- Linux内核栈与用户栈分析
- 内核抢占和schedule()函数的分析
- Linux下进程控制块task_struct结构体注释
- Linux内核分析(六)
- C语言取整方法总结
- 将 Linux on x86 应用程序移植到 Linux on Power 的指南
- Unity常用代码
- R 语言——data types
- 高可用集群之heartbeat安装配置
- 全新升级!超强功能!U糖App 4.0 全面上线!