操作系统(二)——用户接口

第二章 用户接口

用户接口是用户与计算机系统交互的环境和方式。为了方便用户使用计算机系统,操作系统向用户提供了直接使用计算机系统的手段,通常称为用户接口。用户通过操作系统提供的接口与计算机系统交互,即用户通过一定的方式和途径,将自己的要求告诉计算机,而计算机根据用户不同的要求完成相应的操作和处理。
通常操作系统为用户提供两类接口。一类是系统为用户提供的各种命令控制界面接口,用户利用这些操作命令来组织和控制程序的执行或管理计算机系统。另一类接口是程序接口,编程人员在程序中通过程序接口来请求操作系统提供服务。
本章主要讨论操作系统为用户提供的命令控制界面接口和程序接口。

2.1 命令控制界面接口

在当今几乎所有的操作系统中,都向用户提供了各种联机的命令控制接口界面。用户通过输入设备(键盘、鼠标、触摸屏、声音等)发出一系列命令交互地组织和控制程序的执行或管理计算机系统。

2.1.1联机命令的类型

为了能向用户提供多方面的服务,通常操作系统都向用户提供了几十条甚至上百条的联机命令。根据这些命令所完成的功能不同,可把它们分成以下几类:
(1)系统访问。在多用户系统中,为了保证系统的安全性,都设置了系统访问命令,即注册命令Login。用户每次使用某个终端时,都须先使用该命令,使系统能识别该用户。当用户退出系统时,使用注销命令Logout退出系统。
(2)目录和文件管理。该类命令被用来管理和控制终端用户文件或目录文件。例如,复制、移动和删除某个文件或目录文件,或者显示和查找某个文件或目录。
(3)编译和链接装配。用户使用这类命令把用户输入的源程序文件编译链接成可执行程序。
(4)维护管理命令。这类命令一般为管理员使用,该类命令主要用于系统维护、开机、关机、增加和减少用户、计时收费等。
(5)通信。通信类命令在单机系统中被用来进行主机和远程终端之间的呼叫、联接以及断开等,从而在主机和远程终端之间建立会话信道。在网络系统中,通信命令除了被用来进行有关信道的呼叫、联接以及断开等之外,还进行主机和主机之间的信息发送与接收、显示等工作。
(6)其它。包括建立和查看日期、时间,修改和设置外设参数等命令。
联机控制方式使用户直接参与控制程序执行,因而大大地方便了用户。但是,在某些情况下,用户反复输入众多的命令也会感到非常烦琐或浪费了许多不必要的时间。例如,在对某个源代码文件进行编译调试之后,需要重新和多个目标代码文件链接。如果这个调试和链接不是一次成功的话(这种情况经常发生),那么,用户的控制过程将会非常单调和烦琐。显然,在这种情况下,批处理方式要优于联机控制方式。因此,在现代操作系统中,大都提供批处理方式和联机控制方式。这里,批处理方式既指传统的作业控制语言编写的作业说明书方式,也指那些把不同的交互命令按一定格式组合后的命令文件方式。

2.1.2 联机命令接口

目前,大多数操作系统提供了两种联机命令的操作方式,包括了键入式方式和选择式方式,它们针对不同的屏幕显示环境,方便用户的选择和使用。
1.键入式交互命令
键入式交互命令通常指来自控制台和终端键入的操作命令,它是一种命令行操作方式(文本行方式),操作者以字符串形式键入命令,并等待该命令的响应和执行。在单任务环境下,每次只能键入一条命令,只有当该命令功能完成后,操作者才能键入第二条命令。如果操作系统提供多命令缓冲支持,以及在多任务环境和分布式环境下的多命令支持,操作者可以连续键入若干条命令,不必等待每条指令的执行。对于键入式命令,操作者必须记住其命令名、字符串形式及其命令行参数,并须将其在键盘上一一敲入,这是键入式命令的缺点
这种命令行操作方式是一种简捷的命令语言,适合于有经验的用户,大多数操作系统都具有这样的命令语言。例如,著名的Linux中的命令就是一种文本行式命令语言,它对于熟悉它的用户真可为得心应手。
在当今几乎所有的计算机操作系统中,都向用户提供了键入式交互命令。用户需要操作系统提供服务时,先在终端的键盘上打入所需的命令,由终端处理程序接收该命令,将用户键入的字符放入缓冲,同时提供字符编辑并显示在终端屏幕上,以便用户查看。当一条命令输入完成后,命令解释程序对命令进行分析,然后执行相应的处理程序。
在所有的操作系统中,都把命令解释程序放在操作系统的最高层,以便能直接与用户交互。命令解释程序通常按两种方法解释执行输入的命令。一种方法是由命令解释程序查找命令表而得到该命令的处理程序入口地址,然后由解释程序调用相应子程序而直接执行。这一般是那些最常用的、而且子程序比较短小的命令,即我们常用的内部命令。另一种方法是为输入的命令建立一个子进程,由子进程执行对应的命令。这一般是文本编辑、程序编译以及运行各种实用程序和用户程序等命令,即命令程序较长,用到时才从外存调入内存的外部命令
2.选择式命令
选择式命令是在用户界面向可视化发展过程中引入的一种命令选择和执行方式。选择式命令不需要用户输入命令名,操作者只需根据不同的输入和选择设备选择所需的命令名,系统根据选择点击信号进入命令的解释执行,任务完成后再返回原操作环境。
在视窗环境推出后,选择式命令的方式得到了广泛的应用。视窗环境是一种面向屏幕的命令交互接口,它的主体是菜单系统,所有的系统命令、操作信息以及各种控制功能操作都出现在命令菜单中,由用户根据需要从系统提供的命令中挑选一种。这对新入门的用户非常有用,因为他们不须记住命令的名,在某些特定的应用中,如文本编辑、程序编写时最为方便。然而,菜单系统会限制用户使用命令的数量,因显示菜单而占用额外的存储空间和时间。
视窗型命令界面是当今操作系统所具有的良好的用户交互界面,是系统可视化的一个基础,所以在操作系统领域被很快推广。例如,无论是Windows系列,还是UNⅨ系列的操作系统,它们的命令控制界面都是由多窗口的按钮式图形界面组成。在这些系统中,命令已被开发成一条条能用点击方式而执行的简单的菜单或小巧的图标。而且,用户也可以在提示符的提示下用普通字符方式输入各种命令。最近,用声音控制的命令控制界面也已逐步被开发出来。可以预计,计算机系统的命令控制界面将会越来越方便和越来越人性化。

