第二部分:系统结构
在symbian os上运行的四种软件
应用程序
服务
引擎
内核
symbian系统使用活动对象与客户-服务器对事件处理系统进行了优化
硬件资源:
一个cpu,32位arm
一个rom(只读存储器),里面有操作系统与内建的中间件和应用程序
ROM盘被映射到z:盘,所有的文件都可以通过Z:盘访问。
系统RAM.系统RAM用于两个方面,一是被当前活动的程序和系统核心使用,另一个是当成”C”盘的磁盘空间。这两个部分的大小是变化的,不可以保留某个的大小。由于RAM通常只有8MB到16MB,所以内存可能用完,因此经常出现内存越界错误或是(写文件时)磁盘已满错误
IO设备,包括带数字笔输入的触摸屏,键盘,记忆卡(被当成D盘),rs232串口,红外口,蓝牙。
电源,包括电池与外接电源
symbian os与pc系统的区别如下:
资源限制:cpu太慢与太少内存
没有硬盘,不能使用写到硬盘的虚拟内存,不能保证有足够的空间保存程序或是数据文件
电源条件严格.
symbian软件环境如下:
server | server| Application| Application | Application Dll
| | +————–+————- boundary
| | | |
| | | Enghine | Engine
——–+———+————+————–+————– Privilege
boundary
Kernel
kernel工作在高级别,管理机器所有硬件资源。对其它软件模块提供访问这些硬件资源的接口
其它应用程序工作在用户模式
上面如果理解普通操作系统如linux的话,那跟普通操作系统没有区别
应用程序是一个有用户界面的程序,在独立的进程中运行
这与普通操作系统也没有区别
服务是没有用户界面的程序.服务管理一个或多个资源,并提供api,让客户可以访问它的服务.服务的客户可以是一个程序或是其它服务.每个服务也运行在独立的进程空间中。
在symbian中,使用服务的形式提供类似其它操作系统上用驱动程序或是内核程序提供的功能。如文件系统的访问也是客户/服务类型的。(微内核
)引擎是一个应用程序中操作数据而不是与用户交互的部分.通常你可以把一个程序分成引擎部分和一个GUI部分,多部symbian内带的程序都是这样做的。
一个应用程序引擎可以是一个独立的代码模块或是一个独立的dll,或是几个dll.
引擎和应用程序间的边界是模块或dll的边界。
所以在symbian中有四个组件类型与三个边界类型。dll或是模块组件对交叉引用来说很方便。它们使系统模块化与保持封装。
权限边界对交叉引用比较费资源,但是保证系统对用户太程序隐藏内核与设备
进程边界是所有的交叉中最昂贵的,它们保证在ram中分开每个程序
可执行文件的格式
在symbian中有两种类型的可执行文件:
exe,每个程序都有一个主入口E32main()(看上面的例子),它在独立的进程中运行
dll,提供多个入口,由系统或是已存在的线程(进程)调用
有两种类型的dll,
共享库dll,为一个或多个程序提供固定的api,这些dll多数后缀是.dll,当程序启动时就被读到内存中。
多态dll,这些dll实现抽象的api,如一个打印机驱动,socket协议或是一个应用程序。它们的扩展名多不是.dll,而是.prn或.prt或.app等。它们从与dll相关的类继承,并通常只有在程序需要它们时才读入。
从技术上看起来与普通系统上动态库的静态载入与动态载入没有区别
但是从功能上看就不一样了,一种是实现某种特殊功能的,从某个相关类继承的dll,另一个是普通dll
代码执行
如果程序代码在rom上,则直接执行,不然需要读到ram中(与普通操作系统不同,普通操作系统都需要读到ram中
不能直接在硬盘上执行)
可执行代码包括三种类型的二进制数据:
程序代码
只读静态数据
可写静态数据
在symbian中对待.exe与.dll是不同的
由于.exe是不可共享的,如果它在ram中执行,那与普通pc系统没有区别,如果在ram中执行,那它在ram中为可写静态数据分配内存
而.dll是共享的,当dll首次读入内存中时,它被分配到一个特殊的地址,第二个线程需要这个dll时它只要访问已经存在的这份copy就可以。在所有使用它的进程中dll的地址都是相同的。symbian系统维护一个引用计数,当没有其它线程引用时才将它unload.
在rom上的dll像rom上的exe一样直接在rom上执行
为了对dll的大小进行优化,symbbian进行如下操作;
多数系统支持通过名字与通过数字访问dll提供的入口,由于名字太长,浪费空间,所以symbian只提供通过数字访问,当然在link时可以通过名字link.也就是说在.dll中没有名字访问办法,在.lib(引导库,引导linker正确的link这个dll,这个是在windows中使用的概念,在win下每创建一个dll都会创建一个用户引导链接的同名.lib)中有,你的程序link时link的是.lib,link完成后编译器会自动把引用dll的代码变成数字引用
如果dll被读到ram,那重定位信息(把dll
load到什么地址)也必须包含在可执行文件格式中,这个的影响就是你不能把一个在rom中执行的程序放到ram中执行的程序.(rom中执行的多是oem厂家,所以普通开发者多不用关心)
多数应用程序有自己有exe来创建进程,其它的程序使用动态库(DL)L的形式,在主服务线程中调用自己的线程
多数gui程序都是多态(polymorphic)dll,有一个主入口点NewApplication(),这个入口点创建并返回一个继承自CEikAppication的对象.这样的程序被apprun.exe调用,app文件名为参数传入。
电源管理
电源必须高效使用
在系统已经关机时,确定程序仍然可以运行。如闹钤,关机后,到时时仍然可以开机
电源突然关掉时,关键数据应该可以保存
设备驱动
虽然一般不会了解它,但是理解一下还是很有用的
设备驱动工作在两个级别
第一个是中断服务程序(ISR),ISR必须很短,并且不能做很多事情,因为它可能在任何时间出现,甚至在内核服务中。通常它只是通知设备产生了中断并设置一个标志,要求内核为第二阶段的处理运行一个延迟的函数调用(delayed function call DFC)
在方便的时候内核调度DFC.DFC可以使用多数的核心api,通常只是工作了后向用户线程通知io操作已经完成
定时器
` 内核支持真机上64hz的时钟与模拟器上10hz的时钟
时钟中断是最高优先级中断,它可以通过User::After或是RTime::After访问。时钟中断在关机时停止,所以如果你请求5s后的定时操作,然后跑2s,关机,再开机时它也要等3s
内核同时支持日期/时间时钟,你可以使用User::At或是RTime::At。这个定时器很准确。在关机时,如果时间到了,那它会开机,这对闹钟很合适。
内存
symbian使用内存管理单元(memory management unit MMU)管理内存
ROM被映射到z:盘,被映射到一个固定的地址。
物理RAM被MMU分在4k的页,每个物理页可以用于:
用户进程的虚地址空间。
内核服务的虚地址空间
ram盘,盘符是c:,ram盘只可通过文件服务进程访问
如果dll不在rom中,那它被读到ram,dll被读到ram里面后页面标记为只读只读的。
MMU的页面转换表.如果想理解的话学习一下操作系统原理
自由页表
每个进程的地址空间可以分成下面三类:
系统范围的内存,如系统的rom或是读到ram中的dll
进程范围的内存,如进程的.exe映象和它的可写的静态数据
每个线程的内存,包括线程的栈与线程默认的堆(使用线程默认堆的原因只是为了提高内存分配与释放的速度,从开发角度来看,它与系统里面的内存没有区别)。
注意没有交换文件,所以所有的内存都是直接使用。同时,也可能会发生内存不够或是磁盘(c
已满错误每个线程的默认栈很小,只有12k,所以在symbian开发中,不要放太多东西到栈中,一般对象都是在堆中分配的。
线程创建后,它的栈大小就不可再改变。
线程可以使用new或是User::Alloc从线程默认堆中分配内存.如果希望从其它堆中分配内存,只能使用new
动态库(DLL)
symbian中dll不支持可写的静态数据,所以你在里面不可能使用可写的全局变量或是静态变量.
为什么不支持呢?如果支持,那每个进程调用这个dll时,都需要为这个进程分配一个独立的堆,而堆最小单位是4k,系统中有很多堆,并且有很多程序,所以内存消费基金是很大的。所以就不支持了
这样开发时不是很不方便?因为在dll中有时需要保存自己的状态,进行交互
为了解决这个问题,symbian中引入了线程本地数据(thread-local storage
TLS)概念(查看Dll::Tls
Dll;;SetTls)。但是调用TLS性能比较慢.tls的最大大小是1.8k 通常这够用了。
文件:
c: flash ram盘
z: rom盘
d: 记忆棒之类的外挂盘
事件处理
事件处理模型如下图:
keyborad |—————————
|interrupt
|
kernel/driver–+-isr/dfc
|
key event
|
|
window serv—–handle key event———–+update window
| |
|key event draw |request
application +—————– handle ———-+
key event
在symbian中使用活动对象(active object)来处理事件
在symbian os中,所有的symbian
os线程都是事件处理器,每个线程有一个活动调度对象,加上一个或多个活动对象来处理从设备或其它程序发过来的事件。
每个活动对象都有一个虚拟的成员函数RunL(),在这个函数里面处理事件。
多任务与抢占式
symbian os实现抢占式多线程。
活动对象用于在单个线程内实现非抢占式多任务