操作系统开发过程应遵循的一些原则

时间:2021-02-26 20:06:35
 

如何衡量一个操作系统是否成功

在讨论如何衡量一个操作系统是否成功之前,首先必须明确,怎样的系统软件才算作是一个操作系统?并不是所有的系统软件都是操作系统,我认为,一个完整的操作系统,必须具备下列功能(或特征):

1、  基于一种或多种硬件平台(或硬件体系架构),能够成功的启动这个硬件计算机平台,并能够对硬件平台的基本资源进行管理。这里的基本资源,至少包括CPU、内存,以及键盘和显示器等输入输出设备;

2、  提供一个人机接口,比如一个字符界面的shell或一个图形交互界面,用户能够通过这个人机接口直接操作硬件设备;

3、  提供一个应用编程接口(API),程序员能够采用一种或多种计算机语言设计出针对该操作系统的软件程序,能够完成某些特定的功能。当然,软件开发所需的开发环境和开发语言,可以是基于其它操作系统的,不一定非得是本操作系统提供的环境。

 

通俗地讲,能够启动计算机,并能够对硬件资源进行管理和应用的系统软件,才能称为操作系统。按照这个定义,一些只能构启动计算机、显示一些特定内容的程序片断,不能算作操作系统,因为它无法提供人机交互接口,也无法提供一个应用程序运行平台。比如第一个版本的Linux(似乎是Linux 0.0),其全部功能就是把CPU切换到保护模式,在屏幕上输出一连串的A和B,然后进入死循环。按照上面的定义,这不算是操作系统。再进一步,一些软件片断除具备启动计算机的功能外,还提供了基本的键盘/显示器驱动代码,用户可以通过键盘输入一些字符,然后显示在屏幕上。这也不能算是一个操作系统,因为它没有提供一个应用编程接口,无法开发出满足特定需要的应用程序。

需要强调的是,这里的应用编程接口,不一定非得以中断或陷阱调用的方式提供。比如,操作系统以头文件的方式提供一些功能函数调用,应用程序部分直接与操作系统核心代码进行编译连接,组成一个整体的模块,这种实现机制也可认为是满足上述第三条的。而且在实际开发中,很多嵌入式操作系统就是采取这种方式实现系统调用的。这样的好处是,应用程序代码直接调用操作系统功能代码,无需经过描述符切换、上下文切换等额外工作,效率非常高。但缺点也很明显,就是应用程序部分代码与操作系统核心代码无法有机分离,必须统一编译连接。诚然,以中断或陷阱方式提供的API接口,可以使得应用程序与操作系统完全独立,充分实现模块化设计思想,是一种更好的方式。

 

然后,我们再讨论什么样的操作系统算是一个成功的操作系统。满足上述条件的操作系统很多很多,一个计算机专业的学生,在半年的时间内就可写出一个操作系统。但是大多数操作系统并不是成功的操作系统,这些不算成功的操作系统,其最主要意义,可能就是锻炼了操作系统开发者的编程能力,满足了操作系统开发者完成一个操作系统内核的心愿。但一个成功的操作系统的意义就远不止于此了,成功的操作系统会被广泛使用,产生巨大的经济效益。比如Windows操作系统,不论你喜欢还是不喜欢,它都大大的拉近了人与计算机的距离,使得计算机成为一种最重要的生产工具,产生的经济效益是难以估量的。并不是每个成功的操作系统,都必须象windows那样有影响力,我认为,一个操作系统能够满足下列几条要求,就可称为一个成功的操作系统:

1、  提供一组清晰且功能完备的应用程序编程接口(API),并有一个与之配套的应用开发环境,可以完成设备驱动程序、应用程序的开发。开发难度维持在平均软件开发难度以下,比如,一个普通技能水平的程序员,就可以在这个开发环境下,开发出针对这个操作系统的设备驱动程序或应用程序;

2、  有一组与之配套的常规硬件驱动程序,能够完成大多数日常功能。比如具备常见的网卡驱动程序、音频/视频驱动程序、USB总线驱动和USB存储设备驱动程序等。有了这些常规硬件驱动的支撑,该操作系统就可完成大多数的常用功能,比如上网、音频/视频播放等;

