分类:
2013-01-05 23:32:38
严格意义上,操作系统也是一种软件,它控制计算机硬件资源,提供程序运行环境;我们称此为内核(kernel),其相对较小,位于软件运行环境的中心。
内核的接口被成为系统调用(system call)。
公用函数库构建在系统调用接口之上。
应用程序既可使用公用函数库,也可以直接使用系统调用。而 shell 是一种特殊的应用程序,为运行其他应用程序提供了一个接口。
登录
用户登录系统时,系统在口令文件(通常是 /etc/passwd)中查看登录名。
口令文件中的登录项由7个以冒号分隔的字段组成,分别是:登录名、加密口令、数值用户 ID 、数值组 ID、注释字段、起始目录(/home/xxx)以及shell程序(/bin/xxsh)。
当然,也有系统将加密口令移到另一个文件中,并提供相应的访问函数。
shell
用户登录后,系统会启动一个 shell 程序,使用户可以键入命令。shell 是一个命令行解释器,读取输入,然后执行命令。用户可以用终端(交互式 shell),或通过文件(shell 脚本)进行输入。
系统常见的 shell 有:Bourne shell(/bin/sh)、Bourne-again shell(/bin/bash)、C shell(/bin/csh)、Korn shell(/bin/ksh)、Tenex C shell(/bin/tcsh)。其中,Bourne-again shell 是 GUN shell ,所有 Linux 系统都提供这种 shell ,其被设计成遵循 POSIX 。
系统从口令文件中相应用户登录项的最后一个字段(shell 程序)中了解到为该用户执行的 shell 。
文件系统
UNIX文件系统是目录和文件组成的层次结构,目录的起点为根(root),其名字是字符 / ;目录(directory)是一个包含许多目录项的文件,每个目录项都包含一个文件名,同时还包含说明该文件属性的信息。
文件属性是指文件类型(普通股文件还是目录)、文件大小、文件所有者、文件权限以及文件最后的修改时间等。stat 和 fstat 函数返回包含所有文件属性的信息结构。不过,目录项的逻辑视图和实际存放在磁盘的方式是不同的,文件系统的大多数实现并不在目录项中存放属性。
文件名中不能出现的字符有斜线(/)和空操作符(null)两个;其中斜线用来分隔构成路径名的文件名,空操作符用来终止一个路径名。而好的习惯是,只使用印刷字符的一个子集作为文件名字符;可以有效减少在 shell 由于使用了特殊字符而必须使用引号机制来引用文件名的麻烦。
目录中有两个文件名会被自动创建: . (称为点)和 .. (称为点-点)。其中 . 指当前目录, .. 指父目录;而根目录中, .. 和 .相同。
路径名是一个或多个以斜线分隔的文件名序列;以斜线开头的路径名为绝对路径名(absolute pathname),否则称为相对路径名(relative pathname)。
每个进程都有一个工作目录(working directory),也称为当前工作目录(current working directory)。相对路径名都从工作目录开始解析,可以用 chdir 函数更改其工作目录。登录时,工作目录设置为起始目录(home directory),系统在登录时从口令文件中用户的相应登录项中获取。
输入输出
文件描述符(file descriptor)是一个很小的非负整数,内核用来标识特定进程正在访问的文件。
系统运行一个新程序时, shell 都为其打开三个文件描述符:标准输入(standard input)、标准输出(standard output)和标准出错(standard error)。如果没有特殊处理,三个描述符都链向终端。STDIN_FILENO 和 STDOUT_FILENO 定义在
函数 open、read、write、lseek 和 close 提供了不用缓冲的 I/O ,这些函数在头文件
标准 I/O 函数提供了一种对不用缓冲 I/O 函数的带缓冲的接口。使用这类函数,无需担心如何选择最佳的缓冲区大小;并且简化了对输入行的处理。标准 I/O 函数中,printf 函数在头文件
程序和进程
程序(program)是存放在磁盘、处于某个目录中的可执行文件;使用6个 exec 函数中的一个将程序读入存储器,并使其执行。
程序的执行实例被称为进程(process)。每个进程都有一个唯一的数字标识符,称为进程 ID(process ID);可以调用 getpid 函数得到进程ID。有三个用于进程控制的主要函数:fork、exec、waitpid。
通常一个进程只有一个控制线程(thread),而同一时间只执行一组机器指令。多线程能充分利用多处理器系统的并发性。在一个进程内,所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。线程也用 ID 标识,但线程 ID 只在所属的进程内起作用。
出错处理
当 UNIX 函数出错时,尝尝返回一个负值;而整形变量 errno 通常被设置为含有附加信息的值,其中头文件
在支持线程的环境中,多个线程共享进程地址空间,每个线程都有属于自己的局部 errno ,以避免线程间的互相干扰。
函数不会(也不应当)将 errno 设置为 0;而如果没有出错,则其指不会被一个线程清除,此时返回值无意义。
strerror 函数可以将 errno 值映射为一个出错信息字符串,并返回此字符串的指针。perror 函数基于errno的当前值,在标准出错上产生一条出错信息。
出错可以分为致命性和非致命性的两类。对于致命性错误,无法执行恢复动作,只能打印出错信息或者写入日志;对于非致命性错误,有时候可以妥善处理。与资源先关的非致命性出错包括,ENGAIN、ENFILE、ENOBUFS、ENOLCK、ENOSPC、ENOSR、EWOULDBLOCK。
用户标识
用户 ID(user ID)是系统标识各个不同的用户的数值。用户 ID 为 0 的用户为根(root)或超级用户(superuser)。
用户的组 ID(group ID)是系统标识不同用户组的数值。组文件将组名映射为组 ID,通常是 /ect/group。
对于磁盘上的每个文件,文件系统都存放该文件所有者的用户 ID 和组 ID。
口令文件包含了登录名和用户 ID 之间的映射关系,而组文件包含了组名和组 ID 之间的映射关系。
调用 getuid 函数和 getgid 函数可以返回用户 ID 和组 ID。
除了在口令文件中登录名指定一个组 ID 外,大多数 UNIX 系统还允许用户属于多至16个另外的组。
用户登录时,系统读组文件,寻找列有该用户作为成员的前16个记录项就可以得到该用户的附加组 ID(supplementary group ID)。
信号
信号(signal)是通知进程已发生某种情况的一种技术。
进程处理信号有三种选择:(1)忽略信号;(2)按系统默认方式处理;(3)提供一个函数,信号发生时调用该函数,这个过程称为捕捉信号。
终端键盘上有两种产生信号的方法,分别称为中断键(interrupt key,通常是 Delete 键或 Ctrl+C)和退出键(quit key,通常是 Ctrl+\),被用来中断当前运行的进程。
调用 kill 函数,也可以产生信号,但是向一个进程发送信号时,登录用户必须是该进程的所有者或者是超级用户。
时间值
UNIX 系统一直使用两种不同的时间值:
当度量一个进程的执行时间时,UNIX 系统使用三个进程时间值:
其中,用户 CPU 时间和系统 CPU 时间之和为 CPU 时间。
要取得进程的时钟时间、用户时间和系统时间,需要执行命令 time,其参数是需要进行度量执行时间的命令。
系统调用
操作系统提供的服务入口,以便于程序向内核请求服务,这些入口点被称为系统调用。
UNIX 为每个系统调用在标准 C 库中设置一个具有相同名字的函数;用户进程用标准 C 调用序列来调用这些函数,函数用系统所要求的技术调用相应的内核服务。从应用角度考虑,可以将系统调用视为 C 函数。在这一点上将,系统调用和库函数有着一定的重叠。
但那是库函数中有很多通用函数,虽然这些函数可能调用一个或多个系统调用实现,但是并不是内核的入口点。由此可见,系统调用通常提供一种最小接口,而库函数通常提供较复杂的功能。
从实现上可以看出,必要时我们可以替换库函数,但是无法替换系统调用。