/************************************************************************************************** * msg_send ************************************************************************************************** * <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 msg Pointer to the MESSAGE struct. * * @return 0 if success. *************************************************************************************************/ PRIVATE int msg_send(PROCESS* current, int dest, MESSAGE* msg){ PROCESS* sender = current; PROCESS* p_dest = proc_table + dest; assert(proc2pid(sender) != dest); if(deadlock(proc2pid(sender), dest)){ /* Is there deadlock chain? */ panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); } /* dest is waiting for that msg or ANY msg. */ if((p_dest->flags & RECEIVING) && (p_dest->recv_from == proc2pid(sender) || p_dest->recv_from == ANY)){ assert(p_dest->p_msg); assert(msg); phys_copy(va2la(dest, p_dest->p_msg), va2la(proc2pid(sender), msg), sizeof(MESSAGE)); p_dest->p_msg = 0; p_dest->flags &= ~RECEIVING; /* dest has received the message */ p_dest->recv_from = NO_TASK; unblock(p_dest); assert(p_dest->flags == 0); assert(p_dest->p_msg == 0); assert(p_dest->recv_from == NO_TASK); assert(p_dest->send_to == NO_TASK); assert(sender->flags == 0); assert(sender->p_msg == 0); assert(sender->recv_from == NO_TASK); assert(sender->send_to == NO_TASK); }else{ /* However, dest is not waiting for the message */ sender->flags |= SENDING; assert(sender->flags == SENDING); sender->send_to = dest; sender->p_msg = msg; /* append to the sending queue */ PROCESS* p; if(p_dest->q_sending){ p = p_dest->q_sending; while(p->next_sending){ p = p->next_sending; } p->next_sending = sender; }else{ p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->flags == SENDING); assert(sender->p_msg != 0); assert(sender->recv_from == NO_TASK); assert(sender->send_to == dest); } return 0; }
int open(char* filename,int mode,int flag) //int sys_open(char* filename,int mode,int flag) { struct m_inode *inode; struct file *f; int i; int fd = -1; //句柄 //搜索没用过的句柄 for(i = 0;i < NR_OPEN;i++) { if(current->filp[i] == NULL) { fd = i; break; } } if(fd < 0 || fd > NR_OPEN) { panic("filp is full (PID %d)\n",proc2pid(current)); } f = file_table; for(i = 0;i < NR_FILE;i++,f++) { if(!f->f_count) { break; } } if(i < 0 || i > NR_FILE) { panic("file_table is full (PID %d)\n",proc2pid(current)); } (current->filp[fd] = f)->f_count++; // printk("root_inode->i_dev = %d\n",root_inode->i_dev); if((i = open_namei(filename,mode,flag,&inode)) != 0) { current->filp[fd] = NULL; f->f_count = 0; return i; } //返回文件句柄 // printk("open inode->i_num = %d\n",inode->i_num); f->f_inode = inode; f->f_count = 1; f->f_flag = flag; f->f_mode = mode; f->f_pos = 0; // printk("open:fd = %d\n",fd); return fd; }
/************************************************************************************************** * sys_sendrec ************************************************************************************************** * <Ring 0> The core routine of system call 'sendrec'. * * @param function SEND, RECEIVE, BOTH * @param src_dest To / From whom the message is transferred * @param msg Pointer to the MESSAGE struct * @param proc The caller process * * @return 0 if success *************************************************************************************************/ PUBLIC int sys_sendrec(int function, int src_dest, MESSAGE* msg, PROCESS* proc){ 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(proc); MESSAGE* mla = (MESSAGE*) va2la(caller, msg); mla->source = caller; /* from 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 RECEIVE by 'send_recv()'. */ if(function == SEND){ ret = msg_send(proc, src_dest, msg); if(ret != 0){ return ret; } }else if(function == RECEIVE){ ret = msg_receive(proc, src_dest, msg); if(ret != 0){ return ret; } }else{ panic("{sys_sendrec} invalid function: %d (SEND: %d, RECEIVE: %d).", function, SEND, RECEIVE); } return 0; }
/** * <Ring 1> Perform the DUP and DUP2 syscalls. */ PUBLIC int do_dup(MESSAGE * p) { int fd = p->FD; int newfd = p->NEWFD; struct file_desc * filp = pcaller->filp[fd]; if (newfd == -1) { /* find a free slot in PROCESS::filp[] */ int i; for (i = 0; i < NR_FILES; i++) { if (pcaller->filp[i] == 0) { newfd = i; break; } } if ((newfd < 0) || (newfd >= NR_FILES)) panic("filp[] is full (PID:%d)", proc2pid(pcaller)); } if (pcaller->filp[newfd] != 0) { /* close the file */ p->FD = newfd; do_close(p); } filp->fd_cnt++; pcaller->filp[newfd] = filp; return newfd; }
PUBLIC int sys_sendrec(PROCESS *p, int function, int src_dest, MESSAGE *m) { assert(k_reenter == 0); 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); if (function == SEND) { ret = msg_send(p, src_dest, m); } else if (function == RECEIVE) { ret = msg_receive(p, src_dest, m); } else { panic("{sys_sendrec} invalid function: " "%d (SEND:%d, RECEIVE:%d).", function, SEND, RECEIVE); } return ret; }
/* int sys_write(char *buf,int len,struct task_struct *p_proc) { tty_write(&tty_table[p_proc->nr_tty],buf,len); return 0; } */ int sys_printx(char *s,int len,struct task_struct *p_proc) { const char *p; char ch; char reenter_err[] = "? k_reenter is incorrect for unknown reason\n"; if(k_reenter == 0) //用户态下 { p = (char *)va2la(proc2pid(p_proc),s); } else if(k_reenter > 0) //内核态 { p =s; } else { p = reenter_err; } ch = *p; if((ch == MAG_CH_PANIC) || (ch == MAG_CH_ASSERT && current < &proc_table[NR_SYSTEM_PROCS])) { disable_int(); //关中断 char *v = (char *)V_MEM_BASE; const char *c = p + 1; //skip magic char while( v < ((char *)(V_MEM_BASE + V_MEM_SIZE)) && *c) { *v++ = *c++; *v++ = RED_COLOR; } //halt processor until an enabled interrupt __asm__ __volatile__ ("hlt"); } else { while((ch = *p++) != 0) { out_char(tty_table[p_proc->nr_tty].p_console,ch); } } return 0; }
/** * <Ring 1> Change the directory. * @param ppin Directory to be change. * @param string Pathname. * @param len Length of pathname. * @return Zero on success. */ PRIVATE int change_directory(struct inode ** ppin, char * string, int len) { char pathname[MAX_PATH]; if (len > MAX_PATH) return ENAMETOOLONG; /* fetch the name */ data_copy(getpid(), D, pathname, proc2pid(pcaller), D, string, len); //phys_copy(va2pa(getpid(), pathname), va2pa(proc2pid(pcaller), string), len); pathname[len] = '\0'; struct inode * pin = resolve_path(pathname, pcaller); if (!pin) return err_code; int retval = change_node(ppin, pin); put_inode(pin); return retval; }
PUBLIC int sys_sendrec(int function, int src_dest, Message *p_msg, Process *p_proc) { assert(k_reenter == 0); assert((src_dest >= 0 && src_dest < NR_TASKS + NR_PROCS) || src_dest == ANY || src_dest == INTERRUPT); int ret = 0; int caller = proc2pid(p_proc); Message *mla = (Message *)va2la(caller, p_msg); 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 SEDN followed by a RECEIVE * by 'send_recv()'. */ if(function == SEND) { ret = msg_send(p_proc, src_dest, p_msg); if(ret != 0) { return ret; } } else if(function == RECEIVE) { ret = msg_receive(p_proc, src_dest, p_msg); if(ret != 0) { return ret; } } else { panic("{sys_sendrec} invalid function: " "%d (SEND: %d, RECEIVE: %d).", function, SEND, RECEIVE); } return 0; }
/*======================================================================* sys_write *======================================================================*/ PUBLIC int sys_printx(int _unused1, int _unused2, char* s, struct proc* p_proc) { const char * p; char ch; char reenter_err[] = "? k_reenter is incorrect for unknown reason"; reenter_err[0] = MAG_CH_PANIC; /** * @note Code in both Ring 0 and Ring 1~3 may invoke printx(). * If this happens in Ring 0, no linear-physical address mapping * is needed. * * @attention The value of `k_reenter' is tricky here. When * -# printx() is called in Ring 0 * - k_reenter > 0. When code in Ring 0 calls printx(), * an `interrupt re-enter' will occur (printx() generates * a software interrupt). Thus `k_reenter' will be increased * by `kernel.asm::save' and be greater than 0. * -# printx() is called in Ring 1~3 * - k_reenter == 0. */ if (k_reenter == 0) /* printx() called in Ring<1~3> */ p = va2la(proc2pid(p_proc), s); else if (k_reenter > 0) /* printx() called in Ring<0> */ p = s; else /* this should NOT happen */ p = reenter_err; /** * @note if assertion fails in any TASK, the system will be halted; * if it fails in a USER PROC, it'll return like any normal syscall * does. */ if ((*p == MAG_CH_PANIC) || (*p == MAG_CH_ASSERT && p_proc_ready < &proc_table[NR_TASKS])) { disable_int(); char * v = (char*)V_MEM_BASE; const char * q = p + 1; /* +1: skip the magic char */ while (v < (char*)(V_MEM_BASE + V_MEM_SIZE)) { *v++ = *q++; *v++ = RED_CHAR; if (!*q) { while (((int)v - V_MEM_BASE) % (SCR_WIDTH * 16)) { /* *v++ = ' '; */ v++; *v++ = GRAY_CHAR; } q = p + 1; } } __asm__ __volatile__("hlt"); } while ((ch = *p++) != 0) { if (ch == MAG_CH_PANIC || ch == MAG_CH_ASSERT) continue; /* skip the magic char */ out_char(tty_table[p_proc->nr_tty].p_console, ch); } return 0; }
PUBLIC int do_open() { int i = 0; int fd = -1; // return value char pathname[MAX_PATH]; int flags = fs_msg.FLAGS; int name_len = fs_msg.NAME_LEN; int src = fs_msg.source; assert(name_len < MAX_PATH); phys_copy( (void *)va2la(TASK_FS, pathname), (void *)va2la(src, fs_msg.PATHNAME), name_len ); pathname[name_len] = 0; /* 先在调用者进程中查找空闲文件描述符 */ for (i = 0; i < NR_FILES; i++) if (pcaller->filp[i] == 0) { fd = i; break; } if ((fd < 0) || (fd >= NR_FILES)) panic("filp[] is full (PID:%d)", proc2pid(pcaller)); /* 然后在 f_desc_table 中查找空闲位置 */ for (i = 0; i < NR_FILE_DESC; i++) if (f_desc_table[i].fd_inode == 0) break; if (i >= NR_FILE_DESC) panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller)); /* 在磁盘中查找文件 */ int inode_nr = search_file(pathname); /* 准备创建或打开文件 */ struct inode *pin = 0; if (flags & O_CREAT) { if (inode_nr) { printl("file exists.\n"); return -1; } else { // 文件不存在且标志位 O_CREAT pin = creat_file(pathname, flags); } } else { assert(flags & O_RDWR); char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; pin = get_inode(dir_inode->i_dev, inode_nr); } /* 关联文件描述符 */ if (pin) { /* proc <- fd (connects proc with file_descriptor) */ pcaller->filp[fd] = &f_desc_table[i]; /* fd <- inode (connects file_descriptor with inode) */ f_desc_table[i].fd_mode = flags; f_desc_table[i].fd_pos = 0; f_desc_table[i].fd_inode = pin; int imode = pin->i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { MESSAGE driver_msg; driver_msg.type = DEV_OPEN; int dev = pin->i_start_sect; driver_msg.DEVICE = MINOR(dev); assert(MAJOR(dev) == 4); assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); /* 如果是字符设备则交给该设备的驱动处理 */ send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg); } else if (imode == I_DIRECTORY) assert(pin->i_num == ROOT_INODE); else assert(pin->i_mode == I_REGULAR); } else return -1; // open file failed return fd; }
/** * Open a file and return the file descriptor. * * @return File descriptor if successful, otherwise a negative error code. *****************************************************************************/ PUBLIC int do_open() { int fd = -1; /* return value */ char pathname[MAX_PATH]; /* get parameters from the message */ int flags = fs_msg.FLAGS; /* access mode */ int name_len = fs_msg.NAME_LEN; /* length of filename */ int src = fs_msg.source; /* caller proc nr. */ assert(name_len < MAX_PATH); phys_copy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; /* find a free slot in PROCESS::filp[] */ int i; for (i = 0; i < NR_FILES; i++) { if (pcaller->filp[i] == 0) { fd = i; break; } } if ((fd < 0) || (fd >= NR_FILES)) panic("filp[] is full (PID:%d)", proc2pid(pcaller)); /* find a free slot in f_desc_table[] */ for (i = 0; i < NR_FILE_DESC; i++) if (f_desc_table[i].fd_inode == 0) break; if (i >= NR_FILE_DESC) panic("f_desc_table[] is full (PID:%d)", proc2pid(pcaller)); int inode_nr = search_file(pathname); struct inode * pin = 0; if (flags & O_CREAT) { if (inode_nr) { printl("file exists.\n"); return -1; } else { pin = create_file(pathname, flags); } } else { assert(flags & O_RDWR); char filename[MAX_PATH]; struct inode * dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; pin = get_inode(dir_inode->i_dev, inode_nr); } if (pin) { /* connects proc with file_descriptor */ pcaller->filp[fd] = &f_desc_table[i]; /* connects file_descriptor with inode */ f_desc_table[i].fd_inode = pin; f_desc_table[i].fd_mode = flags; /* f_desc_table[i].fd_cnt = 1; */ f_desc_table[i].fd_pos = 0; int imode = pin->i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { MESSAGE driver_msg; driver_msg.type = DEV_OPEN; int dev = pin->i_start_sect; driver_msg.DEVICE = MINOR(dev); assert(MAJOR(dev) == 4); assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg); } else if (imode == I_DIRECTORY) { assert(pin->i_num == ROOT_INODE); } else { assert(pin->i_mode == I_REGULAR); } } else { return -1; } return fd; }
/************************************************************************************************** * msg_receive ************************************************************************************************** * <Ring 0> Try to get a message from the src proc. * If src is blocked sending the message, copy the message from it and unblock src. * Otherwise the caller will be blocked. * * @param current The caller, the proc who wanna receive. * @param src From whom the message will be received. * @param m Pointer to the MESSAGE struct. * * @return 0 if success. *************************************************************************************************/ PRIVATE int msg_receive(PROCESS* current, int src, MESSAGE* m){ PROCESS* p_who_wanna_recv = current; PROCESS* p_from = 0; PROCESS* prev = 0; /* the prior of p_from in the sending queue. */ int copyok = FALSE; assert(proc2pid(p_who_wanna_recv) != src); /* * There is an interrupt needs p_who_wanna_recv's handling and p_who_wanna_recv is ready * to handle it. */ if((p_who_wanna_recv->has_int_msg) && ((src == ANY) || (src == INTERRUPT))){ MESSAGE msg; reset_msg(&msg); msg.source = INTERRUPT; msg.type = HARD_INT; assert(m); phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg, sizeof(MESSAGE)); p_who_wanna_recv->has_int_msg = 0; assert(p_who_wanna_recv->flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->send_to == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); return 0; } /* * Arrive here if no interrupt for p_who_wanna_recv. * * p_who_wanna_recv is ready to receive messages from ANY proc, we'll check the sending queue * and pick the first proc in it. */ if(src == ANY){ if(p_who_wanna_recv->q_sending){ p_from = p_who_wanna_recv->q_sending; copyok = TRUE; assert(p_who_wanna_recv->flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->recv_from == NO_TASK); assert(p_who_wanna_recv->send_to == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->recv_from == NO_TASK); assert(p_from->send_to == proc2pid(p_who_wanna_recv)); } }else{/* p_who_wanna_recv wants to receive a message from a certain proc: src. */ p_from = &proc_table[src]; if((p_from->flags & SENDING) && (p_from->send_to == proc2pid(p_who_wanna_recv))){ copyok = TRUE; PROCESS* p = p_who_wanna_recv->q_sending; assert(p); /* p_from must have been appended to the queue */ while(p){ assert(p_from->flags & SENDING); if(proc2pid(p) == src){ p_from = p; break; } prev = p; p = p->next_sending; } assert(p_who_wanna_recv->flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->recv_from == NO_TASK); assert(p_who_wanna_recv->send_to == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->recv_from == NO_TASK); assert(p_from->send_to == proc2pid(p_who_wanna_recv)); } } /* * It's determined from which proc the message will be copied. * Note that this proc must have been waiting for this moment in the queue, * so we should remove it from the queue. */ if(copyok){ if(p_from == p_who_wanna_recv->q_sending){ /* the 1st one. */ assert(prev == 0); p_who_wanna_recv->q_sending = p_from->next_sending; p_from->next_sending = 0; }else{ assert(prev); prev->next_sending = p_from->next_sending; p_from->next_sending = 0; } assert(m); assert(p_from->p_msg); /* It's time to copy the message. */ phys_copy(va2la(proc2pid(p_who_wanna_recv), m), va2la(proc2pid(p_from), p_from->p_msg), sizeof(MESSAGE)); p_from->p_msg = 0; p_from->send_to = NO_TASK; p_from->flags &= ~SENDING; unblock(p_from); } /* * Unfortunately, nobody is sending any message. * Set flags so that p_who_wanna_recv will not be shceduled util it is unblocked. */ else{ p_who_wanna_recv->flags |= RECEIVING; p_who_wanna_recv->p_msg = m; if(src == ANY){ p_who_wanna_recv->recv_from = ANY; }else{ p_who_wanna_recv->recv_from = proc2pid(p_from); } block(p_who_wanna_recv); assert(p_who_wanna_recv->flags == RECEIVING); assert(p_who_wanna_recv->p_msg != 0); assert(p_who_wanna_recv->recv_from != NO_TASK); assert(p_who_wanna_recv->send_to == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); } return 0; }
PRIVATE int msg_receive(PROCESS *current, int src, MESSAGE *m) { PROCESS *p_who_wanna_recv = current; PROCESS *p_from = 0; PROCESS *prev = 0; int copyok = 0; assert(proc2pid(p_who_wanna_recv) != src); // 不能自己接收自己的消息 if ((p_who_wanna_recv->has_int_msg) && ((src == ANY) || (src == INTERRUPT))) { MESSAGE msg; reset_msg(&msg); msg.source = INTERRUPT; msg.type = HARD_INT; assert(m); phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg, sizeof(MESSAGE)); p_who_wanna_recv->has_int_msg = FALSE; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending == 0); return 0; } if (src == ANY) { // 如果要等待来自任何进程的消息 if (p_who_wanna_recv->q_sending) { // 如果消息队列不为空 p_from = p_who_wanna_recv->q_sending; // 取消息队列中第一个 copyok = TRUE; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } else { // 如果要等待指定进程的消息 p_from = &proc_table[src]; if ((p_from->p_flags & SENDING) && // 如果指定的进程正在发送消息 (p_from->p_sendto == proc2pid(p_who_wanna_recv))) { // 并且就是发送给该进程 copyok = TRUE; PROCESS *p = p_who_wanna_recv->q_sending; assert(p); /* 在消息队列中找到指定的进程 */ while (p) { assert(p_from->p_flags & SENDING); if (proc2pid(p) == src) { p_from = p; break; } prev = p; p = p->next_sending; } assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } if (copyok) { // 如果成功接收到了消息 if (p_from == p_who_wanna_recv->q_sending) { assert(prev == 0); p_who_wanna_recv->q_sending = p_from->next_sending; p_from->next_sending = 0; } else { assert(prev); prev->next_sending = p_from->next_sending; p_from->next_sending = 0; } assert(m); assert(p_from->p_msg); phys_copy(va2la(proc2pid(p_who_wanna_recv), m), va2la(proc2pid(p_from), p_from->p_msg), sizeof(MESSAGE)); p_from->p_msg = 0; p_from->p_sendto = NO_TASK; p_from->p_flags &= ~SENDING; unblock(p_from); // 恢复发送者 } else { p_who_wanna_recv->p_flags |= RECEIVING; p_who_wanna_recv->p_msg = m; p_who_wanna_recv->p_recvfrom = src == ANY ? ANY : proc2pid(p_from); block(p_who_wanna_recv); // 挂起 assert(p_who_wanna_recv->p_flags == RECEIVING); assert(p_who_wanna_recv->p_msg != 0); assert(p_who_wanna_recv->p_recvfrom != NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); } return 0; }
PUBLIC int do_open() { int fd = -1; char pathname[MAX_PATH]; int flags = fs_msg.FLAGS; int name_len = fs_msg.NAME_LEN; int src = fs_msg.source; assert(name_len < MAX_PATH); memcpy((void*)va2la(TASK_FS, pathname), (void*)va2la(src, fs_msg.PATHNAME), name_len); pathname[name_len] = 0; int i; for(i=0; i<NR_FILES; i++) { /* a empty filp item */ if (pcaller -> filp[i] == 0) break; } fd = i; /* printl("PATHNAME: %s, NAME_LEN: %d, FD: %d\n", pathname, name_len, fd); */ if (fd <0 || fd >= NR_FILES) panic("file[] is full. PID: %d", proc2pid(pcaller)); for(i=0; i<NR_FILE_DESC; i++) { /* a empty file descriptor */ if (f_desc_table[i].fd_inode == 0) break; } if (i >= NR_FILE_DESC) panic("f_desc_table[] is full. PID: %d", proc2pid(pcaller)); // FIXME: search_file is wrong int inode_nr = search_file(pathname); struct inode* pin = 0; if (flags & O_CREAT) { if (inode_nr) { /* file exists */ printl("file exists\n"); return -1; } else { pin = create_file(pathname, flags); /* dump_inode(pin); */ } } else { assert(flags & O_RDWR); char filename[MAX_PATH]; struct inode* dir_inode; if (strip_path(filename, pathname, &dir_inode) != 0) return -1; pin = get_inode(dir_inode -> i_dev, inode_nr); } if (pin) { pcaller -> filp[fd] = &f_desc_table[i]; f_desc_table[i].fd_inode = pin; f_desc_table[i].fd_mode = flags; f_desc_table[i].fd_pos = 0; f_desc_table[i].fd_cnt = 1; int imode = pin -> i_mode & I_TYPE_MASK; if (imode == I_CHAR_SPECIAL) { /* tty */ MESSAGE msg; msg.type = DEV_OPEN; int dev = pin -> i_start_sect; assert(MAJOR(dev) == 4); assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER); msg.DEVICE = MINOR(dev); send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &msg); } else if (imode == I_DIRECTORY) { assert(pin -> i_num == ROOT_INODE); } else { assert(pin -> i_mode == I_REGULAR); } } else { return -1; } return fd; }
/** * <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(struct proc* current, int dest, MESSAGE* m) { struct proc* sender = current; struct proc* 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->name, p_dest->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_flags == SENDING); sender->p_sendto = dest; sender->p_msg = m; /* append to the sending queue */ struct proc * p; if (p_dest->q_sending) { p = p_dest->q_sending; while (p->next_sending) p = p->next_sending; p->next_sending = sender; } else { p_dest->q_sending = sender; } sender->next_sending = 0; block(sender); assert(sender->p_flags == SENDING); assert(sender->p_msg != 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == dest); } return 0; }
/** * <Ring 0> Try to get a message from the src proc. If src is blocked sending * the message, copy the message from it and unblock src. Otherwise the caller * will be blocked. * * @param current The caller, the proc who wanna receive. * @param src From whom the message will be received. * @param m The message ptr to accept the message. * * @return Zero if success. *****************************************************************************/ PRIVATE int msg_receive(struct proc* current, int src, MESSAGE* m) { struct proc* p_who_wanna_recv = current; /** * This name is a little bit * wierd, but it makes me * think clearly, so I keep * it. */ struct proc* p_from = 0; /* from which the message will be fetched */ struct proc* prev = 0; int copyok = 0; assert(proc2pid(p_who_wanna_recv) != src); if ((p_who_wanna_recv->has_int_msg) && ((src == ANY) || (src == INTERRUPT))) { /* There is an interrupt needs p_who_wanna_recv's handling and * p_who_wanna_recv is ready to handle it. */ MESSAGE msg; reset_msg(&msg); msg.source = INTERRUPT; msg.type = HARD_INT; assert(m); phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg, sizeof(MESSAGE)); p_who_wanna_recv->has_int_msg = 0; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); return 0; } /* Arrives here if no interrupt for p_who_wanna_recv. */ if (src == ANY) { /* p_who_wanna_recv is ready to receive messages from * ANY proc, we'll check the sending queue and pick the * first proc in it. */ if (p_who_wanna_recv->q_sending) { p_from = p_who_wanna_recv->q_sending; copyok = 1; assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } else { /* p_who_wanna_recv wants to receive a message from * a certain proc: src. */ p_from = &proc_table[src]; if ((p_from->p_flags & SENDING) && (p_from->p_sendto == proc2pid(p_who_wanna_recv))) { /* Perfect, src is sending a message to * p_who_wanna_recv. */ copyok = 1; struct proc* p = p_who_wanna_recv->q_sending; assert(p); /* p_from must have been appended to the * queue, so the queue must not be NULL */ while (p) { assert(p_from->p_flags & SENDING); if (proc2pid(p) == src) { /* if p is the one */ p_from = p; break; } prev = p; p = p->next_sending; } assert(p_who_wanna_recv->p_flags == 0); assert(p_who_wanna_recv->p_msg == 0); assert(p_who_wanna_recv->p_recvfrom == NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->q_sending != 0); assert(p_from->p_flags == SENDING); assert(p_from->p_msg != 0); assert(p_from->p_recvfrom == NO_TASK); assert(p_from->p_sendto == proc2pid(p_who_wanna_recv)); } } if (copyok) { /* It's determined from which proc the message will * be copied. Note that this proc must have been * waiting for this moment in the queue, so we should * remove it from the queue. */ if (p_from == p_who_wanna_recv->q_sending) { /* the 1st one */ assert(prev == 0); p_who_wanna_recv->q_sending = p_from->next_sending; p_from->next_sending = 0; } else { assert(prev); prev->next_sending = p_from->next_sending; p_from->next_sending = 0; } assert(m); assert(p_from->p_msg); /* copy the message */ phys_copy(va2la(proc2pid(p_who_wanna_recv), m), va2la(proc2pid(p_from), p_from->p_msg), sizeof(MESSAGE)); p_from->p_msg = 0; p_from->p_sendto = NO_TASK; p_from->p_flags &= ~SENDING; unblock(p_from); } else { /* nobody's sending any msg */ /* Set p_flags so that p_who_wanna_recv will not * be scheduled until it is unblocked. */ p_who_wanna_recv->p_flags |= RECEIVING; p_who_wanna_recv->p_msg = m; if (src == ANY) p_who_wanna_recv->p_recvfrom = ANY; else p_who_wanna_recv->p_recvfrom = proc2pid(p_from); block(p_who_wanna_recv); assert(p_who_wanna_recv->p_flags == RECEIVING); assert(p_who_wanna_recv->p_msg != 0); assert(p_who_wanna_recv->p_recvfrom != NO_TASK); assert(p_who_wanna_recv->p_sendto == NO_TASK); assert(p_who_wanna_recv->has_int_msg == 0); } return 0; }
PRIVATE int msg_send(PROCESS *current, int dest, MESSAGE *m) { PROCESS *sender = current; PROCESS *p_dest = proc_table + dest; assert(proc2pid(sender) != dest); // 不能自己给自己发消息 if (deadlock(proc2pid(sender), dest)) panic(">>DEADLOCK<< %s->%s", sender->name, p_dest->name); if ((p_dest->p_flags & RECEIVING) && // 如果目的进程正在等待接受消息 (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; 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 { // 如果目的进程没有等待接受本进程的消息 sender->p_flags |= SENDING; // 标志位置位,只有 p_flags == 0 该进程才会被调度 assert(sender->p_flags == SENDING); sender->p_sendto = dest; sender->p_msg = m; /* 将自己添加到目的进程的发送者队列中去 */ PROCESS *p; if (p_dest->q_sending) { // 如果队列不为空 p = p_dest->q_sending; while (p->next_sending) p = p->next_sending; p->next_sending = sender; } else { // 如果队列为空 p_dest->q_sending = sender; } sender->next_sending = NULL; block(sender); assert(sender->p_flags == SENDING); assert(sender->p_msg != 0); assert(sender->p_recvfrom == NO_TASK); assert(sender->p_sendto == dest); } return 0; }