Linux基本概念


在学习Linux的过程中,总有一些基本的概念困扰着我,比如,什么是内核?控制台,Shell程序和内核的关系是怎么样的?这次主要通过度娘和Google把这些不太清楚的概念归纳了一下,具体如下: 

1 Linux 体系结构 (图太大,按列分割成2块了)

 

\

\

2 Linux内核

\

2.1内核基本功能

· 内存管理

\

· 进程管理

进程调度,IPC

进程4要素

程序 PCB 地址空间 系统堆栈空间

PCB:进程创建时内核为其分配的一个核心数据结构,进程自身不能直接存取。

系统堆栈空间:进程运行在核心态时使用的堆栈,和PCB连在一起,共8KB,其中PCB约占1000字节,系统堆栈空间约占7200字节。

2.2 内核中linux进程个数有最大值限制(4092)。但2.4以后,系统中的进程个数受限于系统的物理内存数,即限定所有进程的PCB及系统堆栈(8K)占用的空间≤1/2的物理内存总和。例64M内存:进程数≤64M/2/8K=4K

· 硬件管理

设备驱动程序, ttyS (字符设备),sda (块设备),网络

· 文件系统管理

虚拟文件系统

2.2 启动流程

1) 从BIOS到KERNEL

MBR->KERNEL->KERNEL自解压->内核初始化->内核启动(start_kernel函数,在linux内核源代码树的/usr/src/linux/init/main.c中)

2) 内核启动:创建1#进程并执行,由它创建若干内核线程(kernelthread),然后装入并执

行程序/sbin/init(变成一个用户进程)。此后,init根据/etc/inittab配置文件来执行相应的脚本进行系统初始化,如设置键盘、字体,装载模块,设置网络等

对于Redhat来说,执行的顺序为:
/etc/rc.d/rc.sysinit # 由init执行的第一个脚本
/etc/rc.d/rc $RUNLEVEL # $RUNLEVEL为缺省的运行模式

/etc/rc.d/rc.local #运行模式2、3、5时会运行的脚本

/sbin/mingetty(或getty) # 等待用户登录

/etc/inittab中指定了系统的运行级别(RUNLEVEL),init根据运行级别启动相关的服务(一些后台进程),实现不同的功能。

RUNLEVEL:0-6

0:halt, 1:单用户,2:多用户,3:多用户并启动NFS服务

4:保留,5:运行xdm(Xwindow)以图形界面方式登录

6:reboot

2.3 用户登录流程

\

2.4 Linux 内核空间和用户空间

Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的空间分为两部分。将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。

Linux使用两级保护机制:0级供内核使用,3级供用户程序使用。从图中可以看出(这里无法表示图),每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可见的。最高的1GB字节虚拟内核空间则为所有进程以及内核所共享。

内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。不管是内核空间还是用户空间,它们都处于虚拟空间中。 虽然内核空间占据了每个虚拟空间中的最高1GB字节,但映射到物理内存却总是从最低地址(0x00000000)开始。对内核空间来说,其地址映射是很简单的线性映射,0xC0000000就是物理地址与线性地址之间的位移量,在Linux代码中就叫做PAGE_OFFSET。

内核空间可以访问所有的CPU指令和所有的内存空间、I/O空间。

用户空间只能访问有限的资源,若需要特殊权限,可以通过系统调用获取相应的资源。

用户空间允许页面中断,而内核空间则不允许。

内核空间和用户空间是针对线性地址空间的。

所有内核进(线)程共用一个地址空间,而用户进程都有各自的地址空间。

用户空间和内核空间之间的数据移动:

access_ok

检查用户空间内存指针的有效性

get_user

从用户空间获取一个简单变量

put_user

输入一个简单变量到用户空间

clear_user

清除用户空间中的一个块,或者将其归零。

copy_to_user

将一个数据块从内核复制到用户空间

copy_from_user

将一个数据块从用户空间复制到内核

strnlen_user

获取内存空间中字符串缓冲区的大小

strncpy_from_user

从用户空间复制一个字符串到内核

 

\

2.5 Linux内核态和用户态

当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。

2.6 Linux内核线程,轻量级进程,用户线程

内核线程

内核线程就是内核的分身,一个分身可以处理一件特定事情。这在处理异步事件如异步IO时特别有用。内核线程的使用是廉价的,唯一使用的资源就是内核栈和上下文切换时保存寄存器的空间。支持多线程的内核叫做多线程内核(Multi-Threadskernel )。