3、  有一些与之配套的常用应用程序,形成一个封闭的应用生态环境。比如浏览器、邮件客户端、通信录、即时消息客户端、文字处理软件等,用户可通过这些软件完成常规的任务。

 

上述可归纳为一个操作系统生态链,这个生态链包含硬件支持、应用程序支持、开发环境支持等。只有具备了一个相对完整的生态链的操作系统,才算作一个成功的操作系统。因为它已经具备了能够产生经济效益的基础条件。

再强调一点,这里讲的“成功的操作系统”,不一定是一个商业上成功的操作系统。很多满足上述条件的操作系统,根据这里的限定,算作是一个成功的操作系统,但是在商业上却不一定成功。但是反过来,一个商业上成功的操作系统,必然是一个满足上述限定条件的“成功操作系统”。本文中的成功,着重强调操作系统的生态环境成功。只要具备了一个完善的生态环境,在商业上成功的可能性就大大增加了。

 

那么,要开发出一个成功的操作系统,是否有一些基本原则可遵循呢?我认为是有的,因为我们的目标非常简单和明确,那就是通过合理设计操作系统,使之能够以自己为核心,形成一个完整的操作系统生态链。任何事情,只要目标明确,原则和策略就好定了。当然,操作系统开发是一个复杂的系统工程,工作量巨大,其原则决不是一篇文章能够说清楚的。下面列举了一些我认为非常重要的原则,希望起到抛砖引玉的作用,供朋友们评判。

 

操作系统要有明确的定位和特色,选定某一场景或应用范围,在这个既定范围内深入耕耘。所有成功的操作系统,都有其明确的定位和特点。比如Windows操作系统,主要是面向大众应用、面向个人计算机,因此其在易用性和用户感知上有良好树建,这是其成功的最主要因素。Linux则偏重于代码开源、高效率,因此其得到了更多的硬件平台的支持,同时在性能要求较高、成本较低的服务器领域得到广泛应用。由于其源代码开放的特点,Linux还被移植到嵌入式领域,在嵌入式领域也建立了一个庞大完备的操作系统生态链。目前比较流行的Android操作系统,则明确定位于个人移动终端领域,针对这个领域的应用特点和需求,在用户交互(触摸屏输入、简洁图形输出等)、尺寸受限的屏幕显示、移动通信特性(语音功能、短信功能、邮件功能等)等方面做的很优秀,因而得到广泛应用。要开发一个全新的操作系统,必须选定一个全新的应用场景,或者对已有应用场景进行进一步分析和抽象,做出更明显的特色,方能成功。如果特征不明显,或者与已有成功操作系统的应用领域完全重合但有没有更吸引人的特色,则很难成功,因为现有操作系统已经“先入为主”了。

 

操作系统关键组件一定要与操作系统核心紧密耦合,核心模块尽量不要独立。这个原则可能与我们的常规印象有冲突。在我们接受的教育和日常秉承的开发理念中,软件模块尽量独立,尽量不依赖其它模块。即使模块之间有依赖关系,也必须定义一个良好的接口进行连接。但是在操作系统开发领域,我认为要想成功,操作系统关键模块与操作系统核心之间最好形成紧密绑定关系。这里的操作系统关键模块,指的是GUI模块、文件系统、网络功能模块、系统调用API、支撑库等。这些模块之间不应形成紧密绑定关系,但是这些模块必须与操作系统核心紧密耦合。换言之,为某一特定操作系统开发的功能模块,不能被轻易的拿到别的操作系统之上。这样的原则,主要是为了充分聚集不同模块之间的合力,组成一个完整有机的独特操作系统。比如Linux,虽然其秉承开源开放的原则,但是其文件系统功能、网络功能、系统调用API等,都是Linux本身特定的,不能被其它操作系统直接移植。正是因为这样的特点,使得整个操作系统不至于分散,达到“一荣共荣、一辱共辱”的目的。再举一个相反的例子,在低端嵌入式领域应用比较广泛的ucOS,一直是一个操作系统核心,始终未形成一个完整的操作系统。这主要是因为,以其为基础的各个操作系统重要模块,比如TCP/IP协议栈、GUI、文件系统等,在设计的时候首先想到的是可移植,于是定义了尽量少的操作系统核心调用接口,尽量多的功能在模块内部实现,而不依赖于操作系统核心。这样这些功能模块很容易被移植到别的操作系统上,无法发挥“外围模块助力操作系统核心”的目的。这种朝秦暮楚的设计理念,大大阻碍了操作系统生态链的生成。最后再强调一下,这里的模块与操作系统核心的紧密耦合理念,应该仅仅局限于操作系统关键模块与操作系统核心之间。其它功能模块或实体之间,还是应该秉承独立、模块化原则。比如驱动程序与操作系统之间、应用程序与操作系统之间,必须以清晰独立的模块划分原则进行设计,并定义接口,否则会大大阻碍操作系统生态链的生成。

 

