系统调用、信号量与读者写者
系统调用、信号量与读者写者
1 简介
下面列出了我在orange源码上修改的原理与具体部分与最终运行截图
2 原理
- 如何添加系统调用?
- 在proc.c中添加系统调用方法,在proto.h中添加声明,修改其他涉及到的数据结构与方法
- 在syscall.asm添加系统调用方法,但这个中断号还是设为0x90,所以初始化中断门(protect.c)也不用再做,sys_call(kernel.asm)也不用再写。记得这个也要在proto.h中添加声明。
- 在global.c中的sys_call_table添加系统调用名,修改const.h 记录table大小的NR_SYS_CALL
- 直接在TestA中调用no_slice(20000),asm与c之间传参用堆栈注意
- 如何实现读者写者?
- 无论是读者优先,写者优先还是公平调度,在充分理解ppt代码后,都可参照ppt的写法。
- 读者最大控制,通过信号量rmax控制
- 进程饥饿问题,让每个读者或写者完成后,让其no_slice几个时间片。注意写者要no_slice更多的时间片,否则写者优先中读者仍会饥饿
3 修改部分
-
在代码里搜索“添加部分”和“修改部分”即可(或直接搜索“部分”)。主要修改的是syscall.asm,proc.c,main.c,global.c。在global.h,proto.h,proc.h,const.h,kernel.asm等文件也做了相应的修改。
-
syscall.asm
-
NR_get_ticks equ 0 ; 要跟 global.c 中 sys_call_table 的定义相对应! _NR_no_slice equ 1 _NR_print_str equ 2 _NR_procedure_p equ 3 _NR_procedure_v equ 4 INT_VECTOR_SYS_CALL equ 0x90 ; 导出符号 global get_ticks global no_slice global print_str global procedure_p global procedure_v
-
; ==================================================================== ; no_slice ; ==================================================================== no_slice: push ecx mov ecx,[esp+8] mov eax, _NR_no_slice int INT_VECTOR_SYS_CALL pop ecx ret ; ==================================================================== ; print_str ; ==================================================================== print_str: push ecx push ebx mov ecx,[esp+12] mov ebx,[esp+16] mov eax, _NR_print_str int INT_VECTOR_SYS_CALL pop ebx pop ecx ret ; ==================================================================== ; procedure_p ; ==================================================================== procedure_p: push ecx mov ecx,[esp+8] mov eax, _NR_procedure_p int INT_VECTOR_SYS_CALL pop ecx ret ; ==================================================================== ; procedure_v ; ==================================================================== procedure_v: push ecx mov ecx,[esp+8] mov eax, _NR_procedure_v int INT_VECTOR_SYS_CALL pop ecx ret
-
-
kernel.asm
-
sys_call: call save sti push ebx push ecx call [sys_call_table + eax * 4] mov [esi + EAXREG - P_STACKBASE], eax pop ecx pop ebx cli ret
-
-
main.c
-
//在kernel_main()中 p_proc->delay_ticks = 0; //添加部分 p_proc->wait = 0; initSemaphore(3,2); //前者为readmax,后者0,1,2分别代表fair,rf,wf
-
//A,B,C,D,E做reader()或writer() void TestE() { int i = 0x2000; while(1){ writer(); } }
-
void TestF() { int i = 0x2000; while(1){ if(readcount==0) print_str("Now Write\n",color(p_proc_ready->p_name[0])); else{ print_str("Now Read ",color(p_proc_ready->p_name[0])); if(readcount==1) print_str("1",color(p_proc_ready->p_name[0])); else if(readcount==2) print_str("2",color(p_proc_ready->p_name[0])); else if(readcount==3) print_str("3",color(p_proc_ready->p_name[0])); else print_str("readcount exceeds 3!",color(p_proc_ready->p_name[0])); print_str("\n",color(p_proc_ready->p_name[0])); }; no_slice(slice); } }
-
-
global.c
-
//修改部分 PUBLIC system_call sys_call_table[NR_SYS_CALL] = {sys_get_ticks,sys_no_slice,sys_print_str,sys_procedure_p,sys_procedure_v}; PUBLIC SEMAPHORE R; PUBLIC SEMAPHORE W; PUBLIC SEMAPHORE S; PUBLIC SEMAPHORE X; PUBLIC SEMAPHORE Y; PUBLIC SEMAPHORE Z; PUBLIC SEMAPHORE RMAX; PUBLIC SEMAPHORE* rmutex; PUBLIC SEMAPHORE* wmutex; PUBLIC SEMAPHORE* s; PUBLIC SEMAPHORE* x; PUBLIC SEMAPHORE* y; PUBLIC SEMAPHORE* z; PUBLIC SEMAPHORE* rmax; PUBLIC int readcount; PUBLIC int writecount; PUBLIC int slice = 10000; PUBLIC int choise; PUBLIC int maxwait;
-
-
proc.h
-
//添加部分 typedef struct s_semaphore{ int value; ///信号量值 PROCESS* psl[100]; //信号量等待进程队列指针 int pos; }SEMAPHORE;
-
//s_proc中添加 int delay_ticks; //为指定的tick数 int wait;
-
-
proc.c
-
PUBLIC void schedule() { PROCESS* p; int greatest_ticks = 0; while (!greatest_ticks) { for (p = proc_table; p < proc_table+NR_TASKS+NR_PROCS; p++) { if (p->delay_ticks>0 || p->wait>0) continue; if (p->ticks > greatest_ticks) { greatest_ticks = p->ticks; p_proc_ready = p; } } if (!greatest_ticks) { for(p=proc_table;p<proc_table+NR_TASKS+NR_PROCS;p++) { if (p->delay_ticks>0 || p->wait>0) continue; p->ticks = p->priority; } } } // disp_str(p_proc_ready->p_name); // disp_str("\t"); // disp_int(p_proc_ready->ticks); // disp_str("\t"); // disp_int((proc_table+3)->priority); // disp_str("\t"); // disp_int((proc_table+3)->ticks); // disp_str("\t"); } /*======================================================================* sys_get_ticks *======================================================================*/ PUBLIC int sys_get_ticks() { return ticks; } //添加部分 /*======================================================================* no_slice *======================================================================*/ PUBLIC void sys_no_slice(int milli_seconds) //暂且认为不分配时间片时,进程有时间片也无法运行 //需要给进程表(即进程表数组的一个元素)添加新的成员变量来记录这段时间的时长 //还要修改schedule() { p_proc_ready->delay_ticks = milli_seconds * HZ / 1000; //时间 = (tick数 * 1000)/HZ,所以 tick数 = 时间 * HZ/1000 schedule(); } /*======================================================================* print_str *======================================================================*/ PUBLIC void sys_print_str(char* str,int color) { // TTY* p_tty = &tty; // int i=0; // while(str[i]!='\0'){ // out_char(p_tty->p_console,str[i]); // i++; // } disp_color_str(str,color); } /*======================================================================* procedure_p *======================================================================*/ PUBLIC void sys_procedure_p(SEMAPHORE* s) { s->value--; if(s->value<0){ p_proc_ready->wait = 1; s->psl[s->pos] = p_proc_ready; s->pos++; schedule(); } } /*======================================================================* procedure_v *======================================================================*/ PUBLIC void sys_procedure_v(SEMAPHORE* s) { s->value++; if(s->value<=0){ s->psl[0]->wait = 0; for(int i=0;i<s->pos;i++){ s->psl[i] = s->psl[i+1]; } s->pos--; } } PUBLIC void initSemaphore(int maxr,int cho) { rmutex = &R; wmutex = &W; s = &S; x = &X; y = &Y; z = &Z; rmax = &RMAX; rmutex->value = 1; wmutex->value = 1; s->value = 1; x->value = 1; y->value = 1; z->value = 1; rmax->value = maxr; rmutex->pos = 0; wmutex->pos = 0; s->pos = 0; x->pos = 0; y->pos = 0; z->pos = 0; rmax->pos = 0; readcount = 0; writecount = 0; choise = cho; maxwait = 15000; } PUBLIC int color(char name){ int print_color; switch(name){ case 'A': print_color = 0x04; //红 break; case 'B': print_color = 0x02; //绿 break; case 'C': print_color = 0x06; //棕 break; case 'D': print_color = 0x05; //洋红 break; case 'E': print_color = 0x03; //青 break; case 'F': print_color = 0x07; //白 break; default: break; } return print_color; } PUBLIC void reader(){ switch (choise) { case 0: reader_FAIR(); break; case 1: reader_RF(); break; case 2: reader_WF(); break; default: print_str("choise must be 0 or 1 or 2",color('0')); break; } no_slice(2*slice); } PUBLIC void writer(){ switch (choise) { case 0: writer_FAIR(); break; case 1: writer_RF(); break; case 2: writer_WF(); break; default: print_str("choise must be 0 or 1 or 2",color('0')); break; } no_slice(5*slice); } PUBLIC void same_reader(){ int reader_color = color(p_proc_ready->p_name[0]); disp_color_str(p_proc_ready->p_name,reader_color); disp_color_str(" ",reader_color); disp_color_str("read begin\n",reader_color); disp_color_str(p_proc_ready->p_name,reader_color); disp_color_str(" ",reader_color); disp_color_str("reading\n",reader_color); char name = p_proc_ready->p_name[0]; switch (name) { case 'A': milli_delay(2*slice); break; case 'B': milli_delay(3*slice); break; case 'C': milli_delay(3*slice); break; default: break; } disp_color_str(p_proc_ready->p_name,reader_color); disp_color_str(" ",reader_color); disp_color_str("read end\n",reader_color); } PUBLIC void same_writer(){ int writer_color = color(p_proc_ready->p_name[0]); disp_color_str(p_proc_ready->p_name,writer_color); disp_color_str(" ",writer_color); disp_color_str("write begin\n",writer_color); //写文件 disp_color_str(p_proc_ready->p_name,writer_color); disp_color_str(" ",writer_color); disp_color_str("writing\n",writer_color); char name = p_proc_ready->p_name[0]; switch (name) { case 'D': milli_delay(3*slice); break; case 'E': milli_delay(4*slice); break; default: break; } disp_color_str(p_proc_ready->p_name,writer_color); disp_color_str(" ",writer_color); disp_color_str("write end\n",writer_color); } PUBLIC void reader_FAIR(){ procedure_p(s); procedure_p(rmax); procedure_p(rmutex); if(readcount==0) procedure_p(wmutex); readcount++; procedure_v(rmutex); procedure_v(s); same_reader(); procedure_p(rmutex); readcount--; if(readcount==0) procedure_v(wmutex); procedure_v(rmutex); procedure_v(rmax); } PUBLIC void writer_FAIR(){ procedure_p(s); procedure_p(wmutex); same_writer(); procedure_v(wmutex); procedure_v(s); } PUBLIC void reader_RF(){ procedure_p(rmax); procedure_p(rmutex); if(readcount==0){ procedure_p(wmutex); } readcount++; procedure_v(rmutex); same_reader(); procedure_p(rmutex); readcount--; if(readcount==0) procedure_v(wmutex); procedure_v(rmutex); procedure_v(rmax); } PUBLIC void writer_RF(){ procedure_p(wmutex); same_writer(); procedure_v(wmutex); } PUBLIC void reader_WF(){ procedure_p(z); procedure_p(rmax); procedure_p(rmutex); procedure_p(x); if(readcount==0) procedure_p(wmutex); readcount++; procedure_v(x); procedure_v(rmutex); procedure_v(z); same_reader(); procedure_p(x); readcount--; if(readcount==0) procedure_v(wmutex); procedure_v(x); procedure_v(rmax); } PUBLIC void writer_WF(){ procedure_p(y); writecount++; if(writecount==1) procedure_p(rmutex); procedure_v(y); procedure_p(wmutex); same_writer(); procedure_v(wmutex); procedure_p(y); writecount--; if(writecount == 0) procedure_v(rmutex); procedure_v(y); }
-
4 运行截图
以下列出几种示例,以下几种情况都已解决进程饥饿问题。
-
readmax=3 公平调度
-
readmax=2 读者优先
- readmax=2 写者优先