2.2 Linux系统的命令控制界面

Linux系统具有丰富的操作命令,这些命令都通过Shell提供给用户使用。Shell是Linux系统为用户提供的键盘命令和解释程序的集合。Linux通过Shell提供了300个以上的命令,由于篇幅所限,本节将介绍Linux系统的常用命令,以使读者对Linux系统命令有一个初步的了解。

2.2.1 登录Shell

用户在进入Linux系统之前,必须登录。当用户打开终端后,系统便会显示如下信息:
     login:
用户在输入用户登录名后,系统显示:
     password:
在用户输入完口令后,系统检查用户名和口令是否正确,如果正确,系统将启动该用户的Shell程序,并在屏幕上出现Shell提示符,如下所示:
     $
注意:$ 是系统默认的提示符。用户可随自己的喜好改变提示符的显示形式。然后,用户可在提示符后输入各种各样的命令,由Shell解释和执行用户的命令。当用户的一条命令执行完后,返回Shell提示符,等待用户输入下一条命令,如此循环,直到用户退出系统。
用户在完成工作之后,一般应退出系统。这样做主要是为了安全。因为,如果某个用户离开终端时没有从系统中注销,那么其它用户就能继续借助于那个没有终止的Shell使用机器,从而系统中的用户数据就有可能被破坏或失窃。从系统中注销实际上是将相应的Shell程序终止,方法是在提示符后键入Ctrl+D 或logout,或者用命令exit

2.2.2 命令句法

为了使用户的要求能被Linux系统理解,每条命令必须以正确的格式表示,或者说必须遵循命令行句法。否则,Linux系统将不能理解用户的请求。Linux系统命令以小写字母构成,注意,Linux系统区分大小写字符(这一点与Windows不同)。Linux系统的命令句法如下:

command [option] [arguments]

其中:command是用户要求系统执行的命令名称
option是选择项,用于改变命令的执行方式,一条命令可以有多个选项
arguments是命令的操作对象,它规定了命令所操作的数据

例:命令 ls -l file

要求系统以详细列表方式显示文件file的目录。其中,ls是命令名称-l是选择项file是对象

2.2.3 常用的基本命令

1.显示当前工作目录命令pwd
Linux系统大多数命令的缺省值都是表示在当前目录下对文件进行操作。用户时常需要知道自己在文件系统中所处的位置。命令pwd用于显示用户当前所在的目录。例:

> $pwd
> /home/student/txt

显示出你当前所在的工作目录。pwd以绝对路径名(以“/”开头的路径名)的形式显示当前工作目录。
2.列目录命令 ls
ls 的意义为 “list”,也就是将某一个目录内容显示出来
如果在 ls 命令后面没有跟任何的参数,它将会显示出当前目录中所包含的文件名,而不指出是文件还是目录。
也可以在 ls 后面加上所要察看的文件名称,例:

> $ ls /home/txt    
> 将显示绝对路径/home/txt下包含的内容。
>  $ ls pro1   
> 将显示当前工作目录下的子目录pro1中包含的内容。
>  $ ls *.jan           
> 将显示当前工作目录下所有扩展名为jan的文件。

在Linux系统中提供了三种文件名的通配符:,?和[…]。‘’可以和任意字符串相匹配,‘?’和文件名中单个字符匹配,‘[…]’匹配集合内的任意字符。因此,在指定文件名时可以使用通配符来简化输入。
ls 有一些特别的参数,可以给出除文件名外的有关文件的其它信息。常用的参数如下:
-a : 在 Linux 中若一个目录或文件的名字的第一个为 “.” ,则表示文件是隐含的,列目录时,这些文件一般不显示出来。使用ls -a 可显示这类文件。
-F : 该选项可显示出文件名后跟上适当的符号以指明文件的类型。可执行文件后跟一个‘*’表示;目录文件后跟一个‘/’表示;链接文件后跟一个‘@’表示,例:

> $ls –F 
> letters/  memo@  test*  notes

可以看出当前目录下包含有普通文件notes、子目录letters、链接文件memo以及执行文件test。
-l : 这个参数代表使用 ls 的长( long )格式,可以显示更多的文件信息,如文件的存取权限,文件拥有者( owner ),文件大小种类等。例:

> $ls -l
> drwx--x--x  2 student  group1  325  Nov  29  05:08  letters
>lrwx--x--x  2 student  group1  288  Aug  8   22:00  memos
> -rw-------  1 student  group1  566  Aug  10  06:28  test
> -rw-------  1 student  group1  266  Feb  12  05:28  notes

每行是一个文件的信息,每行划分成不同的段,从左到右每段分别表示文件的种类和文件的存取权限、链接的文件数、文件主名、文件所在的组、文件大小、文件的创建时间或修改时间、文件名。
每行的第1个字符指明了文件的种类:‘-’表示普通文件、‘d’目录文件、‘b’块设备文件、‘c’字符设备文件、‘l’符号链文件、‘p’管道文件。
ls可以同时带多个选项,例:

>   $ls –aF
>     .  ..  .mailc*  letters/

在Linux系统中,(.)和(..)分别表示引用的当前目录及其父目录,本例显示了两个隐含文件‘.’和‘..’,隐含的可执行文件mailc,目录文件letters。
这种多个选项的组合方法不仅适用于ls命令,也适用于多数的Linux命令,并且选项的组合数量没有限制。
3.复制文件命令cp
cp 这个指令的意义是复制copy,**也就是将一个或多个文件复制成另一个文件或者是将其复制到另一个目录去。**cp 的用法如下:

$cp f1 f2  
将文件名为 f1 的文件复制为文件名为 f2 的文件。
$cp –i f1 f2 
如果在当前目录下已有一个名为f2的文件,重写文件f2时提示是否重写文件。
$cp f1 f2 f3  dir  
将文件 f1、 f2、 f3 以相同的文件名复制一份放到目录 dir 里面。
$cp -r dir1 dir2   
将目录 dir1 的全部内容全部复制到目录 dir2 里面。

4.移动文件和更改文件名命令 mv
**mv 的意义为 move , 主要是将一文件改名或换至另一个目录。**mv 的用法如下:

$mv f1 f2       将文件名为 f1 的文件变更成文件名为 f2 的文件。 
$mv dir1 dir2     将文件名为 dir1的目录变更成文件名为 dir2 的目录。  
$mv f1 f2 f3  dir  将文件 f1 、f2 、f3 都移至目录 dir 里面。

mv 的参数有两个,-f 和 -i , 其中 -i 的意义与 cp 中的相同,均是 interactive 询问之意。而 -f 为强迫( force ) , 就是不管有没有同名的文件,反正我就是要搬过去(笑),所有其他的参数遇到 -f 均会失效。
5.删除文件命令 rm
rm 的意义是 remove ,也就是用来删除一个文件的指令在 Linux 中一个被删除的文件除非是系统恰好有做备份,否则是无法像 windows 里面一样还能够救回来的。所以在做rm 动作的时候使用者要特别小心。
rm 的格式如下:

>   $ rm f1 f2 f3   将文件f1、f2 、f3同时删除掉。

而 rm 的参数比较常用的有几个: -f , -i

  -f : 将会使得系统在删除时,不提出任何警告讯息。
  -i : 在除去文件之前均会询问是否真要删除。

6.建立目录命令mkdir
mkdir 是一个让使用者建立一个目录的指令。你可以在一个目录底下使用 midir 建立一个子目录,使用的方法如下:

 mkdir dirname1 [ dirname2 ... ]

7.改变当前工作目录命令 cd
这是让使用者用来转移工作目录用的。cd的用法如下:

cd dirname   

将目前的目录转移到 dirname 这一个目录去。或使用 “cd …” 来转移到上一层目录。
8.查看文件内容的命令 cat和more
查看一个文件最简单的方法是cat命令。cat将用户指定的文件内容全部显示在屏幕上。因此,对于较长的文件会因屏幕的滚过而无法看清。

例:$cat hello
Hello! This is a test!

more 可以将所要查看的文件内容一页页的显示出来,可根据使用者的要求换页或卷。more 的使用方法如下:

more filename
要向前翻一屏,可以按空格;向前移一行可以按回车键;如果你在使用中觉得已经看到了所要看的部份,可以按’q’离开。
9.改变文件的存取权限命令 chmod
在 Linux系统中 一个文件上有可读®、可写(w)、可执行(x)三种执行模式,分别针对该文件的拥有者( onwer )、同组者( group member)以及其他人( other )。chmod 就是用来变更一些文件的执行模式,其使用方式如下:

chmod [who] op-code permission filename

其中,[who]用于指明访问者的身份,可以是用户自己、用户组、所有其他用户及全部,分别用u、g、o和a表示;op—code是操作码,分别用**+、-及=表示增加、消除及赋予访问者以某种权利**;而permission则是分别用r、w及x表示读、写及执行许可。例:

$chmod go—w temp

表示对用户组及所有其他用户,消除他们对文件temp的写许可。
10.联机帮助命令man
用户可通过man命令来获得联机帮助,命令使用方式如下:

man  titil

显示titil 命令的使用方法。

例:man  man      显示man命令如何使用的说明。

2.2.4 重定向与管道命令

1.重定向命令
在Linux系统中,由系统定义了两个分别称为标准输入和标准输出的文件,各对应于终端键盘输入和终端屏幕输出。它们是在用户注册时,由Login程序打开的。这样,在用户程序执行时,隐含的标准输入是键盘输入,标准输出即屏幕显示。但用户程序中可能不要求从键盘输入,而是从某个指定文件上读取信息供程序使用;同样,用户可能希望把程序执行时所产生的结果数据,写到某个指定文件中而非屏幕上。这就使用户必须去改变输入与输出文件,即不使用标准输入、标准输出,而是把另外的某个指定文件或设备,作为输入或输出文件。
Shell向用户提供了这种用于改变输入、输出设备的手段,此即标准输入与标准输出的重新定向。用重定向符“<”和“>”分别表示输入转向与输出转向

例:
    $cat filel
表示将文件filel的内容,在标准输出上显示出来。
    $cat filel>file2
表示把文件filel的内容,输出到文件file2。

须指明的是,在做输出转向时,若上述的文件file2并不存在,则先创建它;若已存在,则认为它是空白的,执行上述输出转向命令时,是用命令的输出数据去重写该文件;如果文件file2事先已有内容,则命令执行结果将用文件filel的内容去更新文件file2的原有内容。现在,如果又要求把file4的内容附加到现有的文件file2的末尾,则应使用另一个输出转向符“》”。例:

$cat file4>>file2

便可在文件file2中,除了上次复制的filel内容外,后面又附加了file4的内容。当然,若想一次把两个文件filel和file4全部复制到file2中,则可用命令
$cat filel file4>>file2。
此外,也可在一个命令行中,同时改变输入与输出。例:

a.out<filel>file0/

表示,在可执行文件a.out执行时,将从文件filel中提取数据,而把a.out的执行结果数据输出到文件file0中。
2.管道命令
在有了上述的重定向思想后,为了进一步增强功能,人们又进一步把这种思想加以扩充,用符号“|“来连接两条命令,使其前一条命令的输出作为后一条命令的输入。即

   $command1|command 2
例:对于下述输入
    $cat file|WC
将使命令cat把文件file中的数据,作为WC命令的计数输入。

从概念上说,系统执行上述输入时,将建立一个作为通信通道的pipe文件。这时,cat命令的输出既不出现在终端(屏幕)上,也不存入某中间文件,而是由Linux系统来“缓冲”第一条命令的输出,并作为第二条命令的输入。在用管道线所连接的命令之间,实现单向、同步运行
其单向性表现在:只把管道线前面的命令的输出送入管道,而管道的输出数据仅供管道线后面的命令去读取
管道的同步特性则表现为:当一条管道满时,其前一条命令停止执行;而当管道空时,则其后一条命令停止运行。
除此两种情况外,用管道所连接的两条命令“同时”运行。可见,利用管道功能,可以流水线方式实现命令的流水线化,即在单一命令行下,同时运行多条命令,以加速复杂任务的完成。

2.2.5 通信命令

为实现源进程与目标进程(或用户)之间的通信,一种办法是系统为每一进程(或用户)设置一个信箱,源用户把信件投入到目标用户的信箱中去;目标用户则可在此后的任一时间,从自己的信箱中读取信件。在这种通信方式中,源和目标用户之间进行的是非交互式通信,因而也是非实时通信。但在有些办公自动化系统中,经常要求在两用户之间进行交互式会话,即源与目标用户双方必须同时联机操作。在源用户发出信息后,要求目标用户能立即收到信息并给予回答。
Linux系统为用户提供了实时和非实时两种通信方式,分别用write及mail命令。此外,联机用户还可根据自己的当前情况,决定是否接受其他用户与他进行通信的要求。
1.信箱通信命令mail
它被作为在Linux的各用户之间,进行非交互式通信的工具。mail采用信箱通信方式。发信者把要发送的消息写成信件,“邮寄”到对方的信箱中。通常各用户的私有信箱采用各自的注册名命名,即它是目录/usr/spool/mail中的一个文件,而文件名又是用接收者的注册名来命名的。信箱中的信件可以一直保留到被信箱所有者消除为止。因而,用mail进行通信时,不要求接收者利用终端与发送者会话。亦即,在发信者发送信息时,虽然接收者已在系统中注册过,但允许他此时没有使用系统;也可以是虽在使用系统,但拒绝接收任何信息。
mail命令在用于发信时,把接收者的注册名当作参数打入后,便可在新行开始键入信件正文,最后在一个新行上,用“.”来结束信件或用“^D”退出mail程序(也可带选项,此处从略)。
接收者也用mail命令读取信件,可使用可选项r、q或p等。其命令格式为:

$mail [-r][-q][-p][-file][-F persons]

由于信箱中可存放所接收的多个信件,这就存在一个选取信件的问题。可选项r、q、及p分别表示:按先进先出顺序显示各信件的内容;在打入中断字符(DEL或RETURN)后,退出mail程序而不改变信箱的内容;以及一次性地显示信箱全部内容而不带询问,把指定文件当作信件来显示。在不使用-p选项时,表示在显示完一个信件后,便出现“?”,以询问用户是否继续显示下一条消息,或选读完最后一条消息后退出mail。此外,还可使用一些其它选项,以指示对消息的各种处理方式,在此不予赘述。
2.对话通信命令write
用这条命令可以使用户与当前在系统中的其他用户直接进行联机通信。由于Linux系统允许一个用户同时在几个终端上注册,故在用此命令前,要用who命令去查看目标用户当前是否联机,或确定接收者所使用的终端名。命令格式为:

$write user[ttyname]

当接收者只有一个终端时,终端名可缺省。当接收者的终端被允许接收消息时,屏幕提示会通知接收者源用户名及其所用终端名。
3.允许或拒绝接收消息的mesg命令
其格式为:

$mesg [-n][ -y]

选项n表示拒绝对方的写许可(即拒绝接收消息);选项y指示恢复对方的写许可,仅在此时,双方才可联机通信。当用户正在联机编写一份资料而不愿被别人干扰时,常选用n选项来拒绝对方的写许可。编辑完毕,再用带有y选项的mesg命令来恢复对方的写许可,不带称选顶的mesg命令只报告当前状态而不改变它。

2.2.6 后台命令

有些命令需要执行很长的时间,这样,当用户键入该命令后,便会发现自己已无事可做,要一直等到该命令执行完毕,方可再键入下一条命令。这时用户自然会想到应该利用这段时间去做些别的事。Linux系统提供了这种机制,用户可以在这种命令后面再加上“&”号,以告诉Shell将该命令放在后台执行,以便用户在前台继续键入其它命令。
在后台运行的程序仍然把终端作为它的标准输出和标准输出,除非对它们进行重新定向。若shell未重定向标准输入,则shell和后台进程将会同时从终端进行读入。这时,用户从终端键入的字符可能被发送到一个进程或另一个进程,并不能预测哪个进程将得到该字符。因此,对所有在后台运行的命令的标准输入,都必须加以重定向,从而使从终端键入的所有字符,都被送到Shell进程。用户可使用ps、wait及Kill命令去了解和控制后台进程的运行。

2.3 程序接口

程序接口旨在运行程序与系统资源及系统服务之间实现交互作用,而为了保证系统的安全性,系统提供了若干系统调用(system call)来实现用户程序和内核的交互。因此,系统调用是操作系统提供给编程人员的唯一接口。编程人员利用系统调用,在源程序一级动态请求和释放系统资源,调用系统中已有的系统功能来完成那些与机器硬件部分相关的工作以及控制程序的执行速度等。事实上,命令控制界面也是在系统调用的基础上开发而成的。

2.3.1 系统调用

通常,在操作系统的核心中都设置了一组用于实现各种系统功能的子程序(过程),用户可以在程序中直接或间接地使用这些子程序,采用低级语言编程可以直接使用这些子程序,采用高级语言编程则采用程序调用的方式,通过解释或编译程序将其翻译成有关的系统调用,完成各种功能和服务
系统调用是用户程序进入内核程序的唯一途径。因此,它与一般的过程调用有下述几方面的明显差别:
(1)运行在不同的系统状态。一般的过程调用,其调用程序和被调用程序都运行在相同的状态——系统态或用户态;而系统调用与一般调用的最大区别就在于:调用过程是运行在用户态,而被调用程序是运行在系统态
(2)通过软中断进入。由于一般的过程调用并不涉及到系统状态的转换,故可直接由调用过程转向被调用过程。但在运行系统调用时,由于调用和被调用过程是工作在不同的系统状态,因而不允许由调用过程直接转向被调用过程。通常都是通过软中断机制,先由用户态转换为系统态,经核心分析后,才能转向相应的系统调用处理子程序。
(3)返回问题。在采用了抢占式(剥夺)调度方式的系统中,在被调用过程执行完后,要对系统中所有要求运行的进程做优先权分析。当调用进程仍具有最高优先级时,才返回到调用进程继续执行;否则,将引起重新调度,以便让位优先权最高的进程优先执行。此时,将把调用进程放入就绪队列。
(4)嵌套调用。像一般过程一样,系统调用也可以嵌套进行,即在一个被调用过程的执行期间,还可以利用系统调用命令去调用另一个系统调用。但是,每个系统对嵌套调用的深度都有一定的限制,例如最大深度为6。
系统调用的主要目的是使得用户可以使用操作系统提供的有关设备管理、输入输出系统、文件系统和进程控制、通信以及存储管理等方面的功能,而不必了解系统程序的内部结构和有关硬件细节,从而起到减轻用户负担和保护系统以及提高资源利用率的作用。

2.3.2 系统调用的类型

系统调用大致可分为如下几类:
(1)设备管理。该类系统调用被用来请求和释放有关设备、以及启动设备操作等。
(2)文件管理。包括对文件的读、写、创建和删除等。
(3)进程控制。进程是一个在功能上独立的程序的一次执行过程。进程控制的有关系统调用包括进程创建、进程执行、进程撤消、进程等待和执行优先级控制等。
(4)进程通信。该类系统调用被用在进程之间传递消息或信号。
(5)存储管理。包括调查进程占据内存区的大小、获取进程占据内存区的始址等。

2.3.3 系统调用的实现

系统调用的实现与一般过程调用的实现相比,两者间有很大差异。对于系统调用,控制是由原来的用户态转换为系统态,这是借助于中断和陷入处理机构来完成的,在该机构中包括中断和陷入硬件机构及中断与陷入处理程序两部分。
1.中断和陷入向量
为了处理上的方便,通常都是针对不同的设备编制不同的中断处理程序,并把该程序的入口地址放在某特定的内存单元中。此外,不同的设备也对应着不同的处理机状态字PSW,且把它放在与中断处理程序入口指针相邻接的特定单元中。在进行中断处理时,只要有了这样两个字,便可转入相应设备的中断处理程序,重新装配处理机的状态字和优先级,进行对该设备的处理。因此我们把这两个字称为中断向量。相应地,把存放这两个字的单元称为中断向量单元。类似地,对于陷入,由所有系统调用的入口地址组成陷入向量。由所有的中断向量和陷入向量构成了中断和陷入向量表。
2.系统调用号和参数的设置
往往在一个系统中设置了许多条系统调用,并赋予每条系统调用一个唯一的系统调用功能号,例如,0,1,2,3等,由用户通过系统调用号来区别调用相应的系统功能。在有的系统中,直接把系统调用号放在系统调用命令中;如IBM 370和早期的Linux系统,是把系统调用命令的低8位用于存放系统调用号;在另一些系统中,则将系统调用号装入某指定寄存器或内存单元中,如MS—DOS是将系统调用号放在AH寄存器中。
由于不同的系统调用需要传递给系统子程序以不同的参数,而且,系统调用的执行结果也要以参数的形式返回给用户程序。因此,在执行系统调用时,如何设置系统调用所需的系数,也有两种方式:
(1)直接将参数送入相应的寄存器中。这是一种最简单的方式,MS—DOS便是采用的这种方式,即用MOV指令将各个参数送入相应的寄存器中。这种方式的主要问题是由于寄存器数量有限,因而限制了所设置参数的数目。
(2)参数表方式。将系统调用所需的参数放入一张参数表中,再将指向该参数表的指针放在某个指定的寄存器中。当前大多数的OS中,如Linux系统,便是采用了这种方式。该方式可进一步分为直接和间接两种方式,如图2-1所示。在直接参数方式中,所有的参数值和参数个数N,都放入一张参数表中;而在间接参数方式中,则在参数表中仅存放参数个数和指向真正参数表的指针。
在这里插入图片描述
3.系统调用的处理步骤
根据编程人员给定的系统调用名和参数,系统设置了系统调用号和传递参数后,便可执行一条相应的系统调用指令(这条指令通常称为陷入指令)。不同的系统可采用不同的执行方式。在Linux系统中,是执行CHMK命令;而在MS-DOS中则是执行INT 21软中断。在处理机执行这条指令时发生相应的陷入中断,并发出有关信号给系统中的中断和陷入处理机构。该处理机构在收到了处理机发来的信号后,启动相关的处理程序和硬件完成该系统调用所要求的功能。
系统调用的处理过程可分成以下三步:①保护处理机现场。首先,在系统发生了陷入中断时,为了不让用户用户程序直接访问系统程序,反映处理机硬件状态的处理机状态字PSW中的相应位要从用户执行模式(用户态)转换为系统执行模式(系统态),这一转换在发生陷入中断时由硬件自动实现;然后,保护被中断进程的CPU环境,将处理机状态字PSW、程序计数器PC、系统调用号、用户栈指针以及通用寄存器内容等,压入堆栈;最后,将用户定义的参数传送到指定的地方保存起来。**②取得系统调用功能号并转入相应的处理程序。**为使不同的系统调用能方便地转向相应的系统调用处理子程序,在系统中配置了一张系统调用入口表(陷入向量表),表中的每个表目都对应一条系统调用,其中包含该系统调用自带参数的数目、系统调用子程序的入口地址等。因此,核心可利用系统调用号去查找该表,即可找到相应的处理子程序的入口地址而转去执行相应的程序。③返回。由于用户程序还需利用系统调用返回的结果继续执行,因此,在系统调用处理结束这之后,陷入处理机构还要恢复处理机现场。系统调用的处理过程如图2-2所示。
在这里插入图片描述
图2-2 系统调用处理过程

