📄 2.html
字号:
4.2.3得到指向下一个要执行线程的指针<br>
4.2.4在线程的执行队列的队尾追加一个线程<br>
4.2.5在线程的执行队列的队头追加一个线程<br>
4.2.6将等待队列中优先级最高的线程提出队列执行<br>
4.2.7从等待队列中删除独占资源的线程<br>
4.2.8此时用到的调度算法<br>
4.2.9将一个线程变为运行态<br>
4.2.10终止该线程目前的调度算法<br>
4.2.11为一个新的线程创建调度参数<br>
4.2.12改变线程的调度状态<br>
4.2.13优先级迁移<br>
4.2.14基于某种原因,线程被送回等待队列<br>
4.2.15返回优先级最高的处于等待状态的线程<br>
4.2.16改变线程的优先级<br>
4.2.17优先级继承<br>
4.2.18不继承优先级<br>
4.2.19优先级递减<br>
本 章 小 结<p>
第五章 OSKIT的应用实例 一个简单系统的设计与实现<br>
5.1设计目的<br>
5.2系统的功能<br>
5.3 我们自己所完成的工作:<br>
5.3.1 系统的启动<br>
5.3.2 线程管理<br>
5.3.3 外设(串口)<br>
5.4 用户手册<br>
5.4.1 安装<br>
5.4.2 用户编程接口<br>
5.4.3 应用程序示例<br>
本 章 小 结<p>
第六章 结束语<p>
后 记
<center><A HREF="#Content">[目录]</A></center>
<hr><br><A NAME="I557" ID="I557"></A><center><b><font size=+2>前言</font></b></center><br>
OSKit的线程机制 前言<br>
2000年12月18日 22:28<p>
<br>
作 者: 汤海京<p>
<br>
导师:陈朔鹰<p>
<br>
课题名称:基于面向对象操作系统开发平台(OSKit)的分析与程序设计<br>
课题来源:自拟题目<p>
如果说自由软件的出现是一个偶然的话,那么,席卷全球的Linux热潮则是一个奇迹,它正以势不可挡的趋势迅猛发展,其前途不可限量。<p>
Linux内核源代码的开放给希望深入操作系统内部世界的人们提供了可能,但随之而来的问题是,当我们要开发自己的操作系统时,由谁来读系统的kernel部分呢。对这部分的处理从逻辑上分析不外乎三种方式:全部保留、对其进行裁减、全部推倒重来。很显然,最后一种方法是不可能的,而如果我们采用的是第一种方法,其结果当然一定可以满足我们的要求,但是,最后编译出来的核心将十分的庞大,尤其是对嵌入式操作系统的开发者来说,是不能忍受的,所以,大多数开发者采用的第二条路。<p>
但是,第二条路也非平坦的大道,道理很简单,你要想对kernel进行裁减,首先你应该将全部的源代码阅读一遍,并且将其中的相关性理顺,然后才能谈到裁减,所以工作量也十分的庞大。<p>
然而,OSKit的出现改变了这一切,它使得我们不需要将精力集中在kernel源代码的阅读上,因为kernel部分的源程序已经由OSKit的开发人员替你分析过了,他们将源码全部模块化,并将所有模块之间的相关性写在了文档之中,呈现在你的面前,这与你自己分析源代码的结果是一样的。<p>
OSKit最本质的东西和Linux一样,体现在"自由"和"开放"的思想,"自由"意味着世界范围内的知识共享,由于OSKit出现在Linux之后,其设计思想继承了Linux的精髓,所以说它的出现并不完全是美国犹它大学计算机科学系FLUX研究组的功劳,而应该是"自由"的结果。"开放"则意味着OSKit对所有的人都敞开大门,在这种开放而自由的天地里,你可以中分发挥自己的创造才能。<p>
在后面的几章里,我将向大家系统地介绍我的全部研究成果-OSKit的线程机制,希望读者能在最短的时间内了解OSKit,更希望大家能本着"自由"与"开放"的精神加入到我们的研究中来,为中国的自由软件事业贡献自己的一份热情。<p>
我写这篇论文力求达到一个目的,那就是让这篇论文在搞研究的人眼里是一本参考书,而在程序设计者眼中是一本函数手册,既有理论指导,又不是泛泛的空谈理论。<p>
由于本人能力有限,论文中的有些术语表达可能不妥,内容也可能不够准确,敬请各位老师和同学批评指正,本人不胜感激。<p>
<br>
汤海京 2000年6月14日<p>
<p>
<center><A HREF="#Content">[目录]</A></center>
<hr><br><A NAME="I558" ID="I558"></A><center><b><font size=+2>第一章 绪 论</font></b></center><br>
OSKit的线程机制 第一章<br>
2000年12月18日 22:34<p>
<br>
作 者: 汤海京<p>
<br>
导师:陈朔鹰<p>
<br>
第一章 绪 论<p>
<br>
1.1 简介<p>
OSKit是由美国犹它大学计算机科学系FLUX研究组编写的一套模块化部件和库函数,用于架构操作系统内核、服务器以及其他的OS级软件。我们设想一下,在一个操作系统的研发项目中,底层模块的开发工作会占去大部分时间,并耗费掉开发人员的大部分精力。而OSKit的出现恰恰弥补了这个缺陷,其设计意图是提供一套可重用的模块,让使用者避开复杂的底层,把精力集中在他们感兴趣的问题上,也就是说,当开发人员拿到OSKit之后,便立刻拥有了一个完整而且安全的核心,使他们可以集中精力研发操作系统的高层次问题,如作业控制、虚存、IPC、文件系统、系统安全以及高级语言(如Java、Lisp或ML)等。这样可以大大丰富操作系统的应用层,为用户提供更多更好的服务,提高操作系统的运行效率,增强操作系统的安全性和稳定性,从而使你的操作系统更加具有魅力。<p>
对于站在操作系统技术最前沿的多线程编程和成熟的作业控制系统,以及时下最流行的嵌入式操作系统,OSKit都提供了支持。通过几个月以来对美国犹它大学计算机科学系FLUX研究组网站的追踪,我们注意到OSKit的版本大约每三个月就更新一次,我们在毕业设计初期拿到的是99年7月的版本,而我们写演示程序是用的2000年5月的版本,在此期间又出现了99年12月版和2000年2月版,而且在每次发布的版本里都有许多新的算法公布,还有许多老版本中的BUG被修改;这说明OSKit不但一直处于操作系统开发平台的最前沿,而且其自身也在不断的完善。<p>
通过对OSKit深入细致的分析与研究,我们发现犹他大学的开发人员们从一开始就确定了自己的目标,那就是对OSKit进行模块化,仿佛Windows中的动态连接库一样,让后来者即使不使用OSKit中的某一部分,仍然可以使用其余部分来完成他们的目标。这样的设计思路十分灵活,为开发者和使用者都提供了便利。<p>
<br>
1.2 安装与配置OSKit<p>
当我们从犹他大学得到OSkit的五月版时,它是个压缩包,使用tar在linux下解开后,就得到了源码,这需要我们在linux下重新编译。<p>
目前,编译OSKit需要以下的工具:<p>
GNU make<br>
GNU CC (gcc) 2.95.2版。<p>
注意:到目前为止,我们使用的Redhat Linux 6.2中的GCC并不是2.95.2,如果要成功编译OSKit,需要先将我们的GCC升级。当然,如果你使用的是Turbo linux 6.0的话,它提供的就是GCC 2.95.2。<p>
在开始编译OSKit之前,我们必须注意一点,那就是要对源码进行一点改动,让它支持实时操作,即将 /oskit20000505/threads/MakeFlage 中的:<br>
# OSKIT_CFLAGS + = -DPTHREAD_SCHED_EDF -DPTHREAD_REALTIME 中的注释符号 # 去掉。<p>
由于我们的环境是Linux,所以论文中的根目录用"/"表示,而不是Windows中的"\"。<p>
由于我们是在intel 586上编译,而我们的目标机要支持到intel 386,所以我们应该在OSKit的目录下键入:<p>
./configure ――host=i586 ――target=i386<br>
此后键入make,编译OSKit。<p>
当OSKit编译好以后,你可以用"make install"命令来安装它。在缺省的情况下,这些库会被安装到/usr/local/lib中,而头文件会被安装到/usr/local/include中,除非你在配置时使用了--prefix选项来指定它。所有的OSKit头文件都安装在oskit/子目录中(例如/usr/local/include/oskit),不会和已经存在的任何头文件冲突。即使是库被安装在主库的目录中(如/usr/local/lib),所有的库文件都有前缀oskit_,这可以避免和其它不相关的库混淆在一起。<p>
<br>
1.3 使用OSKit<p>
一开始,为了能让大家尽快熟悉OSKit,犹他大学的研发人员们给出了许多很具代表性的例子供使用者进行试验,而我们的课题组也编写了一个小型的操作系统,供学习研究之用。<p>
OSKit中库的设计是很经典的,开发者们花费了大量时间清楚地标出了每个库与其它库的依赖关系,这使得OSKit不但保留了操作系统的原汁原味,而且还把库之间的相关性降低到了最低限度,使得使用者可以随意增减其中的库函数。实际上,在很多情况下,特别是在某些函数库中,为了有效的使用OSKit,必须替换掉其中的一些函数或符号,以适应我们的执行环境。要重载某个库中的函数或者符号,只要在你的核心或应用程序中再定义一遍就可以了,LINK程序会确保去使用你所定义的函数和符号。由于在Linux下的编译器是靠读取Makefile文件来确定编译连接的对象以及规则,所以我们认为直接修改Makefile文件要比修改OSKit源码更加方便而且安全,这与Windows下的工程文件十分相似。<p>
如果使用OSKit所提供的模块化部件和库函数编写出了自己的操作系统核心代码,并且对在LINUX下用GCC编译源码有所了解的话,就可以借助OSKit为使用者提供的一整套核心制作命令和LINUX提供的GCC来生成自己的核心文件zImage,然后使用LINUX命令DD将核心写入一张1.44MB的软盘,重新启动计算机,从软盘引导就可进入我们自己编写的操作系统了。<p>
另外,考虑到用户环境复杂多样的实际情况,OSKit还提供了对许多种操作系统的支持,包括Linux、Mach 、BSD或者MS-DOS,当我们用GCC将源码编译成"filename.o"的格式之后,使用OSKit提供的不同的核心制作命令来生成不同操作系统下的核心,其具体实现是由mkbsdimage、mklinuximage和mkdosimage来完成的。这些脚本在OSKit的安装和配置阶段会根据你指定的环境自动安装完毕。在每一个脚本运行的时候都有各自不同的参数。<p>
<br>
1.4 OSKit 导航图<p>
OSKit所提供的功能被分成三类:接口、函数库和部件库<p>
1.4.1 接口<p>
OSKit的接口非常清晰,并且是面向对象的。这些接口全部被定义在C语言的头文件中,我们分别对其加了必要的注释,以方便使用者快速掌握OSKit。这些接口被OSKit的各个部件共享,从而体现了各部件之间的一致性。操作系统的开发人员既可以直接使用它,也可以在其上定义目标操作系统的接口结构。<p>
1.4.2 函数库<p>
OSKit的函数库以C语言中面向函数的方式提供基本的服务。一个库中的函数对另一个库中函数的依赖关系已经被降至最低的程度,如果这种依赖是不可避免的话,那他们已经被很清楚地标注出来,展现给了操作系统的开发人员。函数库很少使用OSKit的面向对象的COM接口,取而代之的是在C的头文件中定义自己的面向函数的接口。这种设计策略为操作系统开发人员提供了灵活性和极大的技术支持;要适应任何特殊的操作系统环境,底层的OSKit工具必须具有可扩展性。<p>
1.4.3 部件库<p>
OSKit的部件库使使用者能站在更高的层次来编程,即面向对象的"黑盒"方式。尽管OSKit的"部件"在缺省情况下也是被打包成为普通的链接库,但它们的结构则是被设计程面向对象的,而不是传统的面向函数的方式。与OSKit的函数库相比,部件库通常只对外开放一些相关的公用调用接口,而不是大量的功能。例如,在Linux和BSD的驱动程序部件库里,每一个完整的驱动程序仅呈现为一个单独的函数调用,这个调用用来初始化并注册驱动程序。<p>
1.4.4 执行环境<p>
OSKit中的许多部件在核心和用户方式下都可以使用,这就需要对部件的执行环境作出定义,例如部件什么时候可以嵌套进入等。此外,OSKIT使用了许多其它操作系统的代码,例如设备驱动程序和网络协议栈,都是原封不动的从原有的核心如BSD和Linux中借用来的,OSKit通过附加代码模拟原始执行环境使的这些执行模块比它们原始执行环境更简单,用户也不需要详细了解原执行环境的细节。下面对OSKIT的每种执行模块进行简单的介绍。<p>
纯执行模块:这是OSKit执行环境中最简单的一个模块,这些部件或函数中没有全局变量或静态变量,只使用和处理由目标环境传递来的数据。例如函数strlen,它只通过目标环境传递给它的字符串指针求出字符串的长度,并将其返回,它只接触参数数据域,而不影响目标环境。当这些函数使用的数据集是分离的,它们可以安全地同时被调用,而不需要同步,反之则不行。例如对重叠的目标缓冲区并发使用memcpy调用时不安全的。<p>
非纯执行模块:这些模块中使用了全局变量或有可能改变全局共享状态,例如liboskit_kern(核心支持库)中的许多函数建立和访问全局处理器寄存器和数据结构,因此它们是非纯执行模块。非纯执行模块有以下特点:非纯函数和部件可能依赖于全局状态,如全局变量,静态变量,处理器中的特殊寄存器等。除非有明确的声明,非纯函数和部件是不可重入的,并且运用在多线程系统中也是不安全的。为了在一个多线程/多处理器环境中使用这些函数和部件,目标操作系统必须提供适当的同步代码。<p>
阻塞模块:它扩展了非纯模块来支持非抢先的多线程,这些模块中有一类可重入的函数称为阻塞函数,在这模块中,除非明确声明为非阻塞函数,否则函数是阻塞的。为了在一个完全抢先的、可中断的或者多处理器的环境中使用阻塞模块,必须在进入模块前加锁,在退出模块时将锁释放。<p>
可中断阻塞模块:在它之中每个部件都是一个单线程的执行域,在一个给定的时刻,只有一个(虚拟的或者物理的)CPU可以执行部件中的代码。例如:在一个多处理器系统中,在进程级别下,任意时刻在一个部件集内只有一个CPU被允许执行;这能够通过在部件前后放置全局锁来实现。<p>
在一段时间内,部件中可以存在多个活动进程,但在某时刻只有一个进程被执行。目标操作系统给每个活动进程提供一个独立堆栈,这个堆栈在阻塞函数运行时被保留。只有在操作完成后,对部件的调用返回时才放弃该堆栈。部件中的代码总是运行在两个级别中之一,进程级或中断级。有意思的是一些部件的函数和方法只能在进程级别被调用,而另一些只能在中断级别被调用,还有的能在任何级别被调用。调用的细节属于接口描述的一部分。<p>
部件中无论进程级别或中断级别的操作都能被部件中的中断处理程序中断,除非代码调用osenv_intr_disable屏蔽了中断。当部件在进程级运行时,OSKIT假定中断开放,部件在处理过程中可能临时屏蔽掉中断,但必须在返回到目标操作系统前重新激活。同样,当部件在中断级运行时,OSKIT假定中断被屏蔽,但是部件可以在目标操作系统允许其它中断级别的活动中断该部件时重新激活中断。<p>
当目标操作系统在一个部件内中断一个进程级别的活动时,在继续这个活动前,操作系统必须执行完这个中断级别的活动。同理,若一个中断级的活动被中断,那么最近的中断级别的活动必须在继续前一个中断级别的活动之前完成。部件中运行在中断级别的代码不能调用目标操作系统提供的阻塞回调函数;只有非阻塞的回调函数能够在中断级别被调用。<p>
<p>
<br>
<center><A HREF="#Content">[目录]</A></center>
<hr><br><A NAME="I559" ID="I559"></A><center><b><font size=+2>第二章 线程初始化</font></b></center><br>
《OSKit的线程机制 第二章》<p>
<p>
<br>
OSKit的线程机制 第二章2000年12月18日22:59<p>
<br>
作 者: 汤海京<p>
<br>
导师:陈朔鹰<p>
<br>
第二章 线程初始化<p>
<br>
前面我们曾经谈到,在OSKit中资源分配和调度的单位是线程而不是传统意义上的进程,所以我们有必要花大量的时间对其线程机制做全面的分析。当然,要分析线程部分,首先应该从线程的初始化入手,然后才能涉及到线程间的通信以及线程调度,所以本章将向各位全面系统地介绍OSKit的线程初始化。<p>
为了让大家能清楚地掌握OSKit的线程部分,在以后的三章内,我将采用理论实际相结合的论述方式,即在每章的开始先论述本章所要讨论的线程机制,以期让大家在概念上对本章有总体上的认识,然后再针对OSKit的源代码做进一步的阐述,希望能理论实践双丰收。<p>
<br>
2.1 线程初始化分析<p>
2.1.1线程的创建<p>
在OSKit中,用户创建一个新线程的唯一方法就是调用创建线程的线程pthread_create。<p>
内核为系统调用pthread_create完成如下操作:<p>
(1) 为新线程在线程表项中分配一个空槽。<br>
(2) 赋给子线程一个唯一的标识号<br>
(3)制作一个父线程上下文的逻辑副本。由于线程的某些部分,如正文区,可能被几个线程所共享,所以内核只要增加某个区的引用计数即可,而不用真的将该区拷贝到一个新的内存物理区。<br>
(4)增加与该线程相关的文件表和索引节点表的引用数。<br>
(5) 向父线程返回子线程的线程号。<p>
系统对一个用户可以同时运行的线程数有一个限制(这个限制是可以改变的),因而任何用户不能使用过多的线程表项,不然的话,就会妨碍其他用户创建新线程,而且,OSKit为了防止死锁,规定了普通用户不能占用线程表项中的最后一个线程,这条规定是从UNIX中演变而来的。<p>
2.1.2线程的存储<p>
OSKit的线程存储方案与UNIX十分相似,由三个逻辑段组成,它们是正文段、数据段和栈。正文段含有一个线程所执行的指令集合,正文段的地址包括正文地址(用于分支和子程序调用)、数据地址(用于存取全局数据变量)和栈地址(为了存取子程序的数据结构)。<p>
若机器将生成的地址看作物理存储器中的地址,那么,两个线程在它们所生成的地址集合重叠了的情况下,是不可能并发执行的。虽然编译器可以产生在程序之间不重叠的地址,但这样的程序对于通用计算机是行不通的,因为一种机器上的存储容量是有限的,而所有可能被编译的程序集合是无限的。采取此种方法可以在很大程度上避免数据的丢失。<p>
2.1.3线程的数据结构<p>
以下我列出了OSKit中线程的完整的数据结构,其中大部分是从UNIX中继承来的,但也有一些是OSKit自己的,例如,为了制作例子程序所提供的CPU资源分配的部分。<p>
为了使各位一目了然,我对此数据结构做了全部注释,并按照其不同应用领域划分成了几个部分,分别加在了下面的注释之中。<p>
queue_chain_t runq; /* 释放队列链 */<br>
pcb_t *ppcb; /*指向PCB的指针 */<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -