内核与操作系统

由于一些商业操作系统设计上的缺陷以及日益庞杂,“操作系统”的概念对很多人而言变得含糊不清。在进一步讨论Linux内核的话题前,我们先区分“内核”与“操作系统”这两个概念。

  • 操作系统:指在整个系统中完成最基本功能和系统管理的部分,包括内核、设备驱动、文件管理工具、系统管理工具、shell命令行或其他用户界面(gnome/KDE等)
  • 内核:是操作系统的核心,完成进程管理、cpu调度、内存管理、中断处理等功能

一般我们编写的应用程序,跑在操作系统上,完成文字编辑、音乐播放、网页游览等特定功能。

内核编译

内核源码一般放在/usr/src目录下,我们也可以从这里获取所需内核版本的源码包。编译内核的第一步是配置内核功能,例如配置是否支持对称多处理器(SMP),可通过设置CONFIG_SMP的值。

通常我们使用"make menuconfig"命令进行配置,其提供了友好的配置界面:

 

保存配置后,源码目录下将生成.config配置文件,打开该文件,可以看到其内容为各种选项设置:

  1. CONFIG_X86_64=y
  2. CONFIG_64BIT=y
  3. CONFIG_X86=y
  4. CONFIG_SEMAPHORE_SLEEPERS=y
  5. CONFIG_MMU=y
  6. ……

我们也可以使用当前的内核配置,使用以下命令快速地生成.config文件:

  1. zcat /proc/config.gz > .config

之后根据.config配置,对源码进行编译:

  1. make -j4

以上使用-j选项,指定并行编译工作任务数目,在多核环境下,减少了编译时间。

编译完成后生成内核压缩镜像:

  1. make bzImage

生成的内核压缩镜像文件位于 arch/x86/boot目录下:

  1. linux-2.6.32.59 # ll arch/x86/boot/bzImage
  2. -rw-r--r-- 1 root root 2814112 07-02 22:27 arch/x86/boot/bzImage

接着安装内核模块:

  1. make modules_install

新的模块会被放置在/lib/modules目录下:

  1. /lib/modules # ll
  2. 总计 8
  3. drwxr-xr-x 4 root root 4096 03-08 23:53 2.6.32.12-0.7-default
  4. drwxr-xr-x 3 root root 4096 07-02 23:31 2.6.32.59-0.7-default

最后执行make install安装内核,在/boot目录下将生成System.map、vmlinuz和initrd文件:

  1. linux-2.6.32.59 # make install
  2. sh /home/lx/kernel/linux-2.6.32.59/arch/x86/boot/install.sh 2.6.32.59-0.7-default arch/x86/boot/bzImage \
  3. System.map "/boot"
  4. Kernel image: /boot/vmlinuz-2.6.32.59-0.7-default
  5. Initrd image: /boot/initrd-2.6.32.59-0.7-default
  6. ……

完成安装后,在/boot/grub/menu.lst文件中增加了新内核相应的启动项,我们可以修改该文件,指定系统启动后使用新编译的内核。

进程与线程

Linux下,进程与线程的最大不同是进程拥有独立的内存地址空间,而线程与其他线程共享内存地址空间。除此之外,进程与线程的实现基本相同,都有task_struct结构,都被分配PID。

内核线程没有独立的地址空间,它们完成特定工作并接受内核的调度,不同于一般用户进程,它们不接收kill命令发送的信号:

  1. F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME   CMD
  2. 1 S root  2   1  0 -40  -   -  0 migrat Jul01 ? 00:00:00 [migration/0]
  3. 1 S root  3   1  0  94 19   -  0 ksofti Jul01 ? 00:00:00 [ksoftirqd/0]
  4. 5 S root 18   1  0  70 -5   -  0 worker Jul01 ? 00:00:00 [events/0]
  5. ……

task_struct

task_struct结构包含进程使用的虚拟内存、打开的文件、进程状态、进程pid等信息,占用的内存由slab分配,在文件中定义。thread_info结构的第一个字段为task_struct类型的指针,当进程创建时,thread_info存放在进程内核栈的顶部:

current全局变量指向当前运行进程的task_struct结构,由于thread_info存放的位置固定,这样我们通过以下汇编指令就能很容易地计算出current的值:

  1. movl $-8192, %eax
  2. andl $esp, %eax

 

