#include "type.h"
#include "const.h"
#include "protect.h"
#include "console.h"
#include "tty.h"
#include "proc.h"
#include "proto.h"
#include "string.h"
#include "global.h"
PRIVATE void block(PROCESS* p);
PRIVATE void unblock(PROCESS* p);
PRIVATE int deadlock(int src, int dest);
PRIVATE int msg_send(PROCESS* current, int dest, MESSAGE* m);
PRIVATE int msg_recevie(PROCESS* current, int src, MESSAGE* m);
PUBLIC void scheduld()
{
PROCESS* p;
int greatest_ticks = 0;
while (!greatest_ticks) {
for (p = &FIRST_PROC; p <= &LAST_PROC; p++) {
if (p->p_flags == 0) {
if (p->ticks > greatest_ticks) {
greatest_ticks = p->ticks;
p_proc_ready = p;
}
}
}
if (!greatest_ticks) {
for (p = &FIRST_PROC; p < &LAST_PROC; p++) {
if (p->p_flags == 0) {
p->ticks = p->priority;
}
}
}
}
}
/**
* <Ring 0> The core routine of system call 'sendrec()'.
*
* @param function SEND or RECEIVE
* @param src_dest To/From whom the message is transferred.
* @param m Ptr to the MESSAGE body.
* @param p The caller proc.
*
* @return Zero if success.
*/
PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* m, PROCESS* 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;
/**
* 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 RECEVIE
* by 'send_recv()'
*/
if (function == SEND) {
ret = msg_send(p, src_dest, m);
if (ret != 0) {
return ret;
}
} else if (function == RECEIVE) {
ret = msg_recevie(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;
}
/**
* <Ring 1~3> IPC syscall.
*
* It is an encapsulation of `sendrec',
* invoking `sendrec' directly should be avoided
*
* @param function SEND, RECEIVE or BOTH
* @param src_dest The caller's proc_nr
* @param msg Pointer to the MESSAGE struct
*
* @return always 0.
*****************************************************************************/
PUBLIC int send_recv(int function, int src_dest, MESSAGE* msg)
{
int ret = 0;
if (function == RECEIVE)
memset(msg, 0, sizeof(MESSAGE));
switch (function) {
case BOTH:
ret = sendrec(SEND, src_dest, msg);
if (ret == 0)
ret = sendrec(RECEIVE, src_dest, msg);
break;
case SEND:
case RECEIVE:
ret = sendrec(function, src_dest, msg);
break;
default:
assert((function == BOTH) ||
(function == SEND) || (function == RECEIVE));
break;
}
return ret;
}
/**
* <Ring 0~1> Calculate the linear address of a certain segment of a given proc.
*
* @param p Whose (the proc ptr).
* @param idx Whick (one proc has more than one segments).
*
* @return The required linear address.
*/
PUBLIC int ldt_seg_linear(PROCESS *p, int idx)
{
DESCRIPTOR *d = &p->ldts[idx];
return d->base_high << 24 | d->base_mid << 16 | d->base_low;
}
/**
* <Ring 0~1> Virtual addr --> Linear addr.
*
* @param pid PID of the proc whose address is to be calculated.
* @param va Virtual address.
*
* @return The liner address for the given virtual address.
*/
PUBLIC void* va2la(int pid, void* va)
{
PROCESS *p = &proc_table[pid];
u32 seg_base = ldt_seg_linear(p, INDEX_LDT_RW);
u32 la = seg_base + (u32)va;
if (pid < NR_TASKS + NR_PROCS) {
assert(la == (u32)va);
}
return (void*)la;
}
/**
* <Ring 0~3> Clear up a MESSAGE by setting each byte to 0.
*
* @param p The message to be cleared.
*/
PUBLIC void reset_msg(MESSAGE* p)
{
memset(p, 0, sizeof(MESSAGE));
}
/**
* <Ring 0> This routine is called after 'p_flags' has been set (!= 0), it
* calls 'schedule()' to choose another proc as the 'proc_ready'.
*
* @attention This routine does not change 'p_flags'. Make sure the 'p_flags'
* of the proc to be blocked has been set properly.
*
* @param p The proc to be blocked.
*/
PRIVATE void block(PROCESS* p)
{
assert(p->p_flags);
scheduld();
}
/**
* <Ring 0> This is a dummy routine. It does nothing actually. When it is
* called, the 'p_flags' should have been cleared (== 0).
*
* @param p The unblocked proc.
*/
PRIVATE void unblock(PROCESS* p)
{
assert(p->p_flags == 0);
}
/**
* <Ring 0> Check whether it is safe to send a message from src to dest.
* The routine will detect if the messaging graph contains a cycle. For
* instance, if we have procs trying to send messages like this:
* A -> B -> C -> A, then a deadlock occurs, because all of then will
* wait forever. If no cycles detected, it is considered as safe.
*
* @param src Who wants to send message.
* @param dest To whom the message is sent.
*
* @return Zero if success.
*/
PRIVATE int deadlock(int src, int dest)
{
PROCESS* p = proc_table + dest;
while (1) {
if (p->p_flags & SENDING) {
if (p->p_sendto == src) {
/* print the chain */
p = proc_table + dest;
printl("=_=%s", p->p_name);
do {
assert(p->p_msg);
p = proc_table + p->p_sendto;
printl("->%s", p->p_name);
} while (p != proc_table + src);
printl("=_=");
return 1;
}
p = proc_table + p->p_sendto;
} else {
break;
}
}
return 0;
}
/**
* <Ring 0> Send a message to the dest proc. If dest is blocked waiting for
* the message, copy the message to it and unblock dest. Otherwise the caller
* will be blocked and appended to the dest's sending queue.
*
* @param current The caller, the sender.
* @param dest To whom the message is sent.
* @param m The message.
*
* @return Zero if success.
*/
PRIVATE int msg_send(PROCESS* current, int dest, MESSAGE* m)
{
PROCESS* sender = current;
PROCESS* p_dest = proc_table + dest; /* proc dest */
assert(proc2pid(sender) != dest);
/* check for deadlock here */
if (deadlock(proc2pid(sender), dest)) {
panic(">>DEADLOCK<< %s->%s", sender->p_name, p_dest->p_name);
}
if ((p_dest->p_flags & RECEIVING) && /* dest is waiting for the msg */
(p_dest->p_recvfrom == proc2pid(sender) ||
p_dest->p_recvfrom == ANY)) {
assert(p_dest->p_msg);
assert(m);
phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), m), sizeof(MESSAGE));
p_dest->p_msg = 0;
p_dest->p_flags &= ~RECEIVING; /* dest has received the msg */
p_dest->p_recvfrom = NO_TASK;
unblock(p_dest);
assert(p_dest->p_flags == 0);
assert(p_dest->p_msg == 0);
assert(p_dest->p_recvfrom == NO_TASK);
assert(p_dest->p_sendto == NO_TASK);
assert(sender->p_flags == 0);
assert(sender->p_msg == 0);
assert(sender->p_recvfrom == NO_TASK);
assert(sender->p_sendto == NO_TASK);
} else { /* dest is not waiting for the msg */
sender->p_flags |= SENDING;
assert(sender->p
没有合适的资源?快使用搜索试试~ 我知道了~
《ORANGE’S:一个操作系统的实现》读书笔记(二十五)进程间通信(三)文章代码
共43个文件
c:15个
h:11个
asm:6个
0 下载量 197 浏览量
2024-01-07
10:18:44
上传
评论
收藏 76KB ZIP 举报
温馨提示
《ORANGE’S:一个操作系统的实现》读书笔记(二十五)进程间通信(三)文章代码
资源推荐
资源详情
资源评论
收起资源包目录
code.zip (43个子文件)
code
include
type.h 334B
const.h 4KB
proto.h 2KB
proc.h 3KB
global.h 817B
keyboard.h 5KB
protect.h 5KB
sconst.inc 1KB
console.h 787B
tty.h 957B
string.h 242B
keymap.h 7KB
lib
misc.c 903B
klib.c 1KB
string.asm 3KB
kliba.asm 4KB
Makefile 4KB
bochsrc.bxrc 2KB
fd.img 1.41MB
boot
include
pm.inc 2KB
lib.inc 1KB
load.inc 932B
fat12hdr.inc 2KB
loader.bin 3KB
boot.bin 512B
loader.asm 14KB
boot.asm 9KB
kernel.bin 30KB
kernel
printf.c 435B
clock.c 874B
vsprintf.c 2KB
proc.c 14KB
kernel.asm 7KB
i8259.c 2KB
console.c 4KB
protect.c 7KB
syscall.asm 483B
keyboard.c 10KB
global.c 882B
systask.c 666B
start.c 1KB
main.c 3KB
tty.c 5KB
共 43 条
- 1
资源评论
zorro_z
- 粉丝: 618
- 资源: 26
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功