操作系统lab4:进程、新增系统调用、读写、消费者生产者

本文详细介绍了操作系统的进程概念,包括进程的定义、进程表、进程栈以及如何通过系统调用来实现进程间的交互。还探讨了时间片在多任务调度中的作用,以及如何在用户程序中调用内核函数。此外,文章还讨论了终端管理,如tty结构体和输出过程。
摘要由CSDN通过智能技术生成

lab4-进程

【操作系统】Oranges学习笔记(五) 第六章 进程_memcpy0的博客-CSDN博客

问答

1、进程是什么?

《操作系统教程》上给出的定义是:进程是具有独立功能的程序在某个数据集合上的一次运行活动,是操作系统进行资源分配和保护的基本单位。

包括了程序计数器(Process Counter)、堆栈(Stack)、数据区域(Data Section)和其他资源、

ORANGE’S(第172页)进行了具体的描述:从宏观来看,进程有自己的功能,且受控于进程调度模块;从微观上来看,它可以利用系统的资源,有自己的代码和数据,同时有自己的堆栈

2、进程表是什么?

进程表就是进程控制块。它用来存储进程的标识信息(唯一标识该进程的信息)、现场信息(处理器运行时的现场信息)和控制信息(与管理、调度相关的信息)。进程创建时建立进程控制块,进程撤销时回收进程控制块,它与进程一一对应。

(来自PPT)PCB是OS用于记录和刻画进程状态及环境信息的数据结构。借助PCB,OS可以全面管理进程的物理实体,刻画进程的执行现状,控制进程的执行。

3、进程栈是什么?

(ORANGE’S第176页):进程运行时自身的堆栈

4、当寄存器的值已经被保存到进程表内, esp 应该指向何处来避免破坏进程表的值?

(ORANGE’S第176页):指向内核栈。

5、tty是什么?

终端,是一种字符型设备。多个终端分占显存的不同位置(但共用显示器和键盘)。

6、不同的tty为什么输出不同的画⾯在同⼀个显示器上?

不同的tty属领的console分别占有显存的不同位置,而通过端口0x3D4和0x3D5可以操纵显示器的寄存器的值从而指定从显存的某个位置开始显示,于是便可以在同一个显示器上输出不同的画面。

7、解释 tty任务执行的过程?

在tty任务完成初始化后,将通过一个循环轮询每一个tty。有两个阶段:

输入处理阶段:如果当前的控制台是轮询到的tty的控制台,他将会读取缓冲区并对得到的输入进行处理(比如处理内存中的键盘缓冲区的扫描码)。

输出处理阶段:如果缓冲区里有内容,则根据内容的情况写显存。

8、tty结构体中⼤概包括哪些内容?

struct s_console;

/* TTY */
typedef struct s_tty
{
   u32    in_buf[TTY_IN_BYTES];  /* TTY 输入缓冲区 */
   u32*   p_inbuf_head;     /* 指向缓冲区中下一个空闲位置 */
   u32*   p_inbuf_tail;     /* 指向键盘任务应处理的键值 */
   int    inbuf_count;      /* 缓冲区中已经填充了多少 */

   struct s_console * p_console;
}TTY;

9、console结构体中⼤概包括哪些内容?

/* CONSOLE */
typedef struct s_console
{
   unsigned int   current_start_addr;    /* 当前显示到了什么位置    */
   unsigned int   original_addr;    /* 当前控制台对应显存位置 */
   unsigned int   v_mem_limit;      /* 当前控制台占的显存大小 */
   unsigned int   cursor;          /* 当前光标位置 */
}CONSOLE;

这里xl还在console里面加了一个8位的无符号成员color(应该是用来完成Lab3的颜色需求的),答的时候可以加上。

10、什么是时间⽚?

《操作系统教程》第5版第105页

调度程序把CPU分配给就绪队列首进程/线程使用的规定的时间间隔

来自xl的blog:时间片是分时操作系统分配给每个正在运行的进程微观上的一段 CPU 时间。

