上篇文章中我们虽然实现了多进程,但是要扩展起来就太麻烦了。如果我们要新加一个进程,就得添加进程体,添加进程堆栈空间,将PCB表的个数加1,在Init_PCB函数中复制一大段代码来填充新加进程的PCB,这样显得不够优雅,特别是最后一段代码中重复的代码比较多,进程与进程之间的区别无非就是执行体和堆栈不同而已,按照书中作者的做法,是把这两样东东作为一个新的结构的成员,作者也是模仿MINIX的做法罢了。
我们下面就来做吧,我们还是只有两个进程。下面在proc.h中定义一个TASK结构,就是用来存放各进程的执行体的地址和堆栈地址:
- typedef struct s_task
- {
- Task_Func eip;
- u32 stack_size;
- }TASK;
其中task_f是新定义的类型,定义在type.h中:
- typedef void (*Task_Func)();
接着就要声明和定义一个TASK类型的结构数组了,显然有多少个进程这个数组就应该有多少个TASK,为了方便引用进程的个数,在proc.h中定义一个表示进程数量的宏:
- #define PROC_NUM 2
OK,来到global.h和global.c中,定义一个TASK类型的结构数组:
- extern TASK Task_Tables[]; /* in global.h */
- #include "proto.h"
- TASK Task_Tables[PROC_NUM] = { {Proc_A,PROC_A_STACK_SIZE},
- {Proc_B,PROC_B_STACK_SIZE}
- }; /* in global.c */
在global.c中,由于在定义中用到进程的执行体的函数名,所以要包含proto.h头文件,在MAKEFILE中也要作相应修改,PROC_A_STACK_SIZE和PROC_A_STACK_SIZE定义在proc.h中,代表该进程的堆栈大小:
- # #define PROC_NUM 2
- # #define PROC_A_STACK_SIZE 0x8000
- # #define PROC_B_STACK_SIZE 0x8000
- # #define PROC_STACK_SIZE_TOTAL (PROC_A_STACK_SIZE + /
- PROC_B_STACK_SIZE)
其中,PROC_STACK_SIZE_TOTAL是进程堆栈空间的总和,我们也不再每添加一个进程就添加一个堆栈空间了,而是统一分配到一个数组空间去,在global.h和global.c中做相应修改,把Proc_A_Stack和Proc_B_Stack的声明和定义分别删掉,添加总的堆栈空间:
- extern u8 Proc_Stack_Space_Total[]; /* in global.h */
- u8 Proc_Stack_Space_Total[PROC_STACK_SIZE_TOTAL]; /* in global.c */
接下来就改动填充进程相应的PCB的部分了,用一个循环就可以减少重复的代码,在Init_PCB中把原来的代码全部删掉,再来添加:
- void Init_PCB()
- {
- PCB *p_Cur_PCB = PCB_Tables;
- TASK *p_Cur_Task = Task_Tables;
- u8 *p_Cur_Top_Of_Stack = Proc_Stack_Space_Total + PROC_STACK_SIZE_TOTAL;
- u16 Cur_LDT_Index = INDEX_OF_FIRST_LDT;
- u32 i;
- for(i = 0 ; i < PROC_NUM ; i++)
- {
- Memory_Set(p_Cur_PCB,sizeof(PCB),0);
- Memory_Copy(&GDT[1],&p_Cur_PCB->ldts[0],sizeof(Descriptor));
- Memory_Copy(&GDT[2],&p_Cur_PCB->ldts[1],sizeof(Descriptor));
- p_Cur_PCB->ldts[0].attr1 &= 0x9f;
- p_Cur_PCB->ldts[0].attr1 |= DA_DPL1;
- p_Cur_PCB->ldts[1].attr1 &= 0x9f;
- p_Cur_PCB->ldts[1].attr1 |= DA_DPL1;
- p_Cur_PCB->stack_frame.ds = 0 + 4 + 1;
- p_Cur_PCB->stack_frame.es = 0 + 4 + 1;
- p_Cur_PCB->stack_frame.gs = 24 + 1 ;
- p_Cur_PCB->stack_frame.fs = 0 + 4 + 1;
- p_Cur_PCB->stack_frame.ss = 0 + 4 + 1;
- p_Cur_PCB->stack_frame.esp = (u32)p_Cur_Top_Of_Stack;
- p_Cur_PCB->stack_frame.cs = 8 + 4 + 1;
- p_Cur_PCB->stack_frame.eip = (u32)p_Cur_Task->eip;
- p_Cur_PCB->stack_frame.eflags = 0x1202;
- p_Cur_PCB->LDT_Selector = (Cur_LDT_Index << 3);
- Fill_Desc(Cur_LDT_Index,(u32)p_Cur_PCB->ldts,sizeof(Descriptor) * 2 - 1,DA_LDT);
- p_Cur_Top_Of_Stack -= p_Cur_Task->stack_size;
- p_Cur_PCB++;
- p_Cur_Task++;
- Cur_LDT_Index++;
- }
- p_Resume_PCB = PCB_Tables;
- }
其中,INDEX_OF_FIRST_LDT是在proc.h中定义的宏,捎带把INDEX_OF_TSS也定义上:
- #define INDEX_OF_TSS 4
- #define INDEX_OF_FIRST_LDT 5
把相关的地方一下修改,在C_Start中:
- Fill_Desc(INDEX_OF_TSS,(u32)&tss,sizeof(tss) - 1,DA_386TSS);
好了,编译链接,结果与前一节相同,但我们的程序已经更加容易扩展了。