Linux内核设计与实现--学习笔记--第三章- 1(task_struct等)
来源:互联网 发布:相思相见知何日 编辑:程序博客网 时间:2024/05/01 03:04
1,Linux系统的线程非常特别,他对线程与进程并不特别区分。对Linux而言,线程是一种特殊的进程。
2,在Linux系统中,调用fork()创建进程,该系统调用通过复制一个现有进程来创建一个全新的进程,调用fork()的进程称为父进程,新生的进程称为子进程,在调用结束时,在返回点这个位置上,父进程恢复执行,子进程开始执行,fork()系统调用从内核返回两次:一次回到父进程,一次回到新生的子进程。
3,在OSE系统(ENEA公司出品,该公司成立于1968年,总部位于瑞典斯得哥尔摩,与爱立信共同成长)中,PCB与进程栈在内存中是相邻的,PCB在低地址处,进程栈(从高向低地址增长)在紧接着PCB的高地址存放(PCB+栈:在systemPool中分配)。而在Linux系统中并不直接存储PCB,取代PCB的是一个小的结构体:struct thread_info, 这个结构中并没有直接包含与进程相关的字段,而是通过task字段指向具体某个进程描述符(struct task_struct),这是因为现在用slab分配器动态生成task_struct(通过预先分配或重复使用task_struct,优点是进程创建迅速),所以只需在栈定(栈的低地址处)创建一个struct thread_info结构体,并指向task_struct。通过下图可知内核的栈(真正的栈)顶指针存储在esp寄存器中。
\include\asm-x86_64:struct thread_info {struct task_struct*task;/* main task structure */struct exec_domain*exec_domain;/* execution domain */__u32flags;/* low level flags */__u32status;/* thread synchronous flags */__u32cpu;/* current CPU */int preempt_count;mm_segment_taddr_limit;struct restart_block restart_block;};
<em><span style="font-family:FangSong_GB2312;font-size:14px;">/** * 内核栈与thread_info 是个联合体, 在\include\linux\sched.h中定义 */union thread_union {struct thread_info thread_info;unsigned long stack[THREAD_SIZE/sizeof(long)];};</span></em>
如在i386处理器中:
#ifdef CONFIG_4KSTACKS
#define THREAD_SIZE (4096)
#else
#define THREAD_SIZE (8192)
#endif
即内核stack数组大小为2048,如果THREAD_SIZE = 8192。
由于thread_union是联合体,我们可知stack[0]的地址与thread_info地址相同,也就是说每个thread的thread_info保存在进程内核栈的最低端(这与OSE系统不一样,OSE系统的PCB与栈是分开的,PCB并不占用栈的空间)
4,内核访问进程需要获取进程的task_struct,通过current宏可以得到当前正在运行的进程的进程描述符,硬件体系结构不同,该宏的实现也不同,有的硬件体系结构可以用专门的寄存器存放指向task_struct的指针,但像x86,其寄存器并不富裕,只能通过栈尾端的thread_info结构,计算偏移得到task_struct。对于i386(32位 x86)的current_thread_info定义如下:
<span style="font-size:14px;"><em>\include\asm-i386\thread_info.hstatic inline struct thread_info *current_thread_info(void){struct thread_info *ti;__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~(THREAD_SIZE - 1)));return ti;}</em></span>
上述代码,如果THREAD_SIZE=8192,则~(THREAD_SIZE - 1)=0xE000,即低13位为0,这样esp寄存器的LSB 13bit被清零,得到了内核堆栈thread_info结构的地址。
current_thread_info()->task就得到了进程task_struct。
通过current宏可以直接得到task_struck:
<span style="font-size:14px;">#ifndef _I386_CURRENT_H \include\asm-i386#define _I386_CURRENT_H#include <linux/thread_info.h>struct task_struct;static inline struct task_struct * get_current(void){return current_thread_info()->task;} #define current get_current()#endif /* !(_I386_CURRENT_H) */</span><span style="font-size: 18px;"></span>
5,OSE系统怎么得到current_process?
<span style="font-size:14px;">PROCESS current_process(void){ D_DIV( debug_printf("current_process *\n"); ); return odo_sys.current->pid;}</span>对于多核处理器系统,OSE在每个CPU都维护一个结构:odo_sys,odo_sys.current就是当前正在运行进程的PCB。
- Linux内核设计与实现--学习笔记--第三章- 1(task_struct等)
- Linux内核设计与实现--学习笔记--第三章- 2(init进程)
- Linux内核设计与实现--学习笔记--第三章- 3(fork,vfork,clone)
- 《linux内核设计与实现》阅读笔记 第三章 调度
- linux内核设计与实现 第三章笔记
- [笔记]《Linux内核设计与实现》第三章进程管理
- linux内核设计与实现第三章
- Linux内核设计与实现学习笔记
- Linux进程 (Linux内核设计与实现学习笔记)
- Linux进程(Linux内核设计与实现学习笔记)
- linux内核设计与实现(第三章)----进程管理
- Linux内核设计与实现--学习笔记--第二章
- Linux内核设计与实现 学习笔记(一)
- 《Linux内核设计与实现》学习笔记(01)
- Linux内核设计与实现 学习笔记(8)内核调试
- 《linux内核设计与实现-笔记1》
- linux内核设计与实现笔记之第三章进程管理
- 《Linux 内核设计与实现》(第三版)粗读笔记
- 2种基于异常机制的反调试方法
- [LeedCode OJ]#169 Majority Element
- Linux下安装Python3
- extjs4 之单元格编辑 获取列对象
- Android IM(五)连接断开重连
- Linux内核设计与实现--学习笔记--第三章- 1(task_struct等)
- 黑马程序员——线程Thread一(线程创建)
- Android系统自带样式(android:theme)
- 深入理解RunLoop
- 不使用Sencha Cmd,创建EXT-JS应用
- UVA11990 ``Dynamic'' Inversion (树状数组套平衡树)
- 论文笔记 《What makes for effective detection proposals?》
- C#堆内存分配和栈内存分配
- Java____进程、线程学习、处理器调度(转)