主要内容
实现进程间的通信
一
Linux的系统调用与Minix的系统调用不同,以点见面可以了解一些宏内核与微内核的区别。
Linux的fork函数通过调用中断0x80,通过IDT转化为_system_call,最终通过一个函数指针数组转化为调用_sys_fork实现
Minix的调用中只有接收消息和发送消息的系统调用,总共有三种SEND,RECEIVE,BOTH。
Minix的fork函数实现需要一个内存管理器(MM),负责fork所要做的工作
对fork的调用先转化为内核态函数sys_call,sys_call将消息传递给MM,MM获得
消息后得知消息的内容是进行fork操作,就进一步调用do_fork完成。
其他系统调用也无外乎通过syscall转化为发送消息,相应的进程接收消息并处理。
二
进程间发送消息又被称为进程间通信(IPC),IPC又可分为同步和异步。
模仿Minix的IPC机制,新建系统调用sendrec来模拟sys_call
sendrec:
mov eax, _NR_sendrec
mov ebx, [esp + 4] ; function
mov ecx, [esp + 8] ; src_dest
mov edx, [esp + 12] ; p_msg
int INT_VECTOR_SYS_CALL
ret
对应的sys_sendrec
将SEND消息交给msg_send处理
将RECEIVE消息交给msg_receive处理
PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, struct proc* p)
{
assert(k_reenter == 0); /* make sure we are not in ring0 */
assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) ||
src_dest == ANY ||
src_dest == INTERRUPT);
int ret = 0;
int caller = proc2pid(p);
MESSAGE* mla = (MESSAGE*)va2la(caller, m);
mla->source = caller;
assert(mla->source != src_dest);
/**
* Actually we have the third message type: BOTH. However, it is not
* allowed to be passed to the kernel directly. Kernel doesn't know
* it at all. It is transformed into a SEND followed by a RECEIVE
* by `send_recv()'.
*/
if (function == SEND) {
ret = msg_send(p, src_dest, m);
if (ret != 0)
return ret;
}
else if (function == RECEIVE) {
ret = msg_receive(p, src_dest, m);
if (ret != 0)
return ret;
}
else {
panic("{sys_sendrec} invalid function: "
"%d (SEND:%d, RECEIVE:%d).", function, SEND, RECEIVE);
}
return 0;
}
msg_send和msg_receive函数
/*****************************************************************************
* ldt_seg_linear
*****************************************************************************/
/**
* <Ring 0~1> Calculate the linear address of a certain segment of a given
* proc.
*
* @param p Whose (the proc ptr).
* @param idx Which (one proc has more than one segments).
*
* @return The required linear address.
*****************************************************************************/
PUBLIC int ldt_seg_linear(struct proc* p, int idx)
{
struct descriptor * d = &p->ldts[idx];
return d->base_high << 24 | d->base_mid << 16 | d->base_low;
}
/*****************************************************************************
* va2la
*****************************************************************************/
/**
* <Ring 0~1> Virtual addr --> Li