进程状态

进程可处于以下几种状态:

  1. RUNNING
  2. INTERRUPTABLE
  3. UNINTERRUPTABLE
  4. STOP
  5. ZOMBIE

这些进程状态作为宏,在sched.h文件中被定义。

  • RUNNING状态表示进程是可执行的,或正在执行或在运行队列中,这些进程占用或等待cpu资源。
  • 进程调用退出函数exit后,进程中止,进入ZOMBIE状态。在ZOMBIE状态下进程不会占用cpu,但因其task_struct结构尚未释放,仍占用一点内存,直到父进程调用wait函数接受子进程遗愿,假如父进程先于子进程退出,则由init进程接受子进程遗愿。如果一个进程长期处于ZOMBIE状态,则是父进程中未调用wait,为程序编码问题。
  • UNINTERRUPTABLE状态表示进程不可中断,处于此状态的进程处于内核态,并且不接收任何信号。

设置进程状态的函数为set_task_state函数,在文件中定义。

进程间关系

进程间关系与目录结构一样,为树状结构,目录结构以/为根,而进程关系以init为根。我们可以使用pstree查看进程间关系:

  1. linux-14:~ # echo $$
  2. 10939
  3. linux-14:~ # pstree -G -p 10939
  4. bash(10939)─┬─pstree(12806)
  5. └─sh(12796)───sleep(12801)

内核代码中提供了一条双向闭环链表,自init进程始,链表连接了所有进程的task_struct结构,可以通过for_each_process宏遍历系统的所有进程:

  1. #define for_each_process(p) \
  2. for (p = &init_task ; (p = next_task(p)) != &init_task ; )

进程创建

Linux kernel将进程创建的步骤分成两步:fork和exec。fork生成子进程的pid,将父进程执行上下文、打开的文件描述符等内容复制一份给子进程;exec将子进程自己的执行上下文加载进内存地址空间。有以下fork例子,问执行该程序将输出多少个1?

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5. int i;
  6. for(i=0 ; i < 10; i++)
  7. {
  8. fork();
  9. }
  10. printf("%d\n", 1);
  11. return 0;
  12. }

fork拷贝父进程的内容到子进程,开销较大,假若调用fork之后马上调用exec,子进程加载自己的执行文件,则拷贝的动作就是多余的。写时拷贝(copy-on-write,COW)解决了拷贝带来无谓开销的问题,在子进程写父进程地址空间时,才触发拷贝的动作。不做多余事情、非到不得已的时候才完成工作,这也是Linux kernel高效的原因之一。

内核中do_fork函数完成fork调用的工作,do_fork调用copy_process。copy_process函数中主要完成以下工作:

  1. 调用dup_task_struct函数申请新进程的task_struct、thread_info结构
  2. 根据clone_flags标志,调用copy_files、copy_fs、copy_mm等函数完成文件、文件系统、内存等信息的拷贝
  3. 调用alloc_pid申请新进程pid

fork返回两次,在do_fork函数中实现。

进程中止

最终进程会调用exit函数中止,exit系统调用最终会调用内核中do_exit函数,do_exit在中定义,其完成以下工作:

  1. 调用exit_signals设置进程flags标志为PF_EXITING
  2. 调用exit_mm、exit_files、exit_fs等函数释放进程内存、文件、文件系统等结构
  3. 设置进程的exit_code
  4. 调用exit_notify,向当前进程的父进程、子进程发送信号,告知当前进程将要中止,并设置当前进程退出状态exit_state为EXIT_DEAD或EXIT_ZOMBIE
  5. 调用schedule,切换到另一个进程,从do_exit函数不会返回到调用它的函数

Reference: Chapter 1 to chapter  3,  Linux kernel development.3rd.Edition

