内核初识(1)

  1. 1.1Unxi系统业务已经演化成一个具有相似应用程序编程接口(API),并且基于相似设计理念的操作系统家族,但是它本身是一个别具特色的操作系统,从萌芽到现在已经有五十余年的历史。
    Unix是从贝尔实验室的一个失败的多用户操作系统Multics中诞生的额,1969年的夏天,贝尔实验室的程序员设计了一个文件系统原型,而这个原型最终演化成unix,1973年用c进行重写,给后来的unix系统的广泛移植铺平了道路(V6版本)
    Unix仅仅提供几百个系统调用并且有一个非常明确的设计目的。 在unix中所有的东西都被当作文件来对待。
    Unix的内核和相关的系统工具软件都说纯c构成的 Unix的进程创建非常迅速,并且有一个非常独特的fork()系统调用
    策略和机制分离的设计理念,确保了unix系统具备清晰的层次化结构
    如今的unix已经发展成为一个支持抢占式多任务,多线程,虚拟内存,换页,动态链接和TCP/IP网络的现代化操作系统。
    1.2 1991年,Linux Torvalds 为当时新推出的,使用Intel 80386微处理器的计算机开发出来的一款全新的操作系统,Linux由此诞生。设计初衷是Linus这个人热衷于Minix,一种教学用的廉价的Unix,但是不能修改和发布该系统的源代码所以后续诞生了Linux。
    Linux没有 抛弃unix的设计目标并且保证了应用程序编程接口的一致。
    一般情况Linux包括:内核,c库,工具集和系统的基本工具但是主要还是指内核。
    Linux的用户界面是操作系统的外在表象,内核才是操作系统的内在核心。系统其他部分必须依靠内核这部分软件提供的服务,像管理硬件设备,分配系统资源等等,内核有时候被称作管理者和操作系统核心。
    内核是由负责响应中断的中断服务程序,负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间的内存管理程序和网络,进程间通信等系统服务程序共同组成。
    1.3 对于提供保护机制的现代系统来说,内核独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限。这种系统态和被保护起来的内存空间被统称为内核空间。
    当内核运行时,系统以内核态进入内核空间执行,而执行一个普通用户程序时,系统将以用户态进入以用户空间执行。
    当一个应用程序执行一条系统调用,我们说内核正在代其执行。如果进一步解释,在这种情况下,应用程序被称为通过系统调用在内核空间执行,而内核被称为运行于进程的上下文当中。
    这种交互关系就是上层应用程序完成其工作的基本行为方式 进程的上下文时内核代替应用程序执行的一段上下文,属于内核空间。应用调用
    syscall,睡眠,内核被唤起执行app请求的内容,执行完毕返回应用层。
    内核也负责管理硬件设备。现在所有的体系结构都提供了中断机制,当硬件设备想和系统通信的时候,他首先要发出一个异步的中断信号区打断处理器的执行,继而打断内核的执行。中断通常对应的一个中断号,内核通过这个中断号查找相应的中断服务程序。并且调用这个程序响应和处理中断。
    许多操作系统的中断服务程序,都不在进程的上下文中执行,他在一个与所有进程都无关的,专门的中断上下文中运行。
    我们可以将每个处理器在任何指定时间点上的活动必然概括为下列三者之一: 运行于用户空间,执行用户进程。
    运行于内核空间,处于进程上下文,代表某个特定的进程执行 运行于内核空间,处于中断上下文,与任何进程无关,处理某个特定的中断
    Cpu必然处于两种状态用户态和内核态
    1.4由于所有的unix都是同宗同源,并且提供相同的API,Unix的内核几乎毫无意外的都是一个不可分割的静态可执行库,也就是说他们必须以巨大的单独的可执行块的形式在一个单独的地址空间中运行。
    内核分为两个阵营:单内核和微内核(第三阵营是外内核,主要用于科研系统中)
    1980年前所有的内核设计都是单内核,单内核就是把它从一个整体作为一个单独的大过程来实现,同时也运行在一个单独的地址空间上,这样内核通常以单个静态二进制文件的形式存放于磁盘中.
    内核间是我通信是微不足道的,因此大家都运行在内核态并且同处于同一的地址空间,内核可以直接调用函数。
    这种单内核模式的支持着认为单模块具有简单和性能高的特点,大多数unix系统都设计为单模块。
    微内核并不作为一个单独的大过程来实现,相反,微内核的功能被划分为多个独立的过程,每个过程叫做一个服务器。
    所有的服务器都保持独立并运行在各自的地址空间上,因此就不可能像单模块内核那样直接调用函数,而是通过消息传递处理微内核通信:系统采用了进程间通信(IPC)机制,因此各个服务器之间通过ipc机制互通消息,互换“服务”。
    服务器的各自独立有效的避免了一个服务器的失效影响另一个,同样,模块化的系统允许一个服务器为另一个服务器而唤出。
    Linux是一个单内核也就是运行于单独的内核地址空间上,不过Linux汲取了微内核的精华,比如模块化设计,抢占式内核,支持内核线程以及动态装载内核模块的能力。
    Linux支持动态加载内核模块。虽然Linux是单内核但是允许在需要的时候动态的卸除和加载部分内核代码。
    Linux支持对称多处理(SMP)机制,传统的Unix并不支持这种机制 Linux的内核可以抢占
    Linux对线程支持的实现比较有意思:内核并不区分线程和其他的一般进程。所有的进程都一样只不过是其中之一的一些共享资源而已。
    Linux提供具有设备类的面向对象的设备模型,热插拔事件,以及用户空间的设备文件系统
    1.5 linux的内核有两种:稳定的和处于开发中的,稳定的内核具有工业级的强度 版本号为2.6.30.1的内核,2是主版本号,6是从版本号,26是修订版本号,1是指稳定版本号。
    2.1 在内核社区中,补丁是通用语,你可以以补丁的形式发布对代码的修改,也可以以补丁的形式接收其他人所做的修改
    2.2内核源码树的根目录描述 Block :块设备I/O层 Drivers:设备驱动程序 Fs:VFS和各种文件系统 Include:内核头文件 Kernel:像调度程序这样的核心子系统 Scripts:编译内核所用的脚本 COPYING文件是内核许可证
    GREADITS:开发了很多内核代码的开发者列表 MAINTAINERS:是维护者列表
    2.3配置内核 比如对称多任务处理器(SMP)的配置选项为CONFIG_SMP,如果设置了该选项,则SMP启用否则则是不启用 $ make config这个是基于总的 $ make menuconfig 这个是基于图形界面的 $make gconfig
    这个是基于gtk工具的 $make defcongig 这个是基于你的pathloss
    2.6之后每一次编译内核之间都不用再运行make deep了代码之间的依赖关系会自动维护,也不需要独立的编译某个模块,makefile会完成这一切。 减少编译的垃圾信息
    如果你想尽量少的看到垃圾信息但是也想看到错误报告和警告信息,可以用以下命令进行输出重定向: m a k e > . . / d e t r i t u s 一旦需要查看这些信息可以查看这些文件但是这长不看,可以 make >../detritus 一旦需要查看这些信息可以查看这些文件但是这长不看,可以 make>../detritus一旦需要查看这些信息可以查看这些文件但是这长不看,可以make >/dev/null 衍生多个编译作业 Make
    程序能把编译过程拆分成多个并行的作业。其中的每个作业独立兵法的运行,这有助于极大的加快多处理器系统上的编译过程,也有利于改善处理器的利用率。makefile经常会出现不正确的依赖信息。对于不正确的依赖,多个作业可能会互相踩踏,导致编译过程报错。当然,内核的Makefile没有这样的编码错误,所以编译衍生出来的多个作业不会出现失败,多个作业进行内核编译可以使用
    $make jn 安装新内核 怎么安装新内核就和体系结构以及启动引导工具(boot loader)息息相关 Make
    modules_install 就可以把所有已编译的模块安装到正确的主目录/lib/modules下。
    编译时也会在内核代码树的根目录下创建一个System.map文件。这是一份符号对照表,用以将内核符号和他们的起始地址对应起来。
    2.4 内核开发的特点 内核编程时既不能访问c库也不能访问标准的c头文件。 内核编程时必须使用GNU C 内核编程时难以执行浮点运算 内核编程时缺乏像用户空间那样的内存保护机制。 内核给每个进程只有一个很小的定长堆栈
    由于内核支持异步中断,抢占和smp,因此必须时刻注意同步和并发。 要考虑移植性的重要性 头文件
    大部分常用的c库函数在内核中都已经得到实现 基本的头文件位于内核源码树顶级目录下的include目录中
    体系结构相关的头文件位于内核源代码树的arch//include/asm目录下。
    Sysloged会根据这个优先级标志来决定在什么地方显示这条系统消息。 GNU C
    像所有姿势清高的unix内核一样,Linux的内核都是靠c来写的,但是并不符合ansi c标准,内核开发者使用的c语音涵盖了ISO
    C99标准和GUN C的扩展特性
    1.内联函数 C99和GUN c都支持内联函数,inline这个名称就可以反映出它的工作方式,函数会在它所调用的位置上展开。这样做可以消除函数调用和返回所带来的开销。不好的地方在于这样代码会更长,这也意味着占用更多的内存空间或者占用更多的指令缓存
    内核开发者通常把那些对时间要求比较高的,而本身长度比较短的函数定义成内联函数
    定义成一个内联函数的时候,需要static作为关键字,并且用inline限定它。必须同时使用static 和 inline static
    inlune void wolf(unsigned long tail_size)
    内联函数必须在使用之前就在头文件中定义好,否则编译器没办法把这个函数展开,而且为了类型安全和易读性,在内核中优先使用内联函数而不是复杂的宏。
    2.内联汇编 Gcc编译器支持在c函数中嵌入汇编指令 用asm()指令嵌入汇编代码 Linux内核混合使用了c和汇编,在偏进体系结构的底层或对执行时间要求严格的地方,一般是汇编,其他部分大部分都是c
    3.分支声明 对于选择条件语句,在一个条件很少出现,或者另一个条件经常出现的时候,编译器可以根据这条指令进行优化,内核把这个指令封装成了宏,比如likely(),unlikely()
    没有内存保护机制
    如果一个用户试图进行一次非法的内存访问,内核就会发现这个错误,发送SIGSEGV信号并且结束整个进程,但是内核自己非法访问内存就没办法控制会导致oops。在内核中不应该去访问非法的内存地址,引用空指针之类的事情,否则它可能会死掉,缺根本不告诉你在内核里风险常常会比外面大一些。
    用户执行一次浮点运算,内核竟然要陷入陷阱进行处理,步骤很多并且不能完美的支持浮点操作,不到万不得以千万别这么做。 容积小而固定的栈
    用户空间的程序可以从栈上分配大量的空间来存储变量,用户空间的栈本身比较大,而且还能动态的增长。
    历史上来说,内核栈的大小是两页。在x86上 栈的大小在编译的时候配置,可以是4kb也可以是8kb. 同步和并发
    内核很容易产生竞争条件,和单线程的用户空间不同,内核的许多特性都要求能够并发的访问共享数据,这就要求有同步机制以保证不出现竞争条件
    Linux是抢占多任务操作系统 Linux内核支持对称多处理器系统 中断说异步到来的,完全不顾及当前正在执行的代码
    Linux内核可以抢占,就是不加以保护的话,内核中正在执行的代码可能会被另一段代码抢占。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值