Linux 内核设计与实现(未完待续)

Linux 源码是 C 写的,这里为了描述方便,C 语言里的 struct 就记成对象。

进程和线程

进程在源码里面是一个 task_struct 对象,它的相关描述是 thread_info 对象。方便找到 进程 对象 的位置并修改。有的服务器还会再CPU的寄存器存放进程的指针,用于加快访问速度。

进程有5种状态,保存在 task_structstate 对象里面。

  1. TASK_RUNNING
  2. TASK_INTERRUPTIBLE (可中断)
  3. TASK_UNINTERRUPTIBLE (不可中断)
  4. _TASK_TRACED (被其他进程追踪的进程)
  5. _TASK_STOPPED (停止)

Unix系统的进程存在一个明显的继承关系,所有的进程都是 PID 为 1 的 init 进程的后代。系统中每个进程必有一个父进程,也可以拥有零个或多个子进程。

Linux 的 fork 实现采用 写时拷贝(copy-on-write) 技术,也就是懒加载。开始fork进程的时候并不会把数据也fork给子进程,开始是父子进程共享地址空间数据,只有当子进程开始写数据的时候,才开始把父子进程的地址空间分离开来。

Linux对线程的处理就是当作普通的进程(轻量级进程)来处理,只不过它与其他的一些进程共享某些资源(地址空间)。在创建的时候,需要指明它与父进程所共享的资源(共享地址空间,文件系统资源,文件描述符,信号处理程序)。

进程调度

Linux 提供的是抢占式的多任务模式,这种模式调度程序就会根据进程的优先级来判断进程什么时候该停止,什么时候该运行。这个强制停止的操作就称为抢占。每个进程可执行的时间都是设置好的,这个叫做进程的时间片。所以,有效的设置时间片对调度是非常有帮助的。linux 的公平调度本身并没有采取时间片来实现。

Linux 的公平调度算法名字叫 CFS,是O(1) 调度的升级版。Linux 的进程有两种优先级范围,实时级优先级是 0-99, 数字越大优先级越高。普通进程是 nice 值表示-20 ~ 19,数字越低权限越大。一个进程不可能同时属于实时级优先级和 nice 值优先级。使用命令可以查看(rtprio表示实时级优先级, ni表示nice值. )

ps -eo state,uid,pid,ppid,rtprio,ni,time,comm

Linux 的公平调度表现在会给相同优先级的进程分配相同的 “时间片”,在 Linux 中表示为处理器使用比。两个相同优先级的进程,初始时都是 50 %, 假设一个是 I/O 密集型任务,一个是 CPU 密集型任务,当I/O阻塞时, CPU这个任务一直在运行,当 I/O 不阻塞时, CPU任务就会立刻阻塞,让I/O任务先处理,这是因为 I/O 阻塞地 时候 处理器使用少,所以优先调度。这才体现了公平调度。读到这里,我不禁感叹一句,真的好牛逼。

Linux 的进程调度是通过一系列进程调度类来实现的,CFS 对应的是普通进程(nice值)的调度类,CFS 的调度不是基于根据nice值等比例的时间片来实现的,首先,会根据进程总数和每个进程的优先级得出每个进程的CPU运行比,有最小时间粒度,是 1ms。当进程过多时,就会出现频繁的进程切换带来的性能损耗,但是实际运行情况还好,没有到那么多进程的程度。

Linux 进程调度实现:

  1. 时间记账。CFS 通过 vruntime 变量来追踪进程的运行时间
  2. 进程选择。所有可运行进程保存在一个自平衡的二叉搜索树上面(红黑树)上面,每次取进程就找数的最左节点,为了保证性能,会缓存最左节点的进程信息,方便快速找到。
  3. 调度器入口。 schedule() 函数实现,从优先级高到低选择调度类的实现,每个调度类都会维护一个可运行队列。具体看源码实现吧
  4. 睡眠和唤醒。当进程需要阻塞或者不可用的时候,会从树中把这个进程移除,修改进程的状态,加入到一个等待队列中去。当有事件触发时,修改进程状态,并加入到可运行队列中去(红黑树)了。

Linux 内核是支持 SMP 的,这里来谈谈它的抢占式特点。抢占分为两种,一种是用户抢占,发生在进程执行完系统调用返回到用户空间中断程序返回用户空间 的时候,会被检查是否设置了 need_resched 标志,当这个标志被设立了,就会调用一次 schedule() 方法执行下一个进程。另一种是内核抢占,内核抢占还会加上另一个锁标志判断,preempt_count, 默认是0,加锁就 +1,释放锁就 -1。只有当 need_sched 被设置了且 preempt_count 等于 0 才会进行进行 schedule() 调用。内核抢占发生在以下几种情况

  1. 中断程序正在运行,且返回用户空间
  2. 内核代码主动调用 schedule()
  3. 内核代码再一次具备可抢占条件的时候
  4. 内核代码中的任务阻塞也会这样

Linux的调度策略,对于实时进程,有 SCHED_FIFOSCHED_RR 两种,后者比前者优先级高,在每一种实时进程里面,只能高优先级的抢占低优先级的。SCHED_FIFO 永远也不能抢占 SCHED_RR 类型的进程。实时进程是有时间片的,只能等待时间片执行完毕或者进程主动阻塞才能切换别的进程执行。实时进程的进程值从0-99,普通进程是 SCHED_NORMAL 调度策略,进程值100 ~ 139 ,对应于nice 值的 -20 ~ 19

系统调用

Linux 在硬件设备和用户空间之间加了一层 系统调用 使得用户程序访问硬件设备更安全,可靠。

Linux 内核的系统调用实现有三步:

  1. 确定系统调用号
  2. 系统调用方式
  3. 参数传递方式

内核为每个系统调用都有一个唯一的系统调用号,存在于 sys_call_table 中。按顺序排序,每种硬件设备都有对应的table。用户程序会通过 软中断 来告知内核需要进行一个系统调用, 这个软中断就是个 0x80 的指令异常,内核会专门处理这个异常然后进行相应的系统调用。这个处理程序就是 system_call(), 现在已经换成了效率更高的 sysenter 指令了。在 x86 上面,系统调用号是通过在 eax 寄存器传递个内核的,所以参数也是一样,不过他们放在寄存器的 ebx, ecx, edx, esi, edi 等32位的寄存器上(in order)。

实现系统调用,这一段没啥说的,只能说一句,我们写代码需要像内核一样的稳定

一个支持 SMP 机器的系统肯定是得有锁的。锁有多种,大致分两类,一类是阻塞式锁,一类是非阻塞式锁。

非阻塞形锁:

​ 原子性操作: 这其实不算是锁,只不过是cpu支持的一种指令,是原子性的。有些是CPU原子级别支持,有些只是通过锁总线来支持的。

​ 自旋锁:未获取到锁的进程就一直在等待队列里面自旋,空转CPU。适用于锁内执行时间较短的任务。否则空转cpu太浪费资源。

阻塞形锁:

  1. 信号量: 可计数的,实现原理是让让等待中的线程睡眠,等待信号唤醒
  2. mutex(互斥锁):默认计数为1的信号量
  3. 顺序锁
  4. BLK(大内核锁)

每种锁都有 读写锁的适配版本,读的时候可以并发读,写的时候只能一个锁持有。

应用场景:

​ 在中断上下文里面只能用自旋锁,因为中断上下文不能让线程睡眠。只能在进程上下文里面使用阻塞形锁。

这里有一篇关于中断上下文和进程上下文的概念文章 https://www.cnblogs.com/stemon/p/5148869.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容