Linux内核入门(一)——体系架构

Linux是一套免费使用和自由传播的类Unix操作系统,它最先用于基于x86系列CPU的计算机上。这个系统是由世界各地的成千上万的程序员设计和实现的。其目的是建立不受任何商品化软件的版权制约的、全世界都能自由使用的Unix兼容产品。

我们不去介绍操作系统的历史了,也不管操作系统这门学科上对操作系统的分类了,闲话少说,Linux操作系统只是一个非常新的操作系统。它不拘泥于某种特定的操作系统类型,从内核上讲,它是一个分时操作系统,但又具备实时操作系统的特性;从体系上讲,它是一个单内核操作系统,但又具备模块化的微内核特征;它支持各种网际协议,所以又是一个网络操作系统;它支持大规模集群、网格计算,甚至现在还有人在它上面架设云计算、云存储等环境,所以它又是一个分布式操作系统……

不管怎么说,Linux的开源性质决定了世界上各式各样的人可以按照自己的需求去发展它、完善它,于是乎Linux就具备了高性能、高可用、可扩展、可移植等多种特性。

当今IT业界,小到嵌入式、手机、PC机,大到大规模集群、网格、云,都能看到Linux的身影。本人写一系列疯狂Linux内核博文的目的,就是让广大的中国同胞了解到这一伟大操作系统的内部真实面貌,让你感受到它为什么伟大。

Linux是一个操作系统,也是一个软件。既然一个软件,肯定就要遵循所有软件的特点,那就是其本质=算法+数据结构+文档。本文就从他的架构入手,一步步进入其内部。

1 Linux体系结构

 

 

上面就是一幅我认为还比较完美的Linux架构图。从图中我们可以看见,用户使用到的应用程序,最终会通过中断的形式访问内核。详细一点描述就是:应用程序向内核发出系统调用这一特殊中断,随后包含该程序的进程又用户态进入内核态,就可以访问内核提供的各式各样的函数和数据结构了。更具体的描述我们随后再细说,先来介绍一些概念吧:

“文件”和“进程”是Linux内核中的两个最基本实体和中心概念,Linux系统的所有操作都是以这两者为基础的。整个系统核心由以下五个部分组成:
① 虚拟文件系统:文件管理和磁盘高速缓存管理(节点和空间管理)
② I/O设备管理:块设备驱动(随机存取设备)、原始设备(raw设备,字符设备,裸设备)
③ 进程控制:进程的调度、同步和通信
④ 存储管理:在主存与CPU二级存储之间对程序进行搬迁
⑤ 网际协议栈:实现各式各样的网络协议。

 

2 一般程序的执行

 

一个进程在执行系统调用exec期间(exec("命令名",参数)),就把可执行文件装入本进程的三个区域中:
      ·正文区:对应可执行文件的正文段
      ·数据区:对应可执行文件的数据标识段
      ·堆栈区:新建立的进程工作区

堆栈是一个重要的概念,其主要用于传递参数,保护现场,存放返回地址以及为局部动态变量提供存储区。我们后面的博文将会重点讨论这个,因为堆栈这个东西太重要了。

 

进程在内核态下运行时的工作区为内核栈,在用户态下运行时的工作区为用户栈。内核栈和用户栈不能交叉使用。

来,我们来看一个程序,用户在标准终端上敲入:copy oldfile newfile。此处,oldfile 是一个现存文件名,而 newfile 是一个新文件名。有:(其中,变量version是初始化数据;数组buffer是未初始化的数据)

 

#include
char buffer[2048];
int version=1;

main(int argc, char *argv[])   /*系统引用main时需要提供argc作为表argv中的 */
{                              /*参数,并且对数组argv的每个成员赋初值,   */
      int fdold, fdnew;        /*对照命令:argv[0]指向字符串copy;        */
      if(argc != 3)            /*argv[1]指向字符串oldfile;               */
      {                        /*argv[2]指向字符串newfile;               */
            printf(“need 2 arguments for copy program/n”);
            exit(1);
      }
      fdold = open(argv[1], O_RDONLY);  /* 打开源文件只读 */
      if (fdold == -1)
      {
            printf(“cannot open file %s/n”, argv[1]);
            exit(1);
      }
      fdnew = creat(argv[2], 0666);     /* 创建可为所有用户读写的目标文件 */
      if(fdnew == -1)
      {
            printf(“cannot create file %s/n”, argv[2]);
            exit(1);
      }
      copy(fdold, fdnew);
      exit(0);
}
copy(int old, int new)
{
      int count;
      while((count = read(old, buffer, sizeof(buffer))) > 0)
            write(new, buffer, count);
}

 

当main被调用时,main中的参数argc和argv、变量fdold、fdnew及相关函数地址信息就会被压栈;并且无论何时,遇到下一个函数(本例中是 copy 函数),其参数和变量以及相关地址也会被压栈:(假设程序不进入三个IF程序段中的堆栈过程,其实IF后也有个压栈的过程,我们省略了,但千万别以为没有)

 

 

 

我们看到:Linux的进程工作在两种状态——内核态(kernel mode)和用户态(user mode)。 所以,Linux系统的内核栈和用户栈是分开的。用户栈保存的是程序中的一般函数和系统调用函数相关信息,对用户是可见的; 内核栈保存的是内核中的函数或数据,如getblk函数等,对用户是透明的。

那么,程序什么时候使用用户栈,什么时候使用内核栈呢?且听下回分解。

你可能感兴趣的:(疯狂内核预备知识)