kernel笔记——内核编译与进程管理相关推荐

  1. linux 进程管理 ppt,Linux内核结构与进程管理.ppt

    Linux内核结构与进程管理.ppt Linux 内核结构与进程管理,Linux系统结构Linux kernel 开放源代码的linux操作系统内核,目前版本为2.6,Linux内核组成1. 进程调度 ...

  2. Linux内核学习008——进程管理(四)

    Linux内核学习007--进程管理(四) 进程家族树 Unix系统的进程之间存在一个明显的继承关系,所有的进程都是PID为1的init进程的后代.内核在系统启动的最后阶段启动init进程,然后ini ...

  3. 《Linux内核设计与实现》读书笔记 第三章 进程管理

    第三章进程管理 进程是Unix操作系统抽象概念中最基本的一种.我们拥有操作系统就是为了运行用户程序,因此,进程管理就是所有操作系统的心脏所在. 3.1进程 概念: 进程:处于执行期的程序.但不仅局限于 ...

  4. 操作系统学习笔记 第二章:进程管理(王道考研)

    本文章基于 2019 王道考研 操作系统 考试复习推荐资料:操作系统复习总结 - 百度文库 (baidu.com) 需要相关电子书的可以关注我的公众号BaretH后台回复操作系统 第一章:操作系统概述 ...

  5. Linux学习笔记 --网络配置及进程管理

    目录 网络配置 ☆☆☆☆指定服务器 IP 设置主机名和 hosts 映射 主机名解析过程分析(Hosts.DNS) ☆☆☆进程管理 ps 父子进程 终止进程 kill.killall ☆☆☆服务管理 ...

  6. Linux内核机制总结进程管理之SMP调度(六)

    文章目录 1 SMP调度 1.1 进程的cpu亲和性 1.2 对调度器的拓展 1.3 期限调度类的cpu负载均衡 1.4 实时调度类的cpu负载均衡 1.5 公平调度类的cpu负载均衡 1.6 迁移线 ...

  7. linux内核——3_(进程管理)系统的进程管理

    作者:GWD 时间:2019.7.28 一.系统的进程的运转方式 1.系统时间:(jiffies系统滴答):CPU内部有一个RTC,会在上电的时候调用mktime函数算出从1970年1月1日0时开始到 ...

  8. UNIX环境编程学习笔记(19)——进程管理之fork 函数的深入学习

    在"进程控制三部曲"中,我们学习到了 fork 是三部曲的第一部,用于创建一个新进程.但是关于 fork 的更深入的一些的东西我们还没有涉及到,例如,fork 创建的新进程与调用进 ...

  9. UNIX环境编程学习笔记(21)——进程管理之获取进程终止状态的 wait 和 waitpid 函数...

    lienhua34 2014-10-12 当一个进程正常或者异常终止时,内核就向其父进程发送 SIGCHLD信号.父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用的函数(信号处理程序).对于 ...

最新文章

  1. Oracle 11g Release 1 (11.1) 游标——显式游标
  2. SQL 获取数据IP,ServerName,ClientIPAddress
  3. 如何在Java地毯下有效地清除问题
  4. SpringMVC 入门教程
  5. 微信端支付宝支付,iframe改造,解决微信中无法使用支付宝付款和弹出“长按地址在浏览器中打开”...
  6. 构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下后篇)—减少不必要...
  7. vc2008工程转vc2005
  8. 高考数学47分学计算机,从57分到高考数学131分,4个月的时间我竟创造了这个传奇!...
  9. 关于加油站GPS坐标所想到的解决办法
  10. 解决出现Creating mailbox file: File exists问题,并分析出错原因
  11. APP稳定性测试工具fastbot(字节开源项目)
  12. #649 (Div. 2)D. Ehab‘s Last Corollary
  13. BRINSON理论 - 投资组合表现的决定因素
  14. github优秀项目源码汇总---Android
  15. rk3568can设置异常
  16. VS2017使用点滴
  17. 基于python的时间序列分析_用Python进行时间序列分析的一些入门操作
  18. 求伯君 QIU BOJUN 挑战微软
  19. 安装redhat linux 7 64位
  20. 木桶原则(计算机,木桶法则

热门文章

  1. CSS Media媒体查询
  2. Node.js 中 source map 使用问题总结
  3. vue.js快速入门
  4. 第二组视频:MySQL复制
  5. 神经网络预测模型算法_MATLAB Elman神经网络的数据预测—电力负荷预测模型研究...
  6. 360浏览器急速模式_国产平台:360安全浏览器扩展使用教程
  7. HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID
  8. vue、cnpm不是内部文件_vue文件通过cnpm install后无法用npm run serve打开
  9. windows10(64bit)上安装mysql(详细步骤)
  10. 在你休息时,你的大脑运动皮层中重放习得的神经放电序列