本帖所述的操作系统源代码和《都江堰操作系统与嵌入式系统设计》一书,均可以在 www.djyos.com 中免费下载。
哦,又一个内核,且慢这样说
都江堰操作系统(简称djyos)是一个操作系统,但不是“又一个操作系统”,它是一个全新思路的操作系统。 djyos操作系统是以事件为核心进行调度的,这种调度策略使程序员可以按人类认知事物的习惯而不是计算机的习惯来编程。 普通操作系统中,调度是以线程为核心的,事件被作为线程的数据,标榜为“事件触发”的软件模型,也是由线程在一旁候着,待特定事件发生时线程恢复运行并把它作为输入数据加以处理。 以事件为核心的调度,则像设备和内存一样,把线程虚拟机作为处理事件所需要的资源看待,当某事件需要处理时,分配或者创建一个线程虚拟机给该事件,并启动该线程虚拟机处理事件。
djyos虽然刚出生,但已经不仅仅是一个内核了,是一个初具雏形的操作系统,目前包括以下模块: 抢占式多事件调度系统 内存管理模块 内存池管理模块 资源管理模块 中断管理模块 锁(含信号量和互斥量)模块,支持优先级继承 泛设备管理模块 文件系统模块 含擦除平衡的flash文件系统驱动模块 看门狗模块 约400页的说明文档,各模块详情请看此文档以及共享之代码 嵌入式操作系统的成功之道
随着嵌入式系统的日益复杂化,嵌入式现在系统越来越成为嵌入式产业的核心,君不见,而在我们国家,嵌入式操作系统几乎是个空白,2008年的十大嵌入式企业以及中国电子信息产业100强中,竟然没有一家是从事嵌入式操作系统的,就连有一个自主操作系统作为副业的都没有。这既是中国嵌入式行业的悲哀,也是对中国工程师的鞭策。
然而,实时嵌入式操作系统市场是如此成熟和完整,新操作系统如要从中分一杯羹,无异于在钢板上钉钉子。即使如此,仍然有不少人前仆后继地往里挤,在前人不断的“壮烈牺牲”中,我看到的是机会与挑战并存。嵌入式操作系统是一个细分市场,所以不会形成桌面系统寡头控制的局面,在桌面系统上,是windows和unix系操作系统双寡头局面,这种情况绝不会出现在嵌入式领域。这就给了后起之秀一个机会,只要你的产品好,工程师认同,你就有机会。嵌入式操作系统的目标用户是工程师,而工程师是一个善于学习的群体,容易接受新事物的群体,这也是djyos的机会。
都江堰操作系统就在这样的环境中,应运而生,我们有理由期待它能脱颖而出。分析一下那些壮烈了的操作系统,我们要吸取的教训很多:
1、没有创新就没有生存之本。看许多发布的操作系统,不外乎就是现有操作系统理论的简单复制,一上来就给人“又一个操作系统”的印象,根本吸引不了人们的眼球。而djyos则不一样,在构成嵌入式操作系统的几个重要方面:调度器、中断管理、设备管理、资源管理等方面,都又非常突出的创新,甚至是理论创新。尤其是在调度器方面,可以说是彻底革新。
2、要贴合用户需求,不能片面强调单项性能。看许多发布的操作系统,在宣传自己的优异性时,不外乎上下文切换时间多么短、占用系统资源多么少、功能模块多么多、线程间通信手段多么丰富。有或者说自己的C语言率多么高,移植需要修改的代码行多么少,等等!整个就是闭门造车,根本没有从用户的角度考虑,不知道代码工程师需要什么,也不知道系统工程师需要什么,更不知道产品经理和研发经理需要什么。djyos不同,他本来就是产品研发工程师写出来的操作系统,它充分考虑到用户的需求,他从技术角度,协助产品经理(研发经理)组织项目团队,协助系统工程师从软硬件联合设计的角度设计系统架构,协助代码工程师写出移植性和一致性都很高的代码。
3、要戒除IT界的浮躁,有许多操作系统发布时,还只是一个简单的内核,连基本的文档都没有,代码也是乱哄哄的没有注释。用户拿到手里,根本就云里雾里。要知道,你一个新生事物,用户是不会有耐心等你成熟的,即使你真的能够成熟,在你成熟的过程中,用户早已审美疲劳了。一个新生的操作系统,应该一上来就给人一种令人耳目一新的冲击,才能是用户有兴趣往下了解你。djyos系统在发布时,就已经是一个完整的操作系统,而不是一个简单的内核,而且带有408页的文档(还是有意压缩篇幅之后的),写这个文档花的时间,远比写一个内核要长,近2万行的代码,有约1/4是注释。
轮嵌入式操作系统的可移植性 许多操作系统夸耀自己的可移植性时,爱这样说: “超过xx%代码由C语言编写,只有xx个函数是汇编,移植时只有xx个函数需要修改”。他们所关注的不外乎是操作系统本身从一个硬件平台移植到另一个硬件平台的难易度,这根本就是舍本逐末的提法。试问,一个含嵌入式系统的产品中,操作系统重要还是应用程序重要?我们说嵌入式操作系统是嵌入式产业的核心,是针对整个产业来说的,毕竟,操作系统的装机量远大于任何一个运行于操作系统的应用程序。而对具体产品来说,则应用程序无论从哪个方面讲都远比操作系统重要。对一个企业来说,尤其如此,企业可能有非常多的衍生产品,他们同同一份操作系统拷贝,或者有许多产品系列,系列之间的操作系统也只是稍有不同。他们花在移植操作系统上的时间,远小于应用程序的工作量,甚至可以忽略不计。因此,操作系统的可移植性,应该把重点放在协助应用程序移植上,那才是可移植性的精髓所在。 djyos在这方面是非常出色的,举个例子,如果某企业有两个相似产品,产品L不需要显示界面,产品H需要显示界面,其他功能相同,在的djyos下,你可以轻易做到: 1、把软件分成两大块,一块是显示部分代码,称为模块A,另一块是显示无关代码,显示无关代码完成产品的整体功能,调用显示部分的功能实现界面显示,称为模块B。 2、如果是si模式,A+B一起编译就是产品H,单独编译B就是产品L。编译产品L时连模块B中跟调用显示功能的代码都无需修改。 3、如果在dlsp模式下,则把模块A编译成A.out,模块B编译成B.out,把A.out和B.out一起copy到autorun目录下就成了产品H,单独copy B.out就成立产品L。 djyos的各模块设置,无不是围绕方便应用程序移植来设计,多事件调度器、泛设备组件、异步信号同步功能、事件和事件类型同步、应用程序模块加载器等,都为此做了许多考虑。今天很累了,暂不细说,在接下来的一段时间里,我将系列化发帖,讲述djyos中如何协助应用程序可移植,以及软件可移植性与可靠性之间的关系。
项目经理和系统工程师需要什么样的可移植性
许多人认为,可移植性就是软件从一个平台换到另一个硬件平台,仍然能正常运行的能力。这种说法是很笼统的,我们在细分一下,其中至少存在以下几个层面: 是否需要修改代码。 是否需要修改配置。 是否需要重新编译。 是否能够运行。 运行的结果是否正确。
听过有人说:C语言编写的代码,哪有移植性的问题。这种看法谬之大矣,等于说:我用拼音输入法写**,所以我的**是可移植的。关于C语言程序的可移植性,我的文档《都江堰操作系统与嵌入式产品设计》的第16章有详细的说明。用标准c语言写的程序,只能保证在支持标准C的编译环境中成功编译,不能确保能够正确运行。 比如下面这段代码,用指令实现10uS延时: for(i=100; i>0; i--); 该语句无论在什么平台下,它都可以编译、运行,但结果可能不正确。具体延时量,与CPU的速度、编译器的效率、编译器的优化级别等都有关系,我们称之为”耦合“,在《都江堰操作系统与嵌入式产品设计》的第11章论述了什么是耦合以及如何解耦。含上述代码的软件,在移植时,必须修改代码。一种改进的方法是,把100定义为符号常量,如下: #define cn_10us 100 for(i=cn_10us; i>0; i--); 这种方法只不过增加了代码的可读性,并降低了代码修改的工作量而已,本质上还是要修给代码并重新编译。djyos提供的改进方法是,有操作系统提供几个共享变量,他们是在操作系统初始化过程中被赋值的: 1. uint32_t u32g_ns_of_u32for; 当 delay_var是 32 位无符号整数时,每个循环消耗的纳秒数。 2. uint32_t u16g_ns_of_u32for; 当 delay_var是 16 位无符号整数时,每个循环消耗的纳秒数。 3. uint32_t u8g_ns_of_u32for; 当 delay_var是 8 位无符号整数时,每个循环消耗的纳秒数。 4. volatile uint32_t u32g_delay_10uS; 用 32 位无符号数做循环变量,延时 10uS 需要的循环次数。 在si模式下,若用下列语句做指令延时,可确保延时时间是100微秒。 volatile uint32_t delay_var; for(delay_var =100000/u32g_ns_of_u32for; delay_var >0; delay_var --);
然而,这只是djyos解除软件与CPU运行速度之间耦合的一个小技巧而已,djyos更着重的是从系统架构入手,帮助项目经理和开发经理组织团队,帮助系统架构师理清组件之间数据流动和代码互动之间的关系。 现在的嵌入式产品开发,从一个新平台重新开始开发的机会相对会少一些。更常见的情况是,拿一套已经有了型的代码到处修改客户化做新项目,或者依据市场需求把产品改一改,添加一点新的需求,去掉一些老的功能,做系列化型号。广义地,就一个功能组件来说,它的运行环境整个由硬件、操作系统、以及应用项目的其他组件共同组成。应用项目某组件的变化,也是运行环境的变化,也可能需要移植,而且这种移植更加广泛,更加受项目经理的重视。djyos系统更加关注的是广义的移植,从这个角度,即使硬件和操作系统部分不改变,某组件的运行平台的数量,也跟使用该组件的衍生产品型号一样多。如果不注意广义平台的可移植性,一个组件往往会在这个型号中好使,那个型号中就不行了,按下葫芦浮起瓢,防不胜防,烦不胜烦!最后造成的是,实现相同功能的组件,在不同的衍生型号中就是不一样。日子久了,这样的东西就会充斥企业的产品中,并与企业历史相结合,企业历史留下来的人和流下来的势力格局有限制了改进问题的机会,许多企业里面软件版本繁多而且凌乱,难于管理,就是这样造成的。解决这个问题,需要一个优秀的系统设计师,在项目设计之初就确定一个良好的系统架构,djyos从技术角度上,对项目经理和系统工程师提供帮助,为新项目的开发和老项目的改造都提供支持。试举例如下: 某工程由多个团队协同开发,某中断的初始化以及ISR代码由团队B负责,另外一个组件由团队A开发,组件A有一个线程需要阻塞等待某中断发生。那么,在传统模式下,团队A和团队B之间在技术上,至少有一个信号量在联系,线程等待信号量而中断释放信号量。别看这个简单联系,它造成的后果就是两个模块互相关联(耦合),中断ISR中至少有一句是跟组件A相联系的,线程和ISR之间至少有一个共享变量——信号量句柄!ISR和线程之间至少失去了独立的命名空间,即使你不用共享变量,那么,ISR至少需要提供一个手段,使线程能够把信号量的地址告知。总之,两个团队之间不可能再是完全独立的关系。而使用djyos的异步信号同步技术,则团队A可以根本不知道团队B的存在。 多团队共同开发的项目中,项目经理最希望看到的是,两个团队之间各自完成自己的任务,各自的任务之间不互相依赖,这样两个团队之间的开发进度就可以异步安排。而如果两个组件之间有耦合的话(就像刚才的例子,通过信号量耦合),至少有一些团队协调工作要做。而djyos中,两个团队是完全独立工作的,独立开发、独立编译、独立加载运行。 友好组与软件项目团队组织--linux的遗憾
从一个例子谈起,笔者曾经有一个项目需要做一个在 Linux 下的PCI 卡驱动程序,由于对 Linux不熟悉,所以花了大量时间熟悉 Linux 系统内核(我只是要写一个 driver,却要熟悉整个内核),在调试的时候,由于驱动程序运行在内核空间,驱动程序特别是中断里面的 bugs 造成反复的重启系统,而且这类错误往往无从着手查,因为系统崩溃了是不会给你输出任何信息的,只能重启,反复的重启差点没把我搞得精神分裂。这时候我就想,如果用户编写的 linux 设备驱动程序运行在用户空间,我根本不用花那么多时间和精力去熟悉 Linux 内核,也不用忍受那不停重启这种非人的折磨,这也使笔者深刻体会到,代码在哪个空间运行,不能由代码的功能属性来决定,而是应该由编写代码的团队来决定,由用户编写的代码应该运行在用户空间。把所有功能属性是设备driver的代码都放在内核空间运行,是一个面向过程的方法,而不是面向对象的思想,这点上,不得不说,是linux的一个遗憾。————软件工程中,面向对象的思想无处不在,而不仅仅在于如何书写代码。当然,linux最初设计在X86上运行,X86的IO指令是特权指令,只能在操作系统层操作,由于X86的先天特性,linux的驱动程序运行在操作系统空间能提高执行效率。 在由多个子团队协同开发的项目中,项目经理以及系统工程师必须考虑的问题是,哪些模块放在一起编译,哪些模块共享命名空间,如果在支持多进程的环境下开发,则还要考虑哪些模块在相同的地址空间运行。这些问题集中到一起,就是如何划分“软件友好组”的问题。在《都江堰操作系统与嵌入式系统设计》一书的第3章,用了相当长的篇幅用于讲述友好组。 友好组的定义很简单,就是可信赖的程序组成一个友好组,什么是可信赖的程序?同一个团队开发的程序是可信赖的。“友好”有两层意思,一是这些代码是为一个共同的目标,密切协作地完成任务;二是这些代码不会主动地、恶意地互相干扰和破坏,也不会故意执行非法操作。有两个特例是,如果同一个团队开发的两个模块将来可能会分成两个团队开发,应该将他们分成两个友好组;第二个特例是,两个模块的可靠性等级相差比较大,也应该分属两个友好组,这样,两个模块就可以使用不同强度的测试手段。 以设计软件的人为核心,是都江堰操作系统的核心思想之一。现代软件开发中,非常强调工程化开发的思想,在工程化开发中,任何软件策略都不能不考虑人的因素。划分友好程序和可疑程序是 djyos 操作系统设计中的一个根本性的策略,划分的依据是开发团队,而不是以技术特征,是都江堰操作系统当然的选择。把协同工作的团队开发的所有代码称作友好程序,划入一个友好组,而把所有不协同工作的团队以及个人开发的程序当成可疑程序,主要考虑的是人的因素。根据这个原则,操作系统自身的所有代码是由一个核心团队开发的,当然地成为一个友好代码组,操作系统开发团队无需与开发应用程序的团队和个人协作,它把所有应用程序都当作可疑程序;同样,一个应用程序是由一个人或者一个密切协作的团队开发的,该程序的所有代码形成一个友好组,而把所有其他应用程序以及操作系统都视为可疑程序。这与传统的观念不同,传统的观念认为,操作系统是可信程序,而用户程序是非可信程序。 djyos建立篱笆墙隔离友好组,使之不能互相影响和互相破坏,以及提供不同友好组之内完整的命名空间。根据硬件支持情况,友好组之间的保护分为两个级别: 1. 在多进程环境下实现物理隔离,使不同友好组拥有独立的寻址空间,他们之间的代码、数据在物理上互不可见,也就无法互相破坏。实现物理隔离的手段,就是下一节讲述的虚拟机。 2. 在平板内存模式下实现逻辑隔离,在编写软件时,同一个友好组的代码独立编译,拥有独立的命名空间,友好组之间的函数、变量互不可见,使其不能显式地互相破坏,但在物理上,他们共享寻址空间,用绝对地址(比如通过指针)是可以访问其他友好组的数据和代码的。 djyos起源
一直不敢公开这段文字,怕别人笑我,笑一个毫无软件经验的硬件工程师居然不自量力地向linux、vworks、wince等巨头们挑战。然而,计算机界是需要奇迹的,也是孕育奇迹的天堂,辍学的盖茨能盖起微软王国,21岁的linus能够成就linux的世界,我、一个多年经验的硬件工程师、为什么就不能撑起嵌入式操作系统的天空!!! 自1996年从西电应用物理系毕业后,到2001年底的5年半时间里,我一直是个单纯硬件工程师,而且是一个出色的硬件工程师,也有一些得意的硬件作品。在此期间,软件方面就是用51的汇编写过几个程序,大学学过pascal,看过几天谭浩强的C语言书,仅此而已。在那之前,对于操作系统,全部经历就是安装并使用过windows,连做梦都没有想过自己会写一个操作系统出来。2008年,多事的祖国,多事的秋,毫无征兆地发生了汶川大地震,不能亲赴灾区我在哀伤中继续为djyos奋斗,也算我对祖国、对灾区人民的支持吧!与地震不可预测一样,2001年无端地发生了一件注定要改变中国无操作系统格局的事!在那一年的年底,公司有一个项目,要写一个软件,而我刚刚完成了一个硬件项目,软件方面又刚好人手紧张,于是任务就落到我这个毫无软件经验的人头上了。这个软件要涉及到另一门很高深的学科的许多专业知识,这些专业知识我一无所知。当时公司的软件开发管理水平比较低,没有架构设计、系统设计的说法,一上来就动手写程序,连个设计文档都没有的阶段,也没有任何流程来控制这些。我实际上负责的是软件系统结构方面的工作,以及写一些界面、通信、模块管理和底层驱动方面的代码。当时最大的目的,就是设计一个好的结构,使之能够容纳我写的部分代码和另外一些我一无所知的专业算法程序。抱着谭浩强的那本《C程序设计》教材,痛苦地写了几千行核心程序,为整个软件(超过2万行)划分好了模块,设计了模块之间互操作以及交换数据的架子,然后交给专业工程师添加血肉。不觉中,该软件成了公司最好的软件之一,后来的移植到别的平台,只花了很少的时间,后来被移植到许多型号的产品上,该部分代码根本无需修改。直至今天,公司还没有一个有一点规模的软件模块能做到这点,今天的djyos特别强调软件在相同平台的不同产品间移植,与此有关。我完成这个项目后,就又回到自己的老本行——硬件设计上继续工作。连我自己都没有想到的是,这个软件的设计思想会成为djyos的最原始的萌芽。也正因为我是硬件工程师,所以在djyos的设计中,特别强调并支持软硬件一体设计。 后来,由于要上网络,公司决定用vxworks,于是要把现有代码移植到vxworks,在购买vxworks后,接受了windriver公司为期2天的培训,这是我首次接触嵌入式操作系统,说是培训,其实效果很差,那些操作系统的专业名词对我来说就如同天书。说是移植,其实就是在人家写好BSP,安装好操作系统的情况下,做一个大任务,把原来的main函数改个名,做任务入口函数而已,啥也没干。这就是迄今为止我使用实时操作系统做项目的全部经验。 因这个项目,我对软件产生了一些兴趣,开始看一些操作系统的书,并把邵贝贝翻译的《UC/OS-II嵌入式实时操作系统》看了一遍,了解了实时操作系统的设计原理。也就是看书,但没有实际写过ucosii下运行的例程。因与工作无关,也就没有压力和动力,东瞧瞧西瞅瞅而已。后来,因为要做一个linux下的PCI卡驱动程序,根据网上的推荐,买了《LINUX设备驱动程序》和《LINUX内核设计与实现》两本书看,但写出来的驱动程序老有bug,后来这个项目还被取消了,算是学了点linux的皮毛,就没有下文了。这就是我做的与桌面操作系统内核相关的软件开发的全部经历。 时间转眼到了2004年,发生了一件注定值得纪念的事,又一个比原来大的软件项目想让我试试。我当然地以第一个项目为蓝本进行系统架构构思,但不幸的是,这个项目还没有开始就夭折了。然而,我的设计思想可没有因此夭折,我看到了它的闪光点,经搜索发现目前并无操作系统使用相同的设计思路(也许我的搜索不全面),决定用业余时间把它用操作系统的形式实现,并把我的设计思想写成书,于是,就有了今天的djyos和《都江堰操作系统和嵌入式系统设计》一书。也就有了这5年的苦旅,说实话,当初是低估了这东西的复杂度和工作量,否则的话,我是否有这种勇气还很难说。 开发历程是艰难而且曲折的,由于是一个全新的设计思想,现成的东西中没有什么可参考的,一切都需要自己从头探索,自己缺乏软件经验也成了前进路上的拦路虎,开始的时候抱的是谭浩强的《C程序设计》,但很快那本书不够用了,根据网络的推荐,换成《C Primer Plus中文版》了,这本书我电子版和纸版都有。我看书有个习惯,先找电子版,发现是本好书的话,一定会买一个纸版的,即使从来不看纸版,以示对作者的尊重。当然,我的书你不需要去买,下载就行了,只要你看,就是对我的鼓励,如果能在我的论坛上发表书评,或者在臭虫榜上留个脚印,就是对我最大的奖赏。也因为没有参考系,在开发的过程中,多次大规模地推翻原来的方案,你现在看到的是2万行代码,408页文档,实际上的工作量,你乘个1.5后就差不多了。 5年怀胎,一朝分娩,让我们共同呵护djyos,期待他能茁壮成长。
|