2.3.4 Linux系统调用

linux内核中设置了一组用于实现系统功能的子程序,称为系统调用。系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于核心态,而普通的函数调用由函数库或用户自己提供,运行于用户态。系统在内核中定义了一个系统调用入口地址表_sys_call_table,该表记录了所有已注册过的系统调用函数,这个表中为每一个系统调用指定了惟一的系统调用号。
Linux通过软中断指令int 0x80 来陷入内核态(在Intel Pentium II 又引入了sysenter指令)通过寄存器传递参数。中断0x80 把控制权传给核心入口地址中的_system_call(),_system_call()将所有的寄存器内容压入用户栈,并检查系统调用是否合法,如果合法,确定系统调用号,从_sys_call_table中找出的相应的系统调用入口地址,执行相应的系统调用功能。
系统调用的编程接口相对用户来说比较复杂,Linux系统为了向户屏蔽这种复杂性,将系统调用接口默认链接到所有用户程序的应用编程接口(Application Programming Interface—API)的库函数中,这就是libc的标准C库函数。在标准C库函数中为每个系统调用设置了一个封装例程。当一个程序需要一个系统调用时,就可调用C库函数中的相对应的封装例程。从而减少了用户程序设计和编程难度,节省用户的程序设计和编程时间。
这里需要特别强调的是,并非所有的标准C库函数都是系统调用的封装例程。或者说,系统调用的封装例程只是这个C函数库中的一部分,其中还有一部分库函数是不需要系统调用就可以实现的,像一些抽象的数学计算库函数,应用编程接口提供它们,也是为了方便用户使用,但这类函数不需要系统内核代码来实现。
随着Linux系统版本的不断翻新,其所提供的系统调用也不断增加,其数量已增至数百条,其中最常用的大约有30多条。根据其功能的不同,Linux系统的系统调用大致可分为如下几类:
1. 有关设备管理的系统调用
用户使用这些系统调用对有关设备进行读写和控制等。例如系统调用ioctl为所有设备的专用命令提供一个一般的、万能的入口点,它允许一个进程预置与一个设备相联系的硬件选择项和与一个驱动程序相联系的软件选择项,从而使设备和相应的驱动程序连接起来。另外,系统调用read,write可用来对指定设备进行读写,系统调用open和close可用来打开和关闭某一指定设备。
2.有关文件系统的系统调用
有关文件系统的系统调用是用户经常使用而且种类较多的一类。它包括文件的打开(open)、关闭(close)、读(read)写(write)、创建(creat)和删除(unlink)等调用,还包括文件的执行(execl)、控制(foctl)、加锁解锁(flock)、文件状态的获取(stat)和安装文件系统(mount)等。较常用的有文件的打开、创建、读写和关闭等。
3.有关进程控制的系统调用
关于进程控制的系统调用有创建进程的调用fork( )、阻塞当前执行进程自己的系统调用wait( )、进程自我终止用的exit( )、获得进程标识符用的getpid( )、父进程标识获取调用getppid( )、进程优先级获取用的getpriority( )、改变进程优先数用的nice( )、发送和接收信号用的kill( )和signal( )、暂停当前进程的执行过程的pause( )以及管道通信调用pipe( )等。
进程创建调用fork( )使用格式是n=fork( );该系统调用的返回值可以是0或大于0的整数或等于﹣1。n=0时表示系统将执行子进程的有关程序段,n>0时表示系统将执行父进程的程序段,而n=﹣1则表示子进程未创建成功。无论n=0或是n>0,父进程的程序段和子进程的程序段都将得到执行,只是二者执行的时间和顺序上有差别。
系统调用wait( )的返回值是等待子进程的进程标识符。wait( )的功能是阻塞父进程,等待子进程完成后使得父进程继续工作。
进程终止调用exit( )终止调用进程本身,并释放所占用的所有资源。
管道通信用的系统调用pipe(fd)为同一家族的进程之间传递数据建立一条管道。其中参数是一个包含2个单元的整型数组,fd[0]代表管道的读端,而fd[1]代表管道的写端。管道被创建之后,一般和系统调用read( )和write( )联合使用,有关管道通信,将在后面章节中进一步说明。
除了上述系统调用之外,在进程控制中还经常用到两个有用的实用程序,一个是sleep(n),执行该实用程序使得当前执行进程睡眠n秒钟。另一个是用于进程互斥的实用程序lockf(fd,mode,size),其功能是将指定文件fd的指定区域进行加锁或解锁,以解决临界资源文件的竞争问题。
4.有关进程通信的系统调用
进程通信用的系统调用主要包括套接字(socket)的建立、链接、控制和删除,以及进程 间通信用的消息队列、共用存储区以及有关同步机制的建立、链接、控制和删除等有关系统调用。
5.关于存储管理的系统调用
这些系统调用包括获取内存现有空间大小、检查内存中现有进程以及对内存区的保护和改变堆栈大小等功能。
6.管理用系统调用
例如,设置和读取日期和时间,取用户和主机等的标识符等系统调用。显然,一个系统提供的系统调用越多,功能就越强,用户使用起来也就更加方便灵活。
下面是一个使用目录系统调用的例子,实现了Linux命令pwd的功能。
例2-1:

#include <stdio.h> 
#include <stdlib.h>
#include <unistd.h>
#define MAX_PATH 255
int main()
{
    char name[MAX_PATH+1];
    if(getcwd(name,MAX_PATH)==NUll)     
     printf("error:Failure getting pathname");
     printf("Current Directory:%S\n",name);
}

程序的运行结果:Current Directory:/home/student

但有点不足是,如果 glibc 没有封装某个内核提供的系统调用时,我就没办法通过上面的方法来调用该系统调用。如我自己通过编译内核增加了一个系统调用,这时 glibc 不可能有你新增系统调用的封装 API,此时我们可以利用 glibc 提供的syscall 函数直接调用。该函数定义在 unistd.h 头文件中,函数原型如下:

long int syscall (long int sysno, ...)

1.sysno 是系统调用号,每个系统调用都有唯一的系统调用号来标识。在 sys/syscall.h 中有所有可能的系统调用号的宏定义。
2… 为剩余可变长的参数,为系统调用所带的参数,根据系统调用的不同,可带0~5个不等的参数,如果超过特定系统调用能带的参数,多余的参数被忽略。
由上所述可见,一个用户程序将频繁地利用各种系统调用以取得操作系统所提供的多种服务。

2.3.5 Windows应用编程接口

Windows程序采用的是事件驱动方式。即应用程序根据事件的内容,如鼠标的一个点击,移动,键盘的按键按下等等操作,都是对应操作系统的一个事件,然后调用相应的程序进行处理。当应用程序调用操作系统服务时,由硬件产生一个陷入信号,将应用程序从用户态切换一核心态,将控制权转交给陷入处理程序,查找“系统服务调度表”,也即陷入向量表,找到对应的系统服务程序入口地址,执行相应的系统服务程序。
为了进一步促进操作系统和应用软件之间互通,方便用户编写 Windows 应用程序,Windows 提供了大量的子程序和函数,也就是 Windows应用编程接口(Application Programming Interface—API)。一个API函数可能不与任何系统调用相对应,也可能调用一个或多个系统调用,不同的API可能封装了相同的系统调用。API是一种公共的标准的应用接口,使不同的软件系统可以互相利用,共享信息。
标准Windows API函数可以分为以下几类:
1. 系统服务
系统服务函数为应用程序提供了访问计算机资源与底层操作系统特性的手段,包括内存管理、文件系统、设备管理、进程和线程控制等。应用程序使用系统服务函数来管理和监视它所需要的资源。
2. 通用控件库
系统提供了一些通用控件,属于操作系统的一部分,所以它们对所有的应用程序都可用。使用通用控件有助于使应用程序的用户界面与其他应用程序保持一致,同时直接使用通用控件也可以节省开发时间。
3. 图形设备接口
图形设备接口(Graphics Device Interface,GDI)提供了一系列的函数和相关的结构,可以绘制直线、曲线、闭合图形、文本以及位图图像等,应用程序可以使用它们在显示器、打印机或其他设备上生成图形化的输出结果。
4. 网络服务
网络服务函数可以使网络上不同计算机的应用程序之间进行通信。使用网络函数可以创建和管理网络连接,从而实现资源共享,例如共享网络打印机。
5. 用户接口
用户接口函数为应用程序提供了创建和管理用户界面的方法,可以使用这些函数创建和使用窗口来显示输出、提示用户进行输入以及完成其他一些与用户进行交互所需的工作。大多数应用程序都至少要创建一个窗口。
6. 系统Shell
Windows API中包含一些接口和函数,应用程序可使用它们来增强系统Shell各方面的功能。
7. Windows系统信息
系统信息函数使应用程序能够确定计算机与桌面的有关信息,例如确定是否安装了鼠标,显示屏幕的工作模式等。
例2-2:下面程序应用Windows API函数实现了例2-1的功能。

include "stdafx.h"
include "windows.h"
define DIRNAME_LEN MAX_PATH+2
int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    TCHAR PwdBuffer[DIRNAME_LEN];
	   DWORD LenCuDir;
    LenCuDir=GetCurrentDirectory(DIRNAME_LEN,PwdBuffer);
	  if(LenCuDir==0)	
MessageBox(NULL,"Failure getting pathname,",NULL,MB_OK);
	  MessageBox(NULL,PwdBuffer,"Current Directory",MB_OK);
    return 0;
}

由此可见,Windows API也是一个基于C语言的接口,只是调用函数和编程模式与Linux不同。Windows API中的函数也可以被使用不同语言编写的程序调用,只要在调用时遵循调用规范即可。

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值