Loading

系统调用、信号量与读者写者

系统调用、信号量与读者写者

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 写者优先
posted @ 2020-12-24 11:35  iterationjia  阅读(159)  评论(0编辑  收藏  举报