Linux内核代码

全局描述符表GDT(Global Descriptor Table):
(1)在整个系统中,全局描述符表(注意这里是表,表只有一张)GDT只有一张(一个处理器对应一个GDT)。
(2)GDT可以被放在内存的任何位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此积存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限。

每一个LDT自身作为一个段存在,它们的段描述符被放在GDT(全局描述符表中)中。
每一个段描述符由一下几部分组成:
(1)32位的base域,含有段的第一个字节的线性地址
(2)粒度位G,如果被清0,段大小以字节为单位,否则以4096(4kB)字节为基本单位
(3)20位的limit域,指定了以字节为单位的段长度,如果G被置0,则是一个非空段大小在1个字节到1M之间变化的,否则将在4KB到4GB之间变化
(4)系统标志S,如果被清0.则是一个系统段,存储内核数据结构,否则他是一个普通的代码段或数据段
(5)4位TYPE域,描述了段的类型特征和他存取权限,一下类型的段描述符被广泛采用
代码段描述符:
这个段描述符代表一个代码段,可以是GDT或LDT中,S标志位1
数据段描述符:
这个段描述符代表一个数据段,可以放在GDT或LDT 中,S标志为1,栈段一般通过一般数据段实现
任务状态段描述符:
这个段描述符代表一个任务状态段(Task state segment,TSS),也就是说这个段用于保存寄存器的内容,他只呢个放在GDT中,分组相应的进程是否正在CPU 上运行,其TYPE域的值分别为11或9,S标志为0
局部描述符表描述符:
这个段描述符代表一个LDT段,他只能放在GDT中,相应的TYPE为2,S标志为0
(6)2位DPL(描述符特权级),用来限制对这个段的存取,他表示方位这个段,cpu所需要的最小特权级
(7)segment-present 标志,设置为0 ,标志这个段当前不在主存中,Linux总是把这个域设为1,因此它从来不把整个段交换到磁盘上去。
(8)一个被称为D或B的额外标志,取决于是代码段还是数据段。D或B的含义在两种情况下稍微有区别。但是,段偏移量的地址是32位,他被置为1,如果偏移量是16位,它被置为0
(9)第53位是保留位,总是设为0
(10)AVL标志,可以被操作系统使用,但是被Linux
进程:
内核必须知道进程的优先级,进程的状态,给进程分配什么样的地址空间,允许访问哪些文件,这些信息都被记录在一个叫——进程描述,的结构中。
进程描述符号都是task_struct{}类型的。
进程状态:
TASK_RUNNING(可运行状态) :
进程要么在CPU中运行,要么准备运行.
TASK_INTERRUPTBLE(可中断的等待状态):
进程被挂起(睡眠),知道一些条件为真,这些条件包括,硬件中断,释放进程等待的资源,或传递一个信号,都可以唤醒一个进程,让进程进入TASK_RUNNING状态
TASK_UNINTERRUPTBLE(不可中断的等待):
该状态和前一个状态类似,但是不能被信号唤醒,要满足特殊的状态才能被唤醒。
TASK_STOPPED(暂停状态):
所谓的暂停状态是指,进程任然在使用CPU 但是,在某个时间,停止运行,当进程接收到信号SIGSTOP,SIGSTP.........等信号时,就会进入该状态。进程用于软件的调试
TASK_ZOMBIE(僵死状态):
进程的执行被终止,但是父进程还没有发布wait()类系统调用以返回死进程的相关信息,如果没有返回相应的信息,内核系统就不能 丢弃死进程中的描述符中的数据,因为符进程可能需要他。
进程描述符的存放:
task 数组中的仅仅包含进程描述符的指针,而不是进程描述符本身。因为进程是动态实体,所以被放在动态内存中,而不是放在永久性分配的内核内存区。Linux把两个不同的数据结构紧凑的放在一个单独为进程分配的存储区域内:(1)一个是内个态的进程堆栈(2)另外一个是紧挨进程描述符的小数据结构中——thread_info(线程描述符)
进程堆栈段和线程描述符总共有8KB的空间
注意:从效率上来讲,进程堆栈段和线程描述结构紧密结合带来的好处是:内核很容易从esp寄存器的值获得当前在CPU 正在运行的thread_info 结构的地址
进程链表:
为了对给定进程类型(可运行的所有进程)进行有效的搜索。内核建立几个进程链表(每个进程链表由指向进程描述符的指针组成,PID存放在进程描述符的PID描述符中)。进程描述符的数据结构中包含了一个指向下一个进程链表指针。
注意:进程链表的链表头是init_task描述符,他是所有进程的祖先。
相关函数:
宏:
SET_LINKS/REMOVE_LINKS //用来链表中插入和删除一个进程描述符
for_each_task()//用来扫描整个进程链表
进程链表——TASK_RUNNING状态的进程链表:
当内核需要寻找一个新的进程在CPU 上运行,必须考虑可运行的进程。如果扫描整个进程链表效率太低了。因此引入可运行状态进程双向链表,也叫做运行队列(runqueue),和一般的进程链表一样,init_task作为链表头,nr_running变量存放可运行队列进程总数
相关函数:
添加和删除:
add_to_runqueue()//把一个进程描述符插入到链表的开始
del_from_runqueue()//从进程中删除一个进程描述符
队列调度:
move_first_runqueue()
move_last_runqueue()
唤醒进程:
wake_up_process()//将一个进程的状态设置为TASK_RUNNING
进程链表——pidhash表及链接表:
当一个进程需要向另外一个进程发送信号,如果采用遍历扫描他消耗时间,然后就使用pidhash 算法。不懂!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
相关函数:
hash_pid()//在pidhash 表中插入进程
unhash_pid()//在pidhash 表中删除一个进程
find_task_by_pid()//查找散列表并返回给定PID 进程的进程描述符指针(如果没有找到则返回空指针NULL)
进程链表中——task空闲表象列表
每当进程被创建或撤销时,就要更新task数组。把一个新项有效的加到数组中去方式,不是线性的寻找列表中找到一个空闲项,而是内核维持了一个独立的包含空闲项的非循环双向列表,这个数组中的每一个空闲项指向下一个空闲项。而链表中的最后一个元素包含空指针,当一个进程被撤销时,task中对应的元素加到表头。
相关函数:
get_free_taskslot()//获得空闲进程描述符表项
add_free_taskslot()//添加空闲进程描述符表项
进程之间的亲属关系:
进程之间的关系无非是父子和兄弟之间的 关系,在进程描符中引出几个域来描述这种关系
等待队列:
运行队列链表把处于TASK_RUNNING 状态的进程组织到一起,同理运行队列列表也会把处于其他状态的组织到一起。
(1)TASK_STOPPED 或TASK_ZOMBIE状态的进程不链接在专门的链表中也没有必要分组,因为父进程可以通过进程PID ,或进程之间的亲属关系检索到子进程
(2)把TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE分类,每一类完成特定类型的,这样进程状态满足不了快速检索进程,因此有必要引入另外的进程链表——等待队列。
进程调度:
Linux内核代码之重要函数
modify_ldt(int func, void *ptr, unsigned bytecount):
该系统调用用来改变当前进程的局部段描述表
Linux内核代码之重要数据
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
Linux内核代码的更多相关文章
- [转] Linux内核代码风格 CodingStyle [CH]
from:http://blog.csdn.net/jiang_dlut/article/details/8163731 中文版维护者: 张乐 Zhang Le <r0bertz@gentoo. ...
- 从linux内核代码分析操作系统启动过程
朱宇轲 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 在本次的实验中, ...
- 第三次阅读赵炯博士的《linux内核代码完全注释》:序
这是我第三次阅读linux内核代码完全注释了,当然前两次也没有读完,第一次读到第五章,第二次第七章. 所以说,赵炯博士对我最大的帮助时介绍了intel386的结构,以及内核编程的方法. 至于真正的内核 ...
- 使用QEMU调试Linux内核代码
http://blog.chinaunix.net/uid-20729583-id-1884617.html http://www.linuxidc.com/Linux/2014-08/105510. ...
- win7 变WIFI热点 & 在线Linux 内核代码
https://daniel.haxx.se/docs/sshproxy.html netsh wlan set hostednetwork mode=allow ssid=mywifi key=1 ...
- linux内核代码的编写初步以及makefile的配置
在linux内核代码开发中,头文件不能包含标准C头文件,只能采用GNC标准 而且内核开发中没有main函数,只有init 和 exit ,这是每个内核模块中必须要包含的函数模块. 在GNU C标准中, ...
- Linux学习笔记:【004】Linux内核代码风格
Chinese translated version of Documentation/CodingStyle If you have any comment or update to the c ...
- linux内核代码注释 赵炯 第三章引导启动程序
linux内核代码注释 第三章引导启动程序 boot目录中的三个汇编代码文件 bootsect.s和setup.s采用近似intel的汇编语法,需要8086汇编器连接器as86和ld86 head ...
- Linux 内核代码风格
文章目录 从编码风格错误开始 快速修改编码风格的工具 scripts/checkpatch.pl scripts/Lindent astyle Linux 内核代码风格 1) 缩进 2) 把长的行和字 ...
随机推荐
- TensorFlow在windows10上的安装与使用(一)
随着近两年tensorflow越来越火,在一台新win10系统上装tensorflow并记录安装过程.华硕最近的 Geforce 940mx的机子. TensorFlow是一个采用数据流图(data ...
- Struts2笔记2--动态方法调用和Action接收请求方式
动态方法调用(在请求的时候,再明确具体的响应方法,配置的时候不明确): LoginAction类中有两个方法some和second 1. 动态方法的调用(修改常量struts.enable.Dynam ...
- 如何基于Spring Boot搭建一个完整的项目
前言 使用Spring Boot做后台项目开发也快半年了,由于之前有过基于Spring开发的项目经验,相比之下觉得Spring Boot就是天堂,开箱即用来形容是绝不为过的.在没有接触Spring B ...
- 一步一步搭建11gR2 rac+dg之配置单实例的DG(八)【转】
RAC主库配置单实例ActiveDataguard 本文文档结构: 这里配置的过程中需要注意的一项是多看看rac1和rac2以及dg的告警日志会对配置过程有更深刻的理解...配置oracle rac的 ...
- sql loader 控制文件使用十六进制分隔符
最近项目中使用到了sql loader加载数据文件至数据库,提供的文件中使用了十六进制 7F5E 分隔符,在sql loader中如何加载呢? 经过查询实验后,控制文件ctl内容如下: load da ...
- Python基础:内置异常(未完待续)
本文根据Python 3.6.5的官文Built-in Exceptions编写,不会很详细,仅对Python的内置异常进行简单(重难点)介绍——很多异常都可以从名称判断出其意义,罗列所有的内置异常. ...
- spotlight on mysql--安装以及简介
Spotlight on MySQL 安装与配置 第一步: 下载并安装mysql-connector-3.5x Spotlight on MySQL 连接mysql必须使用mysql-connecto ...
- docker容器配置独立ip
一般安装docker后都会通过端口转发的方式使用网络,比如 “-p 2294:22” 就将2294抓发到22端口来提供sftp服务,这样使用起来没有问题.但端口号很难记忆,如果前边有nginx等抓发工 ...
- No.1 selenium学习之路之浏览器操作
selenium基础,首先就是浏览器的相关操作 下面描述几种浏览器的常用操作 1.打开浏览器 webdriver后面添加想要打开的浏览器 Ie或者Chrome 2.打开指定页面(百度) 3.休眠时间 ...
- javaweb 要学习的东西
我学院课设是Javaweb程序,要用eclipse,tomcat,jbdc,和数据库 jbdc,是连接数据库的驱动,tomcat是一种类似于服务器的东西,现在买不起服务器,就用tomcat