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) 把长的行和字 ...
随机推荐
- 如何开启一个Django项目
一:新建的Django工程 新建了一个Django工程后,工程会自动创建有两个templates文件夹和unitled文件夹,再加上一个manage.py文件. 二:Django开发的一般流程 在工程 ...
- [转]Ubuntu下ROS开发环境搭建(QT+ros_qtc_plugin)
ROS与C++入门教程-搭建开发环境(QT+ros_qtc_plugin) PS : 在“安装ros_qtc_plugin插件”这一步中,原文提到“ Ubuntu 14.04使用apt-get方式安装 ...
- 如何在ie6/ie7/ie8中实现iframe背景透明
最近做了一个项目,涉及到ie8iframe背景透明的问题,做了老半天,才把它搞定的,现在把我的经历贴出来和大家分享: 众所周知的根据W3C CSS 2.1 规范规定,''''background-co ...
- skb_pull skb_push skb_put
unsigned char *skb_pull(struct sk_buff *skb, int len)该函数将 data 指针向数据区的末尾移动,减少了len 字段的长度.该函数可用于从接收到的数 ...
- 学习网站总结->
慕课大巴网:这是一个学习各类技术视频的网站 慕课大巴网点我-> 吾爱破解: 这是一个破解各类软件的网站 吾爱破解点我-> 鸠摩搜书:可以搜一些免费的书,我喜欢的都能搜到 鸠摩搜书点我-&g ...
- 六、springboot集成Swagger2
1.Swagger简介 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法 ...
- 22 Gobs of data 设计和使用采集数据的包
Gobs of data 24 March 2011 Introduction To transmit a data structure across a network or to store it ...
- MySQL基础 - 视图
创建视图: 假设要将posts表的前十条数据作为视图 mysql> CREATE VIEW view_test AS SELECT * FROM POSTS LIMIT 10; 使用: 可以把视 ...
- Python基础 - Ubuntu+Nginx+uwsgi+supervisor部署Flask应用
网上找了许多讲关于Flask应用部署的文章几乎都是一个helloworld的Demo,按照helloworld来部署都没问题,但实际项目部署时还是遇到了不少问题.在这里简单写下自己成功部署的过程,防止 ...
- UVA 10891 Game of Sum(区间DP(记忆化搜索))
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...