当前位置:Linux教程 - Linux文化 - OSKit包装系统驱动程序 第五章

OSKit包装系统驱动程序 第五章


第五章 OSKit的应用实例--一个简单系统的设计与实现


1. 设计目的

OSKit是一个用来帮助我们研发操作系统的工具,如果你想更好的掌握它,除了对其本身进行分析之外,还有一个更加实际的方法,那就是利用这个工具开发一个我们自己的操作系统。

我们开发这个系统的初衷主要是为了学习,因此并没有想把它设计成像Windows、UNIX那么复杂。我们的目标是很明确的,那就是在大致搞明白OSKit应当如何使用之后,做一次尝试,用较短的时间,设计出一个具有一些最基本功能的系统。这对于我们课题组的每名成员来说,都意味着挑战。


2. 系统的功能

这个系统支持些什么?这是在开始设计之前我们要首先确定的一个问题。下面列出了一些我们希望实现的功能。
通过Multiboot或者LILO进行系统引导:这个系统可以通过所有支持Multiboot的引导程序进行引导,或者通过引导Linux的LILO进行引导。引导方式可以根据用户的要求,选择是通过软盘还是硬盘。
多线程:用户可以通过我们提供的系统调用,创建或杀死自己的线程。由于并不支持文件系统,因此新的线程恐怕只能是一个函数了。从理论上讲,我们可以让这个系统支持很多线程,但因为这仅仅是一个简单的演示性系统,因此我们把线程数限制在32个,当然这个数字也可根据用户的需求任意更改。
进程间通信:这个系统可以支持一些简单的进程间通信机制,比如信号量、消息队列等等。
外设:在众多的外设之中,我们选择了应用范围比较广的串口。利用目前OSKit所提供的机制,支持更多的设备是不成问题的,但加在这个系统中意义并不十分的大。另外,需要强调的是,访问串口的方法,是由我们自己规定,不允许用户更改。
简单的内存管理:应用程序需要的内存可以通过malloc函数动态申请。


3. 总体构想

在该操作系统中,我们规定用户只能创建用户级线程,所有对于核心的操作都将由系统来完成。线程采用RR调度算法,也就是时间片轮转法,并允许抢占,线程在该系统中有四种状态,它们是运行态、阻塞态、睡眠态和就绪态,用户可以设定和改变线程的优先级。在线程中用户可以动态申请内存,但是需要由用户来释放。线程间提供简单的通信机制,包括信号量和消息队列。

在设备方面,对于终端,本系统将提供简单的输入输出功能。而对于串口的功能,本系统可以完整的实现,也就是说,用户既可以从串口读也可以向串口写。

为了方便起见,我们为这个系统起一个很简单的名字,叫acos,这个名字并没有什么实际的意义,仅仅为了叫起来方便。

虽然OSKit已经为我们提供了很多设计操作系统所必须的功能,比如内存分配中的malloc函数,通过Multiboot引导等等。然而,仍有许多工作是要由我们自己完成。


4. 我们自己所完成的工作:

4.1 系统的启动

这里我们所说的系统启动,并不是指通常人们所说的通过软盘或硬盘引导,而是在引导结束之后,操作系统的核心进程如何启动第一个用户进程。通常,在UNIX系统中,内核启动之后,内核程序会去执行文件系统上的init程序,这个程序是整个操作系统中的第一个用户进程,剩下的进程,都必须通过这个进程才能启动。在acos中,我们规定,用户必须要提供一个acos_init()函数,系统在启动初始化工作全部完成之后,acos_init()函数将被作为系统中的第一个进程启动。这之后的工作,就完全由用户来完成了。

当进程acos_init() 结束时,整个系统也将终止运行。

在acos_init()启动之前,究竟还有哪些事情需要做呢?下面我们就列出要做的事情:

对整个系统进行初始化,注册设备,检测设备,初始化设备需要的数据结构,初始化线程库,创建线程需要的数据结构,初始化使串口能在多线程环境下正常工作的数据结构。

4.2 线程管理

所谓操作系统的线程管理,一般包括了一下的三大部分:线程的创建,线程间通信和线程调度。

线程的创建包括了初始化线程和创建线程的属性。

线程间通信中,我们使用了信号量,条件变量。

在线程调度中,用户线程只能使用时间片轮转法作为调度算法,并且规定在调度过程中调度算法不允许更改。

4.3 外设(串口)