11、 结合实验代码解释什么是内核函数?什么是系统调⽤?

内核函数就是只能在内核态下调用的例程或子程序,比如kliba.asm中的disable_int,关中断显然不是用户进程能直接调用的(实际上这个文件里的所有函数都可以看作是内核函数)。

而ORANGE’S中对于系统调用则有如下实现:

先通过汇编代码(syscall.asm)完成参数的保存与发出中断,跳入内核态。内核态下调用中断处理例程(kernel.asm中)将控制权交给sys_call这一函数处理具体的系统调用型中断,该函数通过表驱动的方式再调用某一具体的系统调用函数(代码实现的位置因人而异)。

假设现在需要在用户程序中向终端输出一段字符串,就可以通过以下流程实现:

  1. 用户程序调用内核函数,将要输出的字符串传入内核函数参数;
  2. 内核通过适当的系统调用向终端输出该字符串;
  3. 结束后返回内核函数。

其中,用户程序调用的是内核函数,内核函数再通过系统调用将参数传递到内核,进行终端输出。具体的系统调用可使用 write 系统调用,例如:

// 内核函数
void print_to_terminal(char *str) {
    int fd = 1; // 1表示标准输出
    ssize_t count = write(fd, str, strlen(str));
    // count表示实际写入的字节数
}

// 用户程序
int main() {
    char *str = "Hello, world!";
    print_to_terminal(str);
    return 0;
}

在上述例子中,用户程序调用了内核函数 print_to_terminal,内核函数中使用了系统调用 write 来将传入的字符串打印到终端上。

1、新增系统调用

proto.h

/* 以下是系统调用相关 */

/* 系统调用 - 系统级 */
/* proc.c */
PUBLIC  int     sys_get_ticks();
// PUBLIC  int     sys_write(char* buf, int len, PROCESS* p_proc);
PUBLIC void sys_print(char * s, int len);
PUBLIC void sys_sleep(int milli);
PUBLIC void sys_p(void * mutex);
PUBLIC void sys_v(void * mutex);

/* syscall.asm */
PUBLIC  void    sys_call();             /* int_handler */

/* 系统调用 - 用户级 */
PUBLIC  int     get_ticks();
PUBLIC  void    myprint(char* s, int len);
PUBLIC  void    mysleep(int milli);
PUBLIC  void    P(void * mutex);
PUBLIC  void    V(void * mutex);
// PUBLIC  void    write(char* buf, int len);

kernel.asm

341-356

sys_call:
    call    save
	;push	dword [p_proc_ready] ;以防发生进程切换,这里在开中断前压入
    
	sti
	
	push	ecx
	push	ebx
    call    [sys_call_table + eax * 4]
	pop		ebx
	pop		ecx

    mov     [esi + EAXREG - P_STACKBASE], eax        
	
	cli
    ret

syscall.asm


; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                               syscall.asm
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                                                     Forrest Yu, 2005
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

%include "sconst.inc"

;必增内容!!!!!!!!!
INT_VECTOR_SYS_CALL equ 0x90
_NR_get_ticks       equ 0
_NR_Print	    equ 1
_NR_Sleep           equ 2
_NR_P               equ 3
_NR_V               equ 4

; 导出符号
global	get_ticks
global	myprint
global  mysleep
global  P
global  V

bits 32
[section .text]

; ====================================================================
;                              get_ticks
; ====================================================================
get_ticks:
	mov	eax, _NR_get_ticks
	int	INT_VECTOR_SYS_CALL
	ret

myprint:
	mov	eax,_NR_Print
	push ebx
	push ecx
	mov	ebx,[esp+12]	;字符串
	mov	ecx,[esp+16]	;颜色
	int	INT_VECTOR_SYS_CALL
	pop	ecx
	pop	ebx
	ret

mysleep:
	mov	eax,_NR_Sleep
	push ebx
	mov	ebx,[esp+8]
	int	INT_VECTOR_SYS_CALL
	pop	ebx
	ret