内核经常需要在后台执行一些操作。这种任务可以通过内核线程(kernel thread)完成。内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,(实际它的mm指针被设置为NULL)内核线程只在内核空间运行,从来不切换到用户空间去。内核进程和普通进程一样,可以被调度,也可以被抢占内核线程也只能由其他内核线程创建。在现有内核线程中创建一个新的内核线程的方法如下:

Int kernel_thread(int(*fn)(void *),void *arg, unsigned long flags)

新的任务也是通过向普通的clone()系统调用传递特定的flags参数而创建的。在上面的函数返回时,返回一个指向子线程task_struct的指针。子线程开始运行fn指向的函数,arg是运行时需要用到的参数。一般情况下,内核线程会将它在创建时得到的函数永远执行下去(除非系统重启)。改函数通常由一个循环构成,在需要的时候,这个内核线程就会被唤醒和执行吗,完成了当前任务,它会自行休眠。

从内核的角度来说,它并没有线程这个概念。Linux把所有线程都当做进程来实现。内核并没有准备特别的调度算法或者定义特别的数据结构来表示线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯一属于自己的task_struct,所以在内核中,它看起来就像是一个普通的进程(只是该进程和其他一些进程共享某些资源,如地址空间。

当Linux操作系统启动以后,尤其是X window也启动以后,可以用”ps -ef”命令查看系统中的进程,这时会发现很多以”d”结尾的进程名,确切说名称显示里面加 "[]"的,这些进程就是内核线程。系统的启动是从硬件->内核->用户态进程的,pid的分配是一个往前的循环的过程,所以随系统启动的内核线程的pid往往很小。

PID TTY STAT TIMECOMMAND

2 1? S 0:01 init [3]

2 3? SN 0:00 [ksoftirqd/0]

2 5? SN 0:00 [ksoftirqd/1]

2 6? S< 0:00 [events/0]

2 7? S< 0:00 [events/1]

2 8? S< 0:00 [khelper]

2 9? S< 0:00 [kblockd/0]

2 10? S< 0:00 [kblockd/1]

2 11? S 0:00 [khubd]

2 35? S 0:42 [pdflush]

2 36? S 0:02 [pdflush]

2 38? S< 0:00 [aio/0]

2 39? S< 0:00 [aio/1]

2 37? S 0:19 [kswapd0]

2 112? S 0:00 [kseriod]

2 177? S 0:00 [scsi_eh_0]

2 178? S 0:00 [ahc_dv_0]

2 188? S 0:00 [scsi_eh_1]

2 189? S 0:00 [ahc_dv_1]

2 196? S 2:31 [kjournald]

2 1277? S 0:00 [kjournald]

2 1745? Ss 0:02 syslogd -m 0

2 1749? Ss 0:00 klogd -x

2 1958? Ss 0:13 /usr/sbin/sshd

2 2060? Ss 0:00 crond

2 2135tty2 Ss+ 0:00 /sbin/mingetty tty2

2 2136tty3 Ss+ 0:00 /sbin/mingetty tty3

2 2137tty4 Ss+ 0:00 /sbin/mingetty tty4

2 2138tty5 Ss+ 0:00 /sbin/mingetty tty5

2 2139tty6 Ss+ 0:00 /sbin/mingetty tty6

2 23564? S 0:00 bash

2 25605? Ss 0:00 sshd: peter [priv]

2 25607? S 0:00 sshd: peter@pts/2

轻量级进程(LWP)

轻量级线程(LWP)是一种由内核支持的用户线程。它是基于内核线程的高级抽象,因此只有先支持内核线程,才能有LWP。每一个进程有一个或多个LWPs,每个LWP由一个内核线程支持。这种模型实际上就是恐龙书上所提到的一对一线程模型。在这种实现的操作系统中,LWP就是用户线程。

由于每个LWP都与一个特定的内核线程关联,因此每个LWP都是一个独立的线程调度单元。即使有一个LWP在系统调用中阻塞,也不会影响整个进程的执行。

轻量级进程具有局限性。首先,大多数LWP的操作,如建立、析构以及同步,都需要进行系统调用。系统调用的代价相对较高:需要在usermode和kernel mode中切换。其次,每个LWP都需要有一个内核线程支持,因此LWP要消耗内核资源(内核线程的栈空间)。因此一个系统不能支持大量的LWP。

\

用户线程

用户线程指的是完全建立在用户空间的线程库,用户线程的建立,同步,销毁,调度完全在用户空间完成,不需要内核的帮助。因此这种线程的操作是极其快速的且低消耗的。

上图是最初的一个用户线程模型,从中可以看出,进程中包含线程,用户线程在用户空间中实现,内核并没有直接对用户线程进程调度,内核的调度对象和传统进程一样,还是进程本身,内核并不知道用户线程的存在。用户线程之间的调度由在用户空间实现的线程库实现。

这种模型对应着恐龙书中提到的多对一线程模型,其缺点是一个用户线程如果阻塞在系统调用中,则整个进程都将会阻塞。

\

 

加强版的用户线程——用户线程+LWP

\

 

3 GNU实用程序

3.1核心实用程序

GNU coreutils

3.2 Shell工作原理

Shell的基本功能是解释并执行用户打入的各种命令,实现用户与Linux核心的接口。系统初启后,核心为每个终端用户建立一个进程去执行Shell解释程序。它的执行过程基本上按如下步骤:

(1)读取用户由键盘输入的命令行。

(2)分析命令,以命令名作为文件名,并将其它参数改造为系统调用execve( )内部处理所要求的形式。

(3)终端进程调用fork( )建立一个子进程。

(4)终端进程本身用系统调用wait4( )来等待子进程完成(如果是后台命令,则不等待)。当子进程运行时调用execve(),子进程根据文件名(即命令名)到目录中查找有关文件(这是命令解释程序构成的文件),将它调入内存,执行这个程序(解释这条命令)。

(5)如果命令末尾有&号(后台命令符号),则终端进程不用系统调用wait4( )等待,立即发提示符,让用户输入下一个命令,转⑴。如果命令末尾没有&号,则终端进程要一直等待,当子进程(即运行命令的进程)完成处理后终止,向父进程(终端进程)报告,此时终端进程醒来,在做必要的判别等工作后,终端进程发提示符,让用户输入新的命令,重复上述处理过程。

4 终端,控制台

最初的计算机由于价格昂贵,因此,一台计算机一般是由多个人同时使用的。在这种情况下一台计算机需要连接上许多套键盘和显示器来供多个人使用。在以前专门有这种可以连上一台电脑的设备,只有显示器和键盘,还有简单的处理电路,本身不具有处理计算机信息的能力,他是负责连接到一台正常的计算 机上(通常是通过串口),然后登陆计算机,并对该计算机进行操作。当然,那时候的计算机操作系统都是多任务多用户的操作系统。这样一台只有显示器和键盘能够通过串口连接到计算机 的设备就叫做终端。

而控制台又是什么回事呢?在计算机里,把那套直接连接在电脑上的键盘和显示器就叫做控制台。请注意它和终端的区别,终端是通过串口连接上的,不是计算机本身就有的设备,而控制台是计算机本身就有的设备,一个计算机只有一个控制台。计算机启动的时候,所有的信息都会显示到控制台上,而不会显示到终端上。也就是说,控制台是计算机的基本设备,而终端是附加设备。当然,由于控制台也有终端一样的功能,控制台有时候也被模糊的统称为终端。 计算机操作系统中,与终端不相关的信息,比如内核消息,后台服务消息,都可以显示到控制台上,但不会显示到终端上。

现在由于计算机硬件越来越便宜,通常都是一个人独占一台计算机超做,不再连接以前那种真正意义上的“终端设备了”,因此,终端和控制台的概念也慢慢演化了。终端和控制台由硬件的概念,演化成了软件的概念。现在说的终端,比如linux中的虚拟终端,都是软件的概念,他用计算机的软件来模拟以前硬件的方式。比如在linux中,你用 alt+f1 ~ f6 可以切换六个虚拟终端,就好比是以前多人公用的计算机中的六个终端设备,这就是为什么这个叫“虚拟终端”的原因。当然,现在的linux也可以通过串口线,连接一个真正的终端。

简单的说,能直接显示系统消息的那个终端称为控制台,其他的则称为终端。

参考:

【Linux命令行和shell脚本编程宝典】

【Linux内核结构和进程管理.ppt】(找不到作者是谁,应该是浙大的一位老师)

http://blog.csdn.net/zhangskd/article/details/6956638

http://www.ibm.com/developerworks/cn/linux/l-kernel-memory-access/

http://blog.csdn.net/ylyuanlu/article/details/9115073

http://blog.csdn.net/sailor_8318/article/details/2613107

http://blog.csdn.net/yeyuangen/article/details/6858062

http://blog.csdn.net/caomiao2006/article/details/8791775

相关内容