linux内核——进程管理
在讲进程之前先说一下进程的堆栈的吧:
1.进程的堆栈
内核在创建进程的时候,在创建task_struct的同一时候,会为进程创建对应的堆栈。每一个进程会有两个栈,一个用户栈。存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间执行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。
2.进程用户栈和内核栈的切换
当进程由于中断或者系统调用而陷入内核态之行时。进程所使用的堆栈也要从用户栈转到内核栈。
进程陷入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完毕了用户栈向内核栈的转换;当进程从内 核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器就可以。
这样就实现了内核栈和用户栈的互转。
那么,我们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的。可是在陷入内核的时候,我们是怎样知道内核栈的地址的呢?
关键在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是由于。当进程在用户态执行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态执行的相关信息。可是一旦进程返回到用户态后,内核栈中保存的信息无效,会所有恢复。因此每次进程从用户态陷入内核的时候得到的内核 栈都是空的。所以在进程陷入内核的时候。直接把内核栈的栈顶(从下往上增长的栈)地址给堆栈指针寄存器就能够了。
再来理解一下线程进程的概念:
线程:是进程中的活动对象。每一个线程都用有意个独立的程序计数器,进程栈和一组进程寄存器,内核调度的是线程,而不是进程。
进程:进程就是处于运行期的程序,可是进程并不只局限于一段可运行的程序代码,通常进程还包括其它资源,像打开的文件,挂起的信号。内核内部的数据结构,处理器状态,一个或者多个具有内存映射的内存地址空间及一个或者多个线程,也就是说进程是处于运行期的程序以及相关资源的总称。
进程提供两种虚拟机制:虚拟内存和虚拟处理器;提供给每一个进程一个独立的虚拟处理器以及独立的地址空间,给进程一种独享处理器和拥有整个系统的内存资源的假象。
内核把进程描写叙述符结构(task_struct)存放在一个双向循环链表的任务队列中;
Linux通过slab分配起分配task_struct结构。用slab分配生成的task_struct仅仅须要在栈顶(向上增长的栈)或者栈底(向下增长的栈)创建一个新的结构struct thread_info

进程描写叙述符的存放
内核通过唯一的进程标识值或者PID来标识每个进程,部分硬件体系架构能够用一个专门的寄存器来存放当前进程的task_stuct指针。用于加快訪问速度,x86架构寄存器并不多,所以智能在内核栈尾端创建thread_info结构,通过计算偏移间接地查找task_struct结构。
进程状态:
TASK_RUNNING:运行。进程是可运行的,或者是它正在运行;
TASK_INTERRUPTIBLE:可中断。进程正在睡眠或者堵塞,等待某些条件的达成。
TASK_UNINTERRUPTIBLE:不可中断,就算是接受到信号也不会被唤醒或者执行,不正确信号做不论什么响应。用的较少;
TASK_TRACED:被其它进程跟踪的进程;
TASK_STOPPED:停止,进程没有投入执行或者不能投入执行;

设置当前进程的状态可用函数:set_task_state(task,state)。
进程的创建
一般的操作系统的产生(spawn)进程的机制:新的地址空间里创建进程,读入可运行文件,最后開始运行。
Linux採用UNIX的实现方式将上述步骤分解到两个单独的函数中去运行:fork()和exit(),fork函数通过拷贝当前进程创建一个子进程,exec函数负责读取可运行文件将其加载地址空间開始运行;
写时拷贝技术:
传统的fork系统调用直接把全部资源复制给子进程。可是可能新创建的子进程运行的程序文件映像并不须要那么多资源那么拷贝就就显得非常浪费了,写时拷贝是一种推迟甚至免除拷贝的技术,仅仅有在须要写入是数据才会被拷贝,内核并不复制整个进程的地址空间。而是父子进程共享一个拷贝。
在数据须要被写入时才会复制;
下图是明显的比較:
普通操作系统创建子进程直接全拷贝数据段。堆。栈:

写时复制技术:内核仅仅为新生成的子进程创建虚拟空间结构,它们来复制于父进程的虚拟到底结构。可是不为这些段分配物理内存,它们共享父进程的物理空间,当父子进程中有更改对应段的行为发生时。再为子进程对应的段分配物理空间。

vfork():这个做法更加火爆,内核连子进程的虚拟地址空间结构也不创建了。直接共享了父进程的虚拟空间。当然了。这样的做法就顺水推舟的共享了父进程的物理空间