P:
	push ebx ; 保存Ebx现场
	mov eax, _NR_P
	mov ebx, [esp+8] ; 读取信号量地址
	int INT_VECTOR_SYS_CALL ; 执行中断,通过中断服务例程跳转到内核系统中执行相应操作
	pop ebx; 恢复Ebx现场
	ret ; 返回结果

V:
	push ebx
	mov eax, _NR_V
	mov ebx, [esp+8]
	int INT_VECTOR_SYS_CALL
	pop ebx
	ret

; ====================================================================================
;                          void write(char* buf, int len);
; ====================================================================================
; write:
;         mov     eax, _NR_write
;         mov     ebx, [esp + 4]
;         mov     ecx, [esp + 8]
;         int     INT_VECTOR_SYS_CALL
;         ret

clock.c

19-63
    
/*======================================================================*
                           clock_handler
 *======================================================================*/
// 这个是用于切换进程的
PUBLIC void clock_handler(int irq)
{
    // 时钟中断次数递增
	ticks++;
    // 当前进程的剩余时间片减1
	p_proc_ready->ticks--;
        // 我的修改
    // 从第一个进程循环到最后一个进程
        for(PROCESS* p = proc_table; p < proc_table + NR_PROCS + NR_TASKS; p++){
            // 对需要唤醒的进程进行计时
                if(p->wakeup > 0){
                        p->wakeup--;
                }
        }
    // 如果内核重入标志不为0,则表示当前处理器已在处理中断程序
    // 为了避免重入造成的问题,需要立即返回
	if (k_reenter != 0) {
		return;
	}

    // 如果当前进程还有剩余时间片,则不进行进程调度
	if (p_proc_ready->ticks > 0) {
		return;
	}
        // disp_str("change");
    // 进程时间片用完,进行进程调度
	schedule();

}

/*======================================================================*
                              milli_delay
 *======================================================================*/
PUBLIC void milli_delay(int milli_sec)
{
        int t = get_ticks();

    // 等待指定的时间
        while(((get_ticks() - t) * 1000 / HZ) < milli_sec) {}
}

proc.c

18
    
/*======================================================================*
                              schedule
                              为没有睡眠和阻塞的进程分配时间片
 *======================================================================*/
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->wakeup > 0 || p->block == 1) continue;
			// 正在睡眠/阻塞的进程不会被执行(也就是不会被分配时间片)
			if (p->ticks > greatest_ticks) {
                //分配时间片
				greatest_ticks = p->ticks;
				p_proc_ready = p;
			}
		}
		// 如果都是 0,那么需要重设 ticks
		if (!greatest_ticks) {
			for (p = proc_table; p < proc_table + NR_TASKS + NR_PROCS; p++) {
				if (p->ticks > 0) continue; // >0 还进入这里只能说明它被阻塞了
				p->ticks = p->priority;
			}
		}
	}
}
	
/*======================================================================*
                           sys_get_ticks
 *======================================================================*/    
PUBLIC int sys_get_ticks()
{
	return ticks;
}

PUBLIC void sys_print(char * s, int len){
	CONSOLE *p_con = console_table;
	for (int i = 0; i < len; i++) {
		out_char(p_con, s[i]);
	}
}

// 如果我没有理解错的话,p_proc_ready 是已经在处理机器上运行的进程
PUBLIC void sys_sleep(int milli){
    int ticks = milli / 1000 * HZ * 10;
    //wakeup > 0会被认为正在sleep
	p_proc_ready->wakeup = ticks;
	schedule();// 切换到下一个进程
} 

2、读者写者问题

proc.h


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               proc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/


typedef struct s_stackframe {	/* proc_ptr points here				↑ Low			*/
	u32	gs;		/* ┓						│			*/
	u32	fs;		/* ┃						│			*/
	u32	es;		/* ┃						│			*/
	u32	ds;		/* ┃						│			*/
	u32	edi;		/* ┃						│			*/
	u32	esi;		/* ┣ pushed by save()				│			*/
	u32	ebp;		/* ┃						│			*/
	u32	kernel_esp;	/* <- 'popad' will ignore it			│			*/
	u32	ebx;		/* ┃						↑栈从高地址往低地址增长*/		
	u32	edx;		/* ┃						│			*/
	u32	ecx;		/* ┃						│			*/
	u32	eax;		/* ┛						│			*/
	u32	retaddr;	/* return address for assembly code save()	│			*/
	u32	eip;		/*  ┓						│			*/
	u32	cs;		/*  ┃						│			*/
	u32	eflags;		/*  ┣ these are pushed by CPU during interrupt	│			*/
	u32	esp;		/*  ┃						│			*/
	u32	ss;		/*  ┛						┷High			*/
}STACK_FRAME;

// 进程的状态统统在s_proc这个结构体里面

typedef enum{
	WAITING, WORKING, RELAXING
}STATUS;

//进程的结构体
typedef struct s_proc {
	STACK_FRAME regs;          /* process registers saved in stack frame *//* 进程寄存器,保存在栈帧中 */

	u16 ldt_sel;               /* gdt selector giving ldt base and limit */ // LDT 选择子,用于获取 LDT 的基地址和限制 /
	DESCRIPTOR ldts[LDT_SIZE]; /* local descriptors for code and data */ // 保存代码段和数据段的局部描述符符表 /

        int ticks;                 /* remained ticks */ // 剩余的时钟中断数量 /
        int priority;               // 进程的优先级 /
		int wakeup;
		int block;
		int done;
		STATUS status;
	u32 pid;                   /* process id passed in from MM */
	char p_name[16];           /* name of the process */

	int nr_tty;                 // 进程所在的终端 */
}PROCESS;

// 任务结构体
typedef struct s_task {
	task_f	initial_eip;/* 任务的起始地址 */
	int	stacksize;// / 任务的堆栈大小 /
	char	name[32];//任务的名字 */
}TASK;


/* Number of tasks & procs */
/* 任务和进程的数量 */
#define NR_TASKS	1
#define NR_PROCS	6

// 信号量结构体
typedef struct semaphore
{
	/* data */
	int value;
	PROCESS* queue[NR_PROCS];
} Semaphore;


/* stacks of tasks */
/* 任务的堆栈大小 */
#define STACK_SIZE_TTY		0x8000
#define STACK_SIZE_TESTA	0x8000
#define STACK_SIZE_TESTB	0x8000
#define STACK_SIZE_TESTC	0x8000
#define STACK_SIZE_TESTD	0x8000
#define STACK_SIZE_TESTE	0x8000
#define STACK_SIZE_TESTF	0x8000

/* 所有任务的堆栈大小总和 */
#define STACK_SIZE_TOTAL	(STACK_SIZE_TTY + \
				STACK_SIZE_TESTA + \
				STACK_SIZE_TESTB + \
				STACK_SIZE_TESTC + \
				STACK_SIZE_TESTD + \
				STACK_SIZE_TESTE + \
				STACK_SIZE_TESTF )

proto.h

/* 以下是系统调用相关 */

/* 系统调用 - 系统级 */
/* proc.c */
PUBLIC  int     sys_get_ticks();
// PUBLIC  int     sys_write(char* buf, int len, PROCESS* p_proc);
PUBLIC void sys_print(char * s, int len);
PUBLIC void sys_sleep(int milli);
PUBLIC void sys_p(void * mutex);
PUBLIC void sys_v(void * mutex);

/* syscall.asm */
PUBLIC  void    sys_call();             /* int_handler */

/* 系统调用 - 用户级 */
PUBLIC  int     get_ticks();
PUBLIC  void    myprint(char* s, int len);
PUBLIC  void    mysleep(int milli);
PUBLIC  void    P(void * mutex);
PUBLIC  void    V(void * mutex);
// PUBLIC  void    write(char* buf, int len);