简洁明了的应用编程接口(API)非常重要。一个成功的操作系统,必须要有一个完备的生态链与之配套。显然,打造这个生态链的最主要工具,就是操作系统提供的API接口。所有设备驱动程序、应用程序,都必须调用操作系统API接口完成特定功能。因此,设计良好、易于使用、功能强大的API接口,对操作系统生态链的建设非常关键。在设计API接口的时候,尽量保持接口的简洁,每一个API功能调用,完成一个单一的功能,确保其功能清晰简洁,不要多个功能使用同一个API函数。同时,对于API的参数个数和每个参数的取值范围,尽量简缩和明确。对于API函数的返回值,也明确定义,不要产生歧义。同时,如果可能,尽量与现有流行操作系统提供的API函数语义保持一致,这样可大大降低程序员的学习成本。API定义清楚之后,尽量不要改变,如果要改变,也要以扩展参数的形式进行改变,不要改变原有参数和返回值的含义。最后,一定要有一份清晰的文档,对API的原型和功能进行说明。这份文档非常关键,是程序员所需的最核心开发资料。

 

建立一个简便、高效的应用开发环境。定义和实现了API之后,必须建立一个与之配套的应用程序开发环境,供程序员开发与之配套的应用程序。需要说明的是,这个应用开发环境不一定要从头重新开发,完全可以借鉴现有的应用程序开发环境。比如,可以在现有开发环境中增加插件,使得其支持该操作系统。Android就是一个很好的例子,它没有从头开始建立一个开发环境,而是利用了被广泛应用的Eclipse开发环境。这样不但大大降低开发工作量,也可充分继承现有开发环境所积累的开发经验和开发资源。很多情况下,程序员是根据开发环境选择开发的目标操作系统的,而不是根据操作系统选择开发环境。比如同样是移动开发,熟悉JAVA和Eclipse的程序员,可能就直接选择了Android作为首选目标操作系统,而熟悉C/C++语言的程序员,会首选iOS作为目标开发环境。虽然iOS使用Ojbective C语言作为其开发语言,但是该语言与C/C++更加接近。因此,选择一个流行的、拥有广泛开发者的开发环境,对操作系统本身生态链的建设非常有价值。最后,开发环境(或者依赖于某个成熟开发环境的插件)必须与第一个操作系统版本一起发布,所谓“操作系统未动,开发环境先行”。而且一旦发布,尽量保持不变。这样做的目的,是使程序员尽快熟悉最新操作系统的开发方法,给程序员足够的时间去学习和掌握开发过程。

 