fork(),vfork(),_clone()--------> clone()系统调用-------------->do_fork()在kernel/fork.c中,完毕大部分的创建工作----------------->copy_process()让进程開始执行;
Copy_process():完毕创建task_struct内核栈,thread_info结构,task_struct结构,分配PID,拷贝父进程必要的资源,
线程在linux中的实现:
从内核的角度来看,是没有线程的概念的,linux把全部的线程当进程来实现的,内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。线程只被视为一个与进程共享某些资源的进程。每一个线程都有自己的task_struct,
线程的创建:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND , 0 );
上面的代码产生的结果和fork差点儿相同,仅仅是父子俩共享地址空间,文件系统资源,文件描写叙述符和信号处理程序。一个普通的fork例如以下:
clone( SIGHLD , 0);
Vfork的实现:
Clone(CLONE_VFORK | CLONE_VM | SIGHLD,0);
内核线程并没有独立的地址空间。它们仅仅有在内核空间中执行,从不切换到用户空间去;新任务使用kthread内核进程通过clone系统调用创建的,新创建的内核线程处于不可执行状态;假设不通过wake_up_process唤醒他不主动执行;只是创建一个内核线程并让它执行起来能够通过kthread_run来达到;相当于kthread_create()和wake_up_process()执行;
进程终结:进程析构它发生在进程调用exit系统调用时,do_exit()完毕大部分工作:删除内核定时器。释放mm_struct,离开队列,引用计数降低(为0释放)。为子进程找养父,处于僵死状态,删除进程(任务队列)。释放僵死进程资源,通知其父进程,释放task_struct内核栈,thread_info占的页。并释放task_struct所占的告诉缓存的slab;
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(61) | 评论(0) | 转发(0) |
linux内核——进程管理的更多相关文章
- Linux内核——进程管理与调度
进程的管理与调度 进程管理 进程描写叙述符及任务结构 进程存放在叫做任务队列(tasklist)的双向循环链表中.链表中的每一项包括一个详细进程的全部信息,类型为task_struct,称为进程描写叙 ...
- Linux内核 ——进程管理之进程诞生(基于版本4.x)
<奔跑吧linux内核>3.1笔记,不足之处还望大家批评指正 进程是Linux内核最基本的抽象之一,它是处于执行期的程序.它不仅局限于一段可执行代码(代码段),还包括进程需要的其他资源.在 ...
- Linux内核——进程管理之CFS调度器(基于版本4.x)
<奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...
- Linux内核——进程管理之SMP负载均衡(基于版本4.x)
<奔跑吧linux内核>3.3笔记,不足之处还望大家批评指正 根据实际物理属性,CPU域分类如图1所示. 图1 CPU域分类 问题一:一个4核处理器中的每个物理CPU拥有独立L1 cach ...
- linux内核 进程管理
进程和线程 进程不单单包含可执行代码(代码段),好包含打开的文件,挂起的信号,处理器状态,虚拟内存地址等. 线程:从内核的角度来说,它并没有线程这个概念.Linux把所有线程都当做进程来实现.内核并没 ...
- Linux内核电源管理综述
资料:http://blog.csdn.net/bingqingsuimeng/article/category/1228414http://os.chinaunix.net/a2006/0519/1 ...
- Linux操作系统的进程管理
Linux操作系统的进程管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程相关概念 1>.进程概述 内核的功用: 进程管理.文件系统.网络功能.内存管理.驱动程序. ...
- linux 系统管理--进程管理
目录 linux 系统管理--进程管理 一.进程基本概述 二.监控进程状态 三.进程的优先级[进阶] 四.企业案例,Linux假死是怎么回事 五.后台进程管理 六.系统平均负载[进阶] linux 系 ...
- .Neter玩转Linux系列之五:crontab使用详解和Linux的进程管理以及网络状态监控
一.crontab使用详解 概述:任务调度:是指系统在某个时间执行的特定的命令或程序. 任务调度分类: (1)系统工作:有些重要的工作必须周而 复始地执行. (2)个别用户工作:个别用户可能希望执 行 ...
随机推荐
- bzoj 2406 二分+有源有汇上下界网络流可行流判定
弱爆了,典型的行列建模方式,居然想不到,题做少了,总结少了...... 二分答案mid s----------------------->i行-----------------------> ...
- OpenGL和GLSL版本更迭
前言 最近才发现,自己写的glsl和教程的glsl版本对不上,一直以为是xcode不允许使用太高版本,只能使用OpenGL 2.0的版本,却不知使用glfw可以使用到最新的OpenGL版本.
- Codeforces Round #353 (Div. 2) D. Tree Construction 模拟
D. Tree Construction 题目连接: http://www.codeforces.com/contest/675/problem/D Description During the pr ...
- python 编程语言基础技术框架
python标识符身份 id方法查看唯一标示符,内存地址 >>> a = "str" >>> b = 2 >>> id(a) ...
- 封装scroll.js 获取滚动条的值
function Obj(){} Obj.prototype={ scroll:function(){ /* 主要是做兼容处理 这里必须时!=null 因为默认值和每次滚动的时侯 都可以值为0 但是 ...
- JS实现《黑客帝国》落地字母背景
JS实现<黑客帝国>落地字母背景.这个特别有意思,主要是通过设置字符相关属性.控制循环字母距离顶部的高度值,来达到字母不断循环下落的功能. 恩,还有加上一个随机机制,出现各种大小 各个位置 ...
- adb root : adbd cannot run as root in production builds
在有些android手机上使用adb root希望获取root权限时出现如下提示信息:adbd cannot run as root in production builds.此时提升root权限的方 ...
- 无法打开文件“atlsd.lib”
问题: vs2013编译c++代码,错误 15 error LNK1104: 无法打开文件“atlsd.lib” 解决: 在你电脑或者其他人电脑上搜索atlsd.lib,将其拷贝到D:\Program ...
- 游戏编程之Unity常用脚本类的继承关系
前言学习Unity开发引擎的初学者会接触大量的脚本类,而这些类之间的关系往往容易被忽略.本文对Unity引擎开发中的一些常用类及其关系进行了简单的归纳总结. 博文首发地址:http://tieba.b ...
- .NET:为什么需要逆变和协变
为啥需要协变和逆变? 我目前想到的理由是:逆变和协变的目的是支持多态. 一个小例子 不明白为啥输出的是false和true. using System; using System.Collection ...