global.c

PUBLIC  TASK    user_proc_table[NR_PROCS] = {
	{reporter_A, STACK_SIZE_TESTA, "reporter_A"},
	{reader_B, STACK_SIZE_TESTB, "reader_B"},
	{reader_C, STACK_SIZE_TESTC, "reader_C"},
	{reader_D, STACK_SIZE_TESTD, "reader_D"},
	{writer_E, STACK_SIZE_TESTE, "writer_E"},
	{writer_F, STACK_SIZE_TESTF, "writer_F"}};

main.c

18-19
char sign[3] = {'X', 'O', 'Z'};
char color[3] = {'\01','\02', '\03'};


23-38
// 读者优先的解决饥饿的办法就是并发量,并发量越高越不会发生饥饿,现在其实就不需要改
// 文件的读写还是需要sleep
PRIVATE void init_tasks()
{

	// 表驱动,对应进程0, 1, 2, 3, 4, 5, 6
	int prior[7] = {1, 1, 1, 1, 1, 1, 1};
	for (int i = 0; i < 7; ++i) {
        proc_table[i].ticks    = prior[i];
        proc_table[i].priority = prior[i];
	}

	// initialization
	k_reenter = 0;
	ticks = 0;

	p_proc_ready = proc_table;
}


112-120
	reader_mutex.value = 1;
	reader_count = 0;
	writer.value = 1;
	reader_count_max.value = 3;
	writer_count = 0;
	writer_mutex.value = 1;
	writer_premission.value = 1;
	read_premission.value = 1;
	S.value = 1;


131-311
    
    PUBLIC void reporter_A(){
    // time slice = 1000
	mysleep(TIMESLICE);
	// int time = 0;
	while(1){
		for(int i = 1; i <= 20; i++){
			printf("%c%c%c ", '\06',i / 10 + '0', i % 10 + '0');
			for(int j = NR_TASKS + 1; j < NR_PROCS + NR_TASKS; j++){
				int proc_status = (proc_table + j)->status;
				printf("%c%c ", color[proc_status], sign[proc_status]);
			}
			printf("\n");
			mysleep(TIMESLICE);
		}
		while(1);
	}
}

PUBLIC void reader_B(){
	while(1){
		// reader_rfirst(2);
		// reader_fair(2);
		read_wfirst(2);
		p_proc_ready->status = RELAXING;
		// mysleep(2000);
		p_proc_ready->status = WAITING;
	}
}

PUBLIC void reader_C(){
	while(1){
		// mysleep(3000);
		// reader_rfirst(2);
		// reader_fair(2);
		read_wfirst(2);
		p_proc_ready->status = RELAXING;
		// mysleep(2000);
		p_proc_ready->status = WAITING;
	}
}

PUBLIC void reader_D(){
	while(1){
		// mysleep(3000);
		// reader_rfirst(3);
		// reader_fair(3);
		read_wfirst(3);
		p_proc_ready->status = RELAXING;
		// mysleep(2000);
		p_proc_ready->status = WAITING;
	}
}

PUBLIC void writer_E(){
	while(1){
		// writer_rfirst(3);
		// writer_fair(3);
		writer_wfirst(3);
		p_proc_ready->status = RELAXING;
		// mysleep(2000);
		p_proc_ready->status = WAITING;
	}
}

PUBLIC void writer_F(){
	while(1){
		// mysleep(2000);
		// writer_rfirst(5);
		// writer_fair(3);
		writer_wfirst(5);
		p_proc_ready->status = RELAXING;
		// mysleep(2000);
		p_proc_ready->status = WAITING;
	}
}
void read_proc(int time_slice){
	p_proc_ready->status = WORKING;
	// disp_str("here");
	mysleep(time_slice);
	// milli_delay(time_slice);
}

void write_proc(int time_slice){
	p_proc_ready->status = WORKING;
	mysleep(time_slice);
	// milli_delay(time_slice);
}