采用模块化设计,确保操作系统具有最大可能的扩展性。这里包含两个层面的意思:设备驱动程序层面和应用程序层面。在设备驱动程序层面,要提供一个明确定义、功能完备的设备驱动程序调用接口,设备驱动程序通过这一组接口,调用操作系统的特定服务。这样就可使得设备驱动程序作为独立于操作系统核心的独立模块,而无需与操作系统一起进行编译和连接。显然,这样的结构,可使得设备驱动程序的开发过程非常独立和容易。与之相反的做法是,操作系统不提供设备驱动程序调用接口,或者即使提供,也是以函数的形式提供,设备驱动程序开发的时候,必须包含对应的头文件和库文件,并与操作系统核心一起连接成一个大的系统模块。显然,这种设计方法把操作系统核心和设备驱动程序绑定在了一起,不利于设备驱动程序的单独设计。同样的,对于应用程序开发,也应该定义一个清晰的开发接口,供应用程序调用。同时定义和实现一个应用程序加载机制,使得应用程序在开发过程中无需考虑加载地址等因素,也无需考虑操作系统核心的实现机制,只需要专注于应用程序本身的功能即可。这样的结果是,任何一个应用程序,都是独立于操作系统的一个模块,这个模块可存放在外部存储介质上,供操作系统“按需加载”。主流的成功操作系统,大都是按照这样的原则进行设计。比如Windows和Linux,都实现了可加载模块的功能,同时清晰定义了设备驱动程序和应用程序能够调用的接口函数。在移动领域流行的Android和iOS操作系统,也是按照这种方式设计和实现,取得了良好的成功。如果没有这种模块化的设计机制,Apple应用商店和Android应用商店就无从谈起。最后强调一下,这里的模块化原则,与前面所说的操作系统关键模块之间紧密耦合原则不冲突。前面讲的紧密耦合,是操作系统核心模块之间的紧密耦合,这里讲的模块化分离原则,是操作系统核心部分与外围部分(驱动程序、应用程序等)之间的设计原则。

 

最大程度的包容设计,尽量与现有操作系统兼容和共存。所谓有容乃大,尽量与现有操作系统或现有的应用软件兼容,是操作系统开发的一个重要原则。这样做,可大大加快操作系统生态链的建设。或许有些不可思议,作为最贴近硬件的系统软件,操作系统之间能兼容吗?答案是肯定的,但是这种兼容可能不像应用程序兼容操作系统那样明显。举例来说,比如新开发的操作系统是针对x86平台的,则尽量支持FAT32/NTFS等文件系统,同时其启动过程,也建议充分利用Windows操作系统的启动机制,提供启动菜单让用户选择。这些动作,就是为兼容Windows操作系统而做的。这样做,可使得用户在安装或使用新操作系统的时候,无需重新格式化硬盘,也无需销毁已有的操作系统,而只要象安装普通软件那样安装到已有硬盘上就可以了。另外一种层面的兼容,是API接口的兼容。开发出与现有操作系统完全一样的API接口,可能性比较小,而且这样做也可能侵犯知识产权。但是与现有操作系统的API接口尽量保持一致,比如保持语义、API接口参数类型、错误处理机制等的一致,可大大降低程序员的学习成本,大大加快应用程序的开发速度。与现有操作系统的可执行文件格式保持一致,也是一种兼容行为。比如,新开发的操作系统支持windows的PE格式执行文件,则可大大增加可用于应用程序开发的开发环境数量,有利于生态链的建设。兼容现有的可执行文件格式,对某些基于已有操作系统比如Windows开发的应用程序,甚至直接可以在新操作系统上运行。

 

操作系统开发是一个复杂的系统工程,应该遵循的原则或策略,远不止上述描述的这些。而且上述原则,也是作者在操作系统开发中的一些体会和理解,不一定适合所有操作系统的开发。在这里写出来,主要是希望起一个抛砖引玉的作用,希望能够依次为切入,能够激发更多的讨论和共享,为操作系统开发贡献一份力量。


作者:辛庆祥,操作系统开发爱好者,目前正从事开源操作系统Hello China的开发,曾以蓝枫叶为笔名,出版《嵌入式操作系统:设计与实现》一书。Hello China开发QQ群:38467832   新浪微博:http://weibo.com/2196920292

声明:如果您转载或引用本文(或本文部分内容),那将是我的荣幸。但是请您一定要注明出处和作者,谢谢。