在UNIX系统中,所有的设备都可以通过文件系统进行访问,读、写设备就像读写文件一样。在我们设计的这个acos中,并没有对文件系统提供支持,也不提供像读写文件系统一样的方法来访问设备。但是,我们提供一套基本的函数,供用户线程对串口进行读写操作,这些函数专门用于处理串口。

一个设备在同一时刻只能被一个线程使用,因此,在使用设备以前要申请,只有申请成功的线程才能够使用设备。


5. 使用方法

5.1 安装

使用者需要在Linux下键入 tar -zxvf acos-0.0.1.tar.gz 。

./setup ,详细的安装信息请参见README文件。

5.2 使用

根据我们所提供的API手册编写自己的应用程序,然后将这些应用程序的源文件编译成一个filename.o,用户通过执行acbuild filename.o命令将该应用程序与操作系统内核相链接。根据你所希望使用的引导方法执行mkXXXimage命令生成所需要的核心映像,选择恰当的装入程序装入启动核心映像。

5.3 用户编程接口

如果您对操作系统的概念有所了解,并详细阅读了我们为您提供的技术文档之后,便可以利用用户编程接口自行开发了。以下我将向各位详细介绍每个接口所提供的功能,希望对您能有所帮助。

5.3.1 管理线程的API :

线程创建
ac_thread_create ( void *name, void *arg, int *out_thread_id );
设置线程的优先级
ac_thread_setprio(int thread_id, int pri);
撤销线程
ac_thread_cancel(int thread_id);
线程休眠
ac_thread_sleep(ac_s64_t millisecond);
将该线程与某一个线程相关联
ac_thread_join(int tid, void **status);

5.3.2 管理互斥量的API

初始化互斥量
ac_mutex_init ( ac_pthread_mutex_t* mutex,
ac_pthread_mutexattr_t* attr);
设置互斥量协议
ac_mutexattr_setprotocol ( ac_pthread_mutexattr_t* attr,
int protocol);
设置互斥量类型
ac_mutexattr_settype ( ac_pthread_mutexattr_t* attr,
int type);
初始化互斥量属性
ac_mutexattr_init(ac_pthread_mutexattr_t* attr);
互斥量加锁
ac_mutex_lock(ac_pthread_mutex_t *mutex);
互斥量解锁
ac_mutex_unlock(ac_pthread_mutex_t *mutex);
撤销互斥量
ac_mutex_destroy(ac_pthread_mutex_t *mutex);

5.3.3 管理IPC的API

消息发送( IPC机制 )
ac_ipc_send ( int thread_id, void* msg, ac_size_t msgsize,
ac_s32_t timeout);
3.2消息接受( IPC机制 )
ac_ipc_recv(int thread_id, void* msg, ac_size_t msgsize,
ac_size_t *actual, ac_s32_t timeout);
消息等待( IPC机制 )
ac_ipc_wait(int *src_id, void *msg, ac_size_t msgsize,
ac_size_t *actual, ac_s32_t timeout);
接受同步消息
ac_ipc_reply(int desthread, void *msg, ac_size_t msg_size);
发送同步消息
ac_ipc_call(int dst, void *send_msg, ac_size_t send_msg_size,
void *recv_msg, ac_size_t recv_msg_size,
ac_size_t *actual,ac_s32_t timeout);

5.3.4 管理条件变量的API

条件变量初始化
ac_cond_init(ac_pthread_cond_t *cond,
ac_pthread_condattr_t* attr);
某线程等待条件变量
ac_cond_wait(ac_pthread_cond_t *cond,
ac_pthread_mutex_t *mutex);
唤醒等待该条件变量的线程
ac_cond_signal(ac_pthread_cond_t *cond);
符合条件变量的线程广播:
ac_cond_broacast(ac_pthread_cond_t *cond);

5.3.5 硬件部分

打开串口
ac_serial_open(int serial_num, ac_u32_t flags);
监听串口
ac_serial_listen(int serial_num, ac_u32_t flags);
关闭串口
ac_serial_close(ac_ttystream_t* a_stream);
从串口读
ac_serial_read(ac_ttystream_t* s, void *buf, ac_u32_t len,
ac_u32_t *out_actual);
往串口写
ac_serial_write(ac_ttystream_t* s, const void *buf,
ac_u32_t len, ac_u32_t *out_actual);

5.4 应用程序示例

为了让使用者能够对我们的这个小系统有更加深入的了解,我们制作了一些例子供使用者参考。这些例子包括最简单的"Hello World",串口读写、线程调度、线程间通信,哲学家算法等等。

应用程序的示例可以在examples目录下找到。