void reader_rfirst(int slices){
	P(&reader_mutex);
		if(reader_count == 0){
			P(&writer);
		}
		reader_count++;
	V(&reader_mutex);
	P(&reader_count_max);
	read_proc(TIMESLICE * slices);
	V(&reader_count_max);
	P(&reader_mutex);
	reader_count--;
		if(reader_count == 0){
			V(&writer);
		}
	V(&reader_mutex);
}

void writer_rfirst(int slices){
	P(&writer);
	write_proc(TIMESLICE * slices);
	V(&writer); 
}

void reader_fair(int slices){
	P(&S);
	P(&reader_count_max);
		P(&reader_mutex);
		if(reader_count == 0){
			P(&writer);
		}
		reader_count++;
	V(&reader_mutex);
	V(&S);
	read_proc(TIMESLICE * slices);
	P(&reader_mutex);
	reader_count--;
		if(reader_count == 0){
			V(&writer);
		}
	V(&reader_mutex);
	V(&reader_count_max);

}

void writer_fair(int slices){
	P(&S);
		P(&writer);
	write_proc(TIMESLICE * slices);
	V(&writer); 
	V(&S);
}

void read_wfirst(int slices){
	P(&reader_count_max);
	P(&read_premission);
	P(&reader_mutex);
	if(reader_count == 0){
		P(&writer_premission);
	}
	reader_count++;
	V(&reader_mutex);
	V(&read_premission);
	read_proc(slices * TIMESLICE);


	P(&reader_mutex);
	if (--reader_count == 0)
		V(&writer_premission); // 没有读者时可以开始写
	V(&reader_mutex);
	V(&reader_count_max);

}

void writer_wfirst(int slices){
	P(&writer_mutex);
	if(writer_count == 0){
		P(&read_premission);
	}
	writer_count++;
	V(&writer_mutex);

	P(&writer_premission);
	write_proc(slices * TIMESLICE);
	V(&writer_premission);

	P(&writer_mutex);
	writer_count--;
	if(writer_count == 0){
		V(&read_premission);
	}
	V(&writer_mutex);
}

实验任务3:生产者消费者问题(2分)

main.c


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"

char sign[3] = {'X', 'O', 'Z'};
char color[3] = {'\01','\02', '\03'};

// 假设p1生产橘子, p2生产apple
PRIVATE void init_tasks()
{

	// 表驱动,对应进程0, 1, 2, 3, 4, 5, 6
	int prior[7] = {1, 1, 1, 1, 1, 1, 1};
	for (int i = 0; i < 7; ++i) {
        proc_table[i].ticks    = prior[i];
        proc_table[i].priority = prior[i];
	}

	// initialization
	k_reenter = 0;
	ticks = 0;

	p_proc_ready = proc_table;
}

PUBLIC int clean_screen(){
    disp_pos = 0;
    for (int i = 0 ; i < SCREEN_SIZE; ++i){
        disp_str(" ");
    }
    disp_pos = 0;
}
/*======================================================================*
                            kernel_main
 *======================================================================*/
PUBLIC int kernel_main()
{
	disp_str("-----\"kernel_main\" begins-----\n");


	clean_screen();

	TASK*		p_task		= task_table;
	PROCESS*	p_proc		= proc_table;
	char*		p_task_stack	= task_stack + STACK_SIZE_TOTAL;
	u16		selector_ldt	= SELECTOR_LDT_FIRST;
        u8              privilege;
        u8              rpl;
        int             eflags;
	for (int i = 0; i < NR_TASKS+NR_PROCS; i++) {
                if (i < NR_TASKS) {     /* 任务 */
                        p_task    = task_table + i;
                        privilege = PRIVILEGE_TASK;
                        rpl       = RPL_TASK;
                        eflags    = 0x1202; /* IF=1, IOPL=1, bit 2 is always 1 */
                }
                else {                  /* 用户进程 */
                        p_task    = user_proc_table + (i - NR_TASKS);
                        privilege = PRIVILEGE_USER;
                        rpl       = RPL_USER;
                        eflags    = 0x202; /* IF=1, bit 2 is always 1 */
                }

		strcpy(p_proc->p_name, p_task->name);	// name of the process
			p_proc->pid = i;            // pid
		p_proc->wakeup = 0; // 初始化结构体新增成员
		p_proc->block = 0;
		p_proc->status = RELAXING;		// pid
		p_proc->total = 0;
		p_proc->ldt_sel = selector_ldt;

		memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3],
		       sizeof(DESCRIPTOR));
		p_proc->ldts[0].attr1 = DA_C | privilege << 5;
		memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3],
		       sizeof(DESCRIPTOR));
		p_proc->ldts[1].attr1 = DA_DRW | privilege << 5;
		p_proc->regs.cs	= (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl; // 初始化寄存器
		p_proc->regs.ds	= (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.es	= (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.fs	= (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.ss	= (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | rpl;
		p_proc->regs.gs	= (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl;

		p_proc->regs.eip = (u32)p_task->initial_eip;
		p_proc->regs.esp = (u32)p_task_stack; 
		p_proc->regs.eflags = eflags;

		p_proc->nr_tty = 0;

		p_task_stack -= p_task->stacksize;
		p_proc++;
		p_task++;
		selector_ldt += 1 << 3;
	}


    /**
     * empty_mutex
     */
	empty_mutex.value = 5;
	full_mutex.value = 0;
	apple_mutex.value = 0;
	orange_mutex.value = 0;
	consume_apple_mutex.value = 1;
	init_tasks();  // 扳机

	init_clock(); // 在这里实现了时钟的中断
        // init_keyboard(); // 在这里实现了键盘的中断
	restart();

	while(1){}
}

PUBLIC void reporter_A(){
	mysleep(TIMESLICE);
	// int time = 0;
	while(1){
		for(int i = 1; i <= 20; i++){
			printf("%c%c%c ", '\06',i / 10 + '0', i % 10 + '0');
			for(int j = NR_TASKS + 1; j < NR_PROCS + NR_TASKS; j++){
				int num = (proc_table + j)->total;
				// if(j == NR_TASKS + 1){
				// 	num = num - (proc_table + j + 2)->total;
				// }
				// else if(j == NR_TASKS + 2){
				// 	num = num - (proc_table + j + 2)->total - (proc_table + j + 3)->total;
				// }
				printf("%c%c%c ", '\06',num / 10 + '0', num % 10 + '0');
			}
			printf("\n");
			mysleep(TIMESLICE);
		}
		while(1);
	}
}

PUBLIC void p_orange(){
	while(1){
	P(&empty_mutex);
	produce_porc();
    mysleep(1000);
    V(&orange_mutex);
//	V(&full_mutex);
	}
}

PUBLIC void p_apple(){
	while(1){
	P(&empty_mutex);
	produce_porc();
    mysleep(1000);
    V(&apple_mutex);
//	V(&full_mutex);
	}
}

PUBLIC void c_orange(){
	while(1){
//	P(&full_mutex);
	P(&orange_mutex);
	consume_proc();
    mysleep(1000);
    V(&empty_mutex);
	}
}

PUBLIC void c_apple_1(){
	while(1){
//	P(&consume_apple_mutex);
//	P(&full_mutex);
	P(&apple_mutex);
	consume_proc();
    mysleep(1000);
    V(&empty_mutex);
//	V(&consume_apple_mutex);
	}
}

PUBLIC void c_apple_2(){
	while(1){
//	P(&consume_apple_mutex);
//	P(&full_mutex);
	P(&apple_mutex);
	consume_proc();
    mysleep(1000);
    V(&empty_mutex);
//	V(&consume_apple_mutex);
	}
}

PUBLIC void produce_porc(){
	p_proc_ready->total++;
//	mysleep(1000);
}

PUBLIC void consume_proc(){
	p_proc_ready->total++;
//	mysleep(1000);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值