四 川 大 学
操作系统课程设计报告
学 院: 软件 学院
专 业: 软件工程专业
年 级: 07级
组 编 号: 第 X组
组 成 员: 乔心轲(姓名) 0743111340(学号)
何赵平(姓名) XXXXXXXX(学号)
崔蓉 (姓名) XXXXXXXX(学号)
张雯(姓名) XXXXXXXX(学号)
康小芳(姓名) XXXXXXXX(学号)
提交时间: 2009年 月 日
指导教师评阅意见:
.
. .
. .
指导教师评阅成绩:XXX1:
XXX1:
XXX1:
XXX1:
XXX1:
实验项目一
项目名称:
实验目的:
实验时间:
人员分工:
实验环境:
实验环境的搭建过程、选用的操作系统、机器配置、编译器等。
实验内容:
对实践过程的详细说明,针对已经满足的实践要求,采用了何种算法或思想,对Nachos平台的哪些代码进行了什么样的修改。
实验结果:
对实践要求的满足程度,代码是否编写完成,是否调试通过,能否正常运行,本项目的要求中共满足了哪几项。
参考文献:
实验项目二
实验项目名称:Nachos中的线程管理
实验项目目的:
1.最多能够同时存在128个用户线程
2.改变为遵循“优先级调度”的抢占式调度
参与人员及分工:
乔心轲,何赵平,康小芳完成主要代码编写;
崔蓉,张文进行程序的测试及维护。
实验环境:
n Nachos: Not Another Completely Heuristic Operating System
n Linux
n Gcc
n Windows
实验内容:
1.对于最多能够同时存在128个用户线程,我们在Thread.cc中声明了一个static变量numOfThreads;具体代码如下:
static int numOfThreads = 0;//the count of the threads
在Thread的构造函数中对其值进行加1;即每创建一个线程时,都会把numOfThreads加1;
++numOfThreads;
并在SimpleThread()中进行了如下修改,完成了最多能够同时存在128个用户线程。
static void
SimpleThread(int which)
{
if(numOfThreads<128){
for(inti=0;i<(kernel->currentThread->Time())-(kernel->currentThread->executeTime)+2;i++){
cout << "*** thread " <<which<<" looped "<<kernel->currentThread->executeTime<<" times.\n";
cout<<"priority "<<kernel->currentThread->Priority()<<"\n";
kernel->currentThread->Yield();
}
}
else{
if(count == 0)
printf("The number of the threads can not be larger than 128!\n");
kernel->currentThread->Yield();
count++;
}
}
为了实现遵循“优先级调度”的抢占式调度策略,首先为Thread增加了三个变量:executeTime;time;priority
在Thread.h中对它们的声明:
public:
Thread(char* debugName); // initialize a Thread
~Thread(); // deallocate a Thread
// NOTE -- thread being deleted
// must not be running when delete
// is called
int executeTime;//The time that this thread has executed
// basic thread operation
void setExTime(int exT);//set the executeTime of the thread to exT
int Time();//return the time that the thread should be served
void setTime(int t);//set the time that the thread should be served to t
void setPriority(int pri); //set the priority of the thread to pri
int Priority(); //return the priority of the thread
private:
// some of the private data for this class is listed above
int time; // the time that the thread should be served int priority; //the priority of each thread
在Thread.cc中的实现:
Thread::Thread(char* threadName)
{
name = threadName;
stackTop = NULL;
stack = NULL;
status = JUST_CREATED;
for (int i = 0; i < MachineStateSize; i++) {
machineState[i] = NULL; // not strictly necessary, since
// new thread ignores contents
// of machine registers
}
space = NULL;
executeTime=1;
setPriority(0);
setTime(2);
}
在Fork()中对numOfThreads进行了+1操作:
void
Thread::Fork(VoidFunctionPtr func, void *arg)
{
Interrupt *interrupt = kernel->interrupt;
Scheduler *scheduler = kernel->scheduler;
IntStatus oldLevel;
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg);
StackAllocate(func, arg);
oldLevel = interrupt->SetLevel(IntOff);
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
// are disabled!
(void) interrupt->SetLevel(oldLevel);
++numOfThreads;
}
//---------------------------------------------------------------------
//Thread::setExTime
// set the executeTime of the thread to exT
//---------------------------------------------------------------------
void
Thread::setExTime(int exT){
executeTime = exT;
}
//---------------------------------------------------------------------
//Thread::setPriority
// set the priority of the thread to pri
//---------------------------------------------------------------------
void
Thread::setPriority(int pri)
{
priority=pri;
}
//---------------------------------------------------------------------
//Thread::Priority
// return the priority of the thread
//---------------------------------------------------------------------
int
Thread::Priority(){
return priority;
}
//---------------------------------------------------------------------
//Thread::setPriority
// set the time of the thread to t
//---------------------------------------------------------------------
void
Thread::setTime(int t){
time=t;
}
//---------------------------------------------------------------------
//Thread::Time
// return the time of the thread need to run
//---------------------------------------------------------------------
int
Thread::Time(){
return time;
}
并在SimpleThread()中进行了如下修改:
static void
SimpleThread(int which)
{
if(numOfThreads<128){
for(int i=0;i<(kernel->currentThread->Time())-(kernel->currentThread->executeTime)+2;i++){
cout << "*** thread " <<which<<" looped "<<kernel->currentThread->executeTime<<" times.\n";
cout<<"priority "<<kernel->currentThread->Priority()<<"\n";
kernel->currentThread->Yield();
}
}
else{
if(count == 0)
printf("The number of the threads can not be larger than 128!\n");
kernel->currentThread->Yield();
count++;
}
}
对Scheduler.cc中进行了以下修改,实现了按照优先级进行线程的调度,返回最高优先级的线程,让其运行。
Thread *
Scheduler::FindNextToRun ()
{
ASSERT(kernel->interrupt->getLevel() == IntOff);
if (readyList->IsEmpty()) {
return NULL;
} else
{
Thread *highestPri = readyList->RemoveFront();
for (int i =1;i<readyList->NumInList();i++){
if(readyList->IsEmpty()){
return highestPri;
}
if(readyList->Front()->Priority()<=highestPri->Priority()){
readyList->Append(highestPri);
highestPri = readyList->RemoveFront();;
}
}
return highestPri;
}
}
并在Run()中进行了以下修改:在Run()代码的最后加了以下语句:
kernel->currentThread->setPriority(kernel->currentThread->Priority()+1);
kernel->currentThread->setExTime(kernel->currentThread->executeTime+1);
实验结果和结论:
对实验进行的测试,首先编译通过测试:
经过编译测试,程序已完成了以上要求,具体测试如下:
对遵循“优先级调度”抢占式调度的实现:
void
Thread::SelfTest()
{
DEBUG(dbgThread, "Entering Thread::SelfTest");
for(int i=0;i<=3;i++){
Thread *t = new Thread("forked thread");
t->setPriority(3-i);
t->Fork((VoidFunctionPtr) SimpleThread, (void *) numOfThreads);
}
}
对最多只有128个用户线程存在的实现:
参考文献:
实验项目三
实验项目名称:Nachos中的文件管理系统
实验项目目的:
? 实现多个线程同时存在内存,虚拟地址到物理地址的转换,限制程序大小,不实现缺页中断处理
? 不实用虚拟内存
? 维护二类页表
– 实页页表(空闲页表):操作系统维护
(Machine中创建)——nachos现在有多少页表是可以供用户使用
– 线程页表:各线程维护自己的页表
参与人员及分工:
乔心轲,何赵平,康小芳完成主要代码编写;
崔蓉,张文进行程序的测试及维护。
实验环境:
n Nachos: Not Another Completely Heuristic Operating System
n Linux
n Gcc
n Windows
实验内容:
首先是在Machine.h中对空闲页表及其相关函数进行了声明:
TranslationEntry *freePageTable; //空闲页表
TranslationEntry NextFreePage();//下一个空闲的页
int NumOfFreePage(); //剩余空闲页的数目
其次在Machine.cc中空闲页表进行初始化以及函数的实现:
Machine::Machine(bool debug)
{
int i;
for (i = 0; i < NumTotalRegs; i++)
registers[i] = 0;
mainMemory = new char[MemorySize];
for (i = 0; i < MemorySize; i++)
mainMemory[i] = 0;
freePageTable = new TranslationEntry[NumPhysPages];
for (i = 0; i < NumPhysPages; i++) {
freePageTable[i].virtualPage=i;
freePageTable[i].physicalPage = i;
freePageTable[i].valid = TRUE;
freePageTable[i].use = FALSE;
freePageTable[i].dirty = FALSE;
freePageTable[i].readOnly = FALSE;
}
#ifdef USE_TLB
tlb = new TranslationEntry[TLBSize];
for (i = 0; i < TLBSize; i++)
tlb[i].valid = FALSE;
pageTable = NULL;
#else // use linear page table
tlb = NULL;
pageTable = NULL;
#endif
singleStep = debug;
CheckEndian();
}
//----------------------------------------------------------------------
//Machine::NextFreePage()
//----------------------------------------------------------------------
TranslationEntry
Machine::NextFreePage(){
for(int i = 0;i<NumPhysPages;i++)
{
if(freePageTable[i].valid==TRUE)
return freePageTable[i];
}
}
//----------------------------------------------------------------------
//Machine::numOfFreePage()
//----------------------------------------------------------------------
int
Machine::NumOfFreePage(){
int num = 0;
for(int i = 0;i<NumPhysPages;i++)
{
if(freePageTable[i].valid==TRUE)
num++;
}
return num;
}
对AddrSpace.cc的修改如下:
AddrSpace::AddrSpace()
{
}
AddrSpace::~AddrSpace()
{
if(pageTable!=NULL){
for(int i=0;i<numPages;i++){
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
delete pageTable;
}
}
为了实现限制程序大小以及实现线程页表和空闲页表的转换,对代码进行了如下修改:
bool
AddrSpace::Load(char *fileName)
{
OpenFile *executable = kernel->fileSystem->Open(fileName);
NoffHeader noffH;
unsigned int size;
if (executable == NULL) {
cerr << "Unable to open file " << fileName << "\n";
return FALSE;
}
executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
if ((noffH.noffMagic != NOFFMAGIC) &&
(WordToHost(noffH.noffMagic) == NOFFMAGIC))
SwapHeader(&noffH);
ASSERT(noffH.noffMagic == NOFFMAGIC);
#ifdef RDATA
// how big is address space?
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
noffH.uninitData.size + UserStackSize;
// we need to increase the size
// to leave room for the stack
#else
// how big is address space?
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size
// to leave room for the stack
#endif
numPages = divRoundUp(size, PageSize);
size = numPages * PageSize;
ASSERT(numPages <= NumPhysPages); // check we're not trying
// to run anything too big --
// at least until we have
// virtual memory
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
pageTable = new TranslationEntry[numPages];
if(kernel->machine->NumOfFreePage()>=numPages){
for(int i=0;i<numPages;i++){
TranslationEntry temp = kernel->machine->NextFreePage();
pageTable[i].virtualPage=temp.virtualPage;
pageTable[i].physicalPage=temp.physicalPage;
pageTable[i].valid=FALSE;
pageTable[i].use=FALSE;
kernel->machine->freePageTable[temp.physicalPage].valid = FALSE;
kernel->machine->freePageTable[temp.physicalPage].use = TRUE;
}
//sgeTable[i].virtualPage=0;
// then, copy in the code and data segments into memory
// Note: this code assumes that virtual address = physical address
int i=0;
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
for(;i<(noffH.code.size/PageSize);i++){
executable->ReadAt(
&(kernel->machine->mainMemory[pageTable[i].physicalPage]),
PageSize, noffH.code.inFileAddr+i*PageSize);
cout<<"Page "<<pageTable[i].virtualPage<<" for code segment is used!\n";
}
}
cout<<"Page for code is allocated\n";
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
for(;i<(noffH.code.size/PageSize)+(noffH.initData.size/PageSize);i++){
executable->ReadAt(
&(kernel->machine->mainMemory[pageTable[i].physicalPage]),
PageSize, noffH.initData.inFileAddr+i*PageSize);
cout<<"Page "<<pageTable[i].virtualPage<<" for data segment is used!\n";
}
}
#ifdef RDATA
if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment.");
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
for(;i<(noffH.code.size/PageSize)+(noffH.initData.size/PageSize)+(noffH.readonlyData.size/PageSize);i++){
executable->ReadAt(
&(kernel->machine->mainMemory[pageTable[i].physicalPage]),
PageSize, noffH.readonlyData.inFileAddr+i*PageSize);
cout<<"Page "<<pageTable[i].virtualPage<<" for readOnlydata segment is used!\n";
}
}
#endif
}
else{
cout<<"Not enough space for the program!\n";
delete pageTable;
}
delete executable; // close file
return TRUE; // success
}
实验结果和结论:
程序已编译通过,实现了
1.多个线程同时存在内存,虚拟地址到物理地址的转换,限制程序大小,不实现缺页中断处理
2.维护二类页表
(1)实页页表(空闲页表):操作系统维护(Machine中创建)——nachos现在有多少页表是可以供用户使用
(2)线程页表:各线程维护自己的页表
具体如下:
编译通过:
测试:
参考文献:
实验项目四
实验项目名称:Nachos中的文件管理模块升级
实验项目目的:
l 多个线程不能同时对一个文件进行写操作,因为会发生冲突,但是可以同时进行读操作.
l 将简单的通过信号量进行控制的同步机制修改为读者/写者问题的机制.
l 实现目录结构的多级机制
参与人员及分工:
实验环境:
n Nachos: Not Another Completely Heuristic Operating System
n Linux
n Gcc
n Windows
实验内容:
实现多个线程不能同时对一个文件进行写操作,因为会发生冲突,但是可以同时进行读操作. 将简单的通过信号量进行控制的同步机制修改为读者/写者问题的机制:
在SynchDisk.h中的修改如下:
private:
int readcount; //count the number of the readers
int writecount; //count the number of the writers
Disk *disk; // Raw disk device
Semaphore *x;
Semaphore *y;
Semaphore *z;
Semaphore *wsem;
Semaphore *rsem;
在SynchDisk.cc中的构造函数中对信号量进行初始化。
SynchDisk::SynchDisk()
{
x = new Semaphore("synch disk", 1);
y= new Semaphore("synch disk", 1);
z = new Semaphore("synch disk", 1);
wsem= new Semaphore("synch disk", 1);
rsem= new Semaphore("synch disk", 1);
lock = new Lock("synch disk lock");
disk = new Disk(this);
readcount=0;
writecount=0;
}
在SynchDisk.cc中的析构函数中把信号量的指针删除。
SynchDisk::~SynchDisk()
{
delete disk;
delete lock;
delete x;
delete y;
delete z;
delete wsem;
delete rsem;
}
在ReadSector函数中进行的修改如下:
void
SynchDisk::ReadSector(int sectorNumber, char* data)
{
while(TRUE)
{
z->P();//只有一个读进程可以进入
rsem->P();
x->P();
readcount++;
if(readcount==1)
wsem->P();
x->V();
rsem->V();
z->V();
x->P();
lock->Acquire();
disk->ReadRequest(sectorNumber, data);
lock->Release();
x->V();
readcount--;
if(readcount==0)
wsem->V();
x->V();
}
}
void
SynchDisk::WriteSector(int sectorNumber, char* data)
{
while(TRUE){
y->P();
//多个写进程可以进行排队
writecount++;
if(writecount==1)
rsem->P();
y->V();
wsem->P();
lock->Acquire();
disk->WriteRequest(sectorNumber, data);
lock->Release();
wsem->V();
y->P();
writecount--;
if(writecount==0)
rsem->V();
y->V();
}
}
实现目录结构的多级机制:
创建了一个SubFileHeader类:
主要就是把FileHeader的内容拷贝过去了;
然后在FileHeader中进行了如下修改:
bool
FileHeader::Allocate(PersistentBitmap *freeMap, int fileSize)
{
int hdr_size;
SubFileHeader *subHdr[30];
numBytes = fileSize;
if(fileSize<NumDirect*SectorSize)
{
printf("filehdr.cc 50 -->\n");
numHdrSectors = divRoundUp(fileSize, SectorSize);
if (freeMap->NumClear() < numHdrSectors)
return FALSE; // not enough space
for (int i = 0; i < numHdrSectors; i++)
dataSectors[i] = freeMap->FindAndSet();
return TRUE;
}
else{
numHdrSectors= divRoundUp(fileSize, SectorSize*30);
if (freeMap->NumClear() < numHdrSectors*NumDirect)
return FALSE; // not enough space
for (int i = 0; i < NumDirect; i++){
dataSectors[i] = -1;
}
for(int i=0;i<numHdrSectors;i++)
{
subHdr[i]= new SubFileHeader;
dataSectors[i]=freeMap->FindAndSet();
printf("Another file header in sector %d \n",dataSectors[i]);
if(i<numHdrSectors-1)
subHdr[i]->Allocate(freeMap, 30*SectorSize);
else if(i==numHdrSectors-1)
subHdr[i]->Allocate(freeMap, fileSize-30*SectorSize*i);
subHdr[i]->WriteBack(dataSectors[i]);
printf("filehdr 63\n");
}
}
delete subHdr;
return true;
}
//----------------------------------------------------------------------
// FileHeader::Deallocate
// De-allocate all the space allocated for data blocks for this file.
//
// "freeMap" is the bit map of free disk sectors
//----------------------------------------------------------------------
void
FileHeader::Deallocate(PersistentBitmap *freeMap)
{
if(numBytes<NumDirect*SectorSize)
{
for (int i = 0; i < numHdrSectors; i++) {
ASSERT(freeMap->Test((int) dataSectors[i])); // ought to be marked!
freeMap->Clear((int) dataSectors[i]);}
}
else{
for (int i = 0; i < numHdrSectors; i++) {
SubFileHeader *hdr= new SubFileHeader;
hdr->FetchFrom(dataSectors[i]);
hdr->Deallocate(freeMap);
}
}
}
实验结果和结论:
程序已编译通过,并实现了
1.多个线程不能同时对一个文件进行写操作,因为会发生冲突,但是可以同时进行读操作.
2.将简单的通过信号量进行控制的同步机制修改为读者/写者问题的机制.
3.实现目录结构的多级机制
首先,编译通过:
参考文献:
《操作系统原理》实验报告院(部):管理工程学院专业:信息管理与信息系统实验项目:实验一二三五班级:信管102姓名:学号:目录引言.…
西安郵電大學操作系统设计报告题目进程线程互斥锁院系名称计算机学院班级1104学生姓名赵大伟学号8位04113124指导教师舒新峰设…
操作系统课程论文院系班级姓名学号指导教师完成时间东莞理工学院摘要本文分析面向对象教学操作系统EOS的系统结构和代码构成通过源代码分…
操作系统课程设计实验报告姓名学号班级地点20xx年月日任务说明共完成四个任务任务一IO系统调用开销比较任务二实现一个简单的shel…
《操作系统原理》实验报告院(部):管理工程学院专业:信息管理与信息系统实验项目:实验一二三五班级:信管102姓名:学号:目录引言.…
操作系统课程设计报告专业学号姓名提交日期操作系统课程设计报告设计目的1本实验的目的是通过一个简单多用户文件系统的设计加深理解文件系…
上海电力学院计算机操作系统原理课程设计报告题目名称编写程序模拟虚拟存储器管理姓名杜志豪学号20xx1798班级20xx053班同组…
课程设计说明书设计题目操作系统课程设计班级信管学号姓名山东科技大学20xx年12月15日课程设计任务书学院信息学院专业信息管理与信…
南通大学计算机科学与技术学院操作系统实验报告班级软件工程121姓名金凯学号11020xx019指导老师戴树贵时间19周一周1程序流…
《课程设计报告》的格式要求撰写课程设计报告参考格式:题目(居中,小三号黑体字)学生姓名(学号)(学生姓名之间两格)(一律采用五号宋…