假設處理序 P 有子處理序 A。而 A 使用 exit(),那麼 MM 將會:
- 告訴 FS:A 退出,請作相應處理
- 釋放 A 佔用的記憶體
- 判斷 P 是否正在 WAITING
- 如果是
- 清除 P 的 WAITING 位
- 向 P 發送訊息以解除阻塞(到此 P 的 wait() 函數結束)
- 釋放 A 的處理序表項(到此 A 的 exit() 函數結束)
- 如果否
- 設定 A 的 HANGING 位
- 瀏覽 proc_table[],如果發現 A 有子處理序 B,那麼
- 將 Init 處理序設定為 B 的父處理序(換言之,將 B 過繼給 Init)
- 判斷是否滿足 Init 正在 WAITING 且 B 正在 HANGING
- 如果是
- 清除 Init 的 WAITING 位
- 向 Init 發送訊息以解除阻塞(到此 Init 的 wait() 函數結束)
- 釋放 B 的處理序表項(到此 B 的 exit() 函數結束)
- 如果否
- 如果 Init 正在 WAITING 但 B 並沒有 HANGING,那麼「握手」會在將來 B 使用 exit() 時發生
- 如果 B 正在 HANGING 但 Init 並沒有 WAITING,那麼「握手」會在將來 Init 使用 wait() 時發生
如果 P 使用 wait(),那麼 MM 將會:
- 瀏覽 proc_table[],如果發現 A 是 P 的子處理序,並且它正在 HANGING,那麼
- 向 P 發送訊息以解除阻塞(到此 P 的 wait() 函數結束)
- 釋放 A 的處理序表項(到此 A 的 exit() 函數結束)
- 如果 P 的子處理序沒有一個再 HANGING,則
- 設 P 的 WAITING 位
- 如果 P 壓根兒沒有子處理序,則
- 向 P 發送訊息,訊息攜帶一個表示出錯的返回值(到此 P 的 wait() 函數結束)
程式碼
kernel/main.c
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Forrest Yu, 2005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ #include "type.h" #include "stdio.h" #include "const.h" #include "protect.h" #include "string.h" #include "fs.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "proto.h" /***************************************************************************** * kernel_main *****************************************************************************/ /** * jmp from kernel.asm::_start. * *****************************************************************************/ PUBLIC int kernel_main() { disp_str("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); int i, j, eflags, prio; u8 rpl; u8 priv; /* privilege */ struct task * t; struct proc * p = proc_table; char * stk = task_stack + STACK_SIZE_TOTAL; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++,t++) { if (i >= NR_TASKS + NR_NATIVE_PROCS) { p->p_flags = FREE_SLOT; continue; } if (i < NR_TASKS) { /* TASK */ t = task_table + i; priv = PRIVILEGE_TASK; rpl = RPL_TASK; eflags = 0x1202;/* IF=1, IOPL=1, bit 2 is always 1 */ prio = 15; } else { /* USER PROC */ t = user_proc_table + (i - NR_TASKS); priv = PRIVILEGE_USER; rpl = RPL_USER; eflags = 0x202; /* IF=1, bit 2 is always 1 */ prio = 5; } strcpy(p->name, t->name); /* name of the process */ p->p_parent = NO_TASK; if (strcmp(t->name, "INIT") != 0) { p->ldts[INDEX_LDT_C] = gdt[SELECTOR_KERNEL_CS >> 3]; p->ldts[INDEX_LDT_RW] = gdt[SELECTOR_KERNEL_DS >> 3]; /* change the DPLs */ p->ldts[INDEX_LDT_C].attr1 = DA_C | priv << 5; p->ldts[INDEX_LDT_RW].attr1 = DA_DRW | priv << 5; } else { /* INIT process */ unsigned int k_base; unsigned int k_limit; int ret = get_kernel_map(&k_base, &k_limit); assert(ret == 0); init_desc(&p->ldts[INDEX_LDT_C], 0, /* bytes before the entry point * are useless (wasted) for the * INIT process, doesn't matter */ (k_base + k_limit) >> LIMIT_4K_SHIFT, DA_32 | DA_LIMIT_4K | DA_C | priv << 5); init_desc(&p->ldts[INDEX_LDT_RW], 0, /* bytes before the entry point * are useless (wasted) for the * INIT process, doesn't matter */ (k_base + k_limit) >> LIMIT_4K_SHIFT, DA_32 | DA_LIMIT_4K | DA_DRW | priv << 5); } p->regs.cs = INDEX_LDT_C << 3 | SA_TIL | rpl; p->regs.ds = p->regs.es = p->regs.fs = p->regs.ss = INDEX_LDT_RW << 3 | SA_TIL | rpl; p->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | rpl; p->regs.eip = (u32)t->initial_eip; p->regs.esp = (u32)stk; p->regs.eflags = eflags; p->ticks = p->priority = prio; p->p_flags = 0; p->p_msg = 0; p->p_recvfrom = NO_TASK; p->p_sendto = NO_TASK; p->has_int_msg = 0; p->q_sending = 0; p->next_sending = 0; for (j = 0; j < NR_FILES; j++) p->filp[j] = 0; stk -= t->stacksize; } k_reenter = 0; ticks = 0; p_proc_ready = proc_table; init_clock(); init_keyboard(); restart(); while(1){} } /***************************************************************************** * get_ticks *****************************************************************************/ PUBLIC int get_ticks() { MESSAGE msg; reset_msg(&msg); msg.type = GET_TICKS; send_recv(BOTH, TASK_SYS, &msg); return msg.RETVAL; } /***************************************************************************** * Init *****************************************************************************/ /** * The hen. * *****************************************************************************/ void Init() { int fd_stdin = open("/dev_tty0", O_RDWR); assert(fd_stdin == 0); int fd_stdout = open("/dev_tty0", O_RDWR); assert(fd_stdout == 1); printf("Init() is running ...\n"); int pid = fork(); if (pid != 0) { /* parent process */ printf("parent is running, child pid:%d\n", pid); int s; int child = wait(&s); printf("child (%d) exited with status: %d.\n", child, s); } else { /* child process */ printf("child is running, pid:%d\n", getpid()); exit(123); } while (1) { int s; int child = wait(&s); printf("child (%d) exited with status: %d.\n", child, s); } } /*======================================================================* TestA *======================================================================*/ void TestA() { for(;;); } /*======================================================================* TestB *======================================================================*/ void TestB() { for(;;); } /*======================================================================* TestB *======================================================================*/ void TestC() { for(;;); } /***************************************************************************** * panic *****************************************************************************/ PUBLIC void panic(const char *fmt, ...) { int i; char buf[256]; /* 4 is the size of fmt in the stack */ va_list arg = (va_list)((char*)&fmt + 4); i = vsprintf(buf, fmt, arg); printl("%c !!panic!! %s", MAG_CH_PANIC, buf); /* should never arrive here */ __asm__ __volatile__("ud2"); }
mm/forkexit.c
/*************************************************************************//** ***************************************************************************** * @file forkexit.c * @brief * @author Forrest Y. Yu * @date Tue May 6 00:37:15 2008 ***************************************************************************** *****************************************************************************/ #include "type.h" #include "stdio.h" #include "const.h" #include "protect.h" #include "string.h" #include "fs.h" #include "proc.h" #include "tty.h" #include "console.h" #include "global.h" #include "keyboard.h" #include "proto.h" PRIVATE void cleanup(struct proc * proc); /***************************************************************************** * do_fork *****************************************************************************/ /** * Perform the fork() syscall. * * @return Zero if success, otherwise -1. *****************************************************************************/ PUBLIC int do_fork() { /* find a free slot in proc_table */ struct proc* p = proc_table; int i; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p++) if (p->p_flags == FREE_SLOT) break; int child_pid = i; assert(p == &proc_table[child_pid]); assert(child_pid >= NR_TASKS + NR_NATIVE_PROCS); if (i == NR_TASKS + NR_PROCS) /* no free slot */ return -1; assert(i < NR_TASKS + NR_PROCS); /* duplicate the process table */ int pid = mm_msg.source; u16 child_ldt_sel = p->ldt_sel; *p = proc_table[pid]; p->ldt_sel = child_ldt_sel; p->p_parent = pid; sprintf(p->name, "%s_%d", proc_table[pid].name, child_pid); /* duplicate the process: T, D & S */ struct descriptor * ppd; /* Text segment */ ppd = &proc_table[pid].ldts[INDEX_LDT_C]; /* base of T-seg, in bytes */ int caller_T_base = reassembly(ppd->base_high, 24, ppd->base_mid, 16, ppd->base_low); /* limit of T-seg, in 1 or 4096 bytes, depending on the G bit of descriptor */ int caller_T_limit = reassembly(0, 0, (ppd->limit_high_attr2 & 0xF), 16, ppd->limit_low); /* size of T-seg, in bytes */ int caller_T_size = ((caller_T_limit + 1) * ((ppd->limit_high_attr2 & (DA_LIMIT_4K >> 8)) ? 4096 : 1)); /* Data & Stack segments */ ppd = &proc_table[pid].ldts[INDEX_LDT_RW]; /* base of D&S-seg, in bytes */ int caller_D_S_base = reassembly(ppd->base_high, 24, ppd->base_mid, 16, ppd->base_low); /* limit of D&S-seg, in 1 or 4096 bytes, depending on the G bit of descriptor */ int caller_D_S_limit = reassembly((ppd->limit_high_attr2 & 0xF), 16, 0, 0, ppd->limit_low); /* size of D&S-seg, in bytes */ int caller_D_S_size = ((caller_T_limit + 1) * ((ppd->limit_high_attr2 & (DA_LIMIT_4K >> 8)) ? 4096 : 1)); /* we don't separate T, D & S segments, so we have: */ assert((caller_T_base == caller_D_S_base ) && (caller_T_limit == caller_D_S_limit) && (caller_T_size == caller_D_S_size )); /* base of child proc, T, D & S segments share the same space, so we allocate memory just once */ int child_base = alloc_mem(child_pid, caller_T_size); /* int child_limit = caller_T_limit; */ printl("{MM} 0x%x <- 0x%x (0x%x bytes)\n", child_base, caller_T_base, caller_T_size); /* child is a copy of the parent */ phys_copy((void*)child_base, (void*)caller_T_base, caller_T_size); /* child's LDT */ init_desc(&p->ldts[INDEX_LDT_C], child_base, (PROC_IMAGE_SIZE_DEFAULT - 1) >> LIMIT_4K_SHIFT, DA_LIMIT_4K | DA_32 | DA_C | PRIVILEGE_USER << 5); init_desc(&p->ldts[INDEX_LDT_RW], child_base, (PROC_IMAGE_SIZE_DEFAULT - 1) >> LIMIT_4K_SHIFT, DA_LIMIT_4K | DA_32 | DA_DRW | PRIVILEGE_USER << 5); /* tell FS, see fs_fork() */ MESSAGE msg2fs; msg2fs.type = FORK; msg2fs.PID = child_pid; send_recv(BOTH, TASK_FS, &msg2fs); /* child PID will be returned to the parent proc */ mm_msg.PID = child_pid; /* birth of the child */ MESSAGE m; m.type = SYSCALL_RET; m.RETVAL = 0; m.PID = 0; send_recv(SEND, child_pid, &m); return 0; } /***************************************************************************** * do_exit *****************************************************************************/ /** * Perform the exit() syscall. * * If proc A calls exit(), then MM will do the following in this routine: * <1> inform FS so that the fd-related things will be cleaned up * <2> free A's memory * <3> set A.exit_status, which is for the parent * <4> depends on parent's status. if parent (say P) is: * (1) WAITING * - clean P's WAITING bit, and * - send P a message to unblock it * - release A's proc_table[] slot * (2) not WAITING * - set A's HANGING bit * <5> iterate proc_table[], if proc B is found as A's child, then: * (1) make INIT the new parent of B, and * (2) if INIT is WAITING and B is HANGING, then: * - clean INIT's WAITING bit, and * - send INIT a message to unblock it * - release B's proc_table[] slot * else * if INIT is WAITING but B is not HANGING, then * - B will call exit() * if B is HANGING but INIT is not WAITING, then * - INIT will call wait() * * TERMs: * - HANGING: everything except the proc_table entry has been cleaned up. * - WAITING: a proc has at least one child, and it is waiting for the * child(ren) to exit() * - zombie: say P has a child A, A will become a zombie if * - A exit(), and * - P does not wait(), neither does it exit(). that is to say, P just * keeps running without terminating itself or its child * * @param status Exiting status for parent. * *****************************************************************************/ PUBLIC void do_exit(int status) { int i; int pid = mm_msg.source; /* PID of caller */ int parent_pid = proc_table[pid].p_parent; struct proc * p = &proc_table[pid]; /* tell FS, see fs_exit() */ MESSAGE msg2fs; msg2fs.type = EXIT; msg2fs.PID = pid; send_recv(BOTH, TASK_FS, &msg2fs); free_mem(pid); p->exit_status = status; if (proc_table[parent_pid].p_flags & WAITING) { /* parent is waiting */ proc_table[parent_pid].p_flags &= ~WAITING; cleanup(&proc_table[pid]); } else { /* parent is not waiting */ proc_table[pid].p_flags |= HANGING; } /* if the proc has any child, make INIT the new parent */ for (i = 0; i < NR_TASKS + NR_PROCS; i++) { if (proc_table[i].p_parent == pid) { /* is a child */ proc_table[i].p_parent = INIT; if ((proc_table[INIT].p_flags & WAITING) && (proc_table[i].p_flags & HANGING)) { proc_table[INIT].p_flags &= ~WAITING; cleanup(&proc_table[i]); } } } } /***************************************************************************** * cleanup *****************************************************************************/ /** * Do the last jobs to clean up a proc thoroughly: * - Send proc's parent a message to unblock it, and * - release proc's proc_table[] entry * * @param proc Process to clean up. *****************************************************************************/ PRIVATE void cleanup(struct proc * proc) { MESSAGE msg2parent; msg2parent.type = SYSCALL_RET; msg2parent.PID = proc2pid(proc); msg2parent.STATUS = proc->exit_status; send_recv(SEND, proc->p_parent, &msg2parent); proc->p_flags = FREE_SLOT; } /***************************************************************************** * do_wait *****************************************************************************/ /** * Perform the wait() syscall. * * If proc P calls wait(), then MM will do the following in this routine: * <1> iterate proc_table[], * if proc A is found as P's child and it is HANGING * - reply to P (cleanup() will send P a messageto unblock it) * - release A's proc_table[] entry * - return (MM will go on with the next message loop) * <2> if no child of P is HANGING * - set P's WAITING bit * <3> if P has no child at all * - reply to P with error * <4> return (MM will go on with the next message loop) * *****************************************************************************/ PUBLIC void do_wait() { int pid = mm_msg.source; int i; int children = 0; struct proc* p_proc = proc_table; for (i = 0; i < NR_TASKS + NR_PROCS; i++,p_proc++) { if (p_proc->p_parent == pid) { children++; if (p_proc->p_flags & HANGING) { cleanup(p_proc); return; } } } if (children) { /* has children, but no child is HANGING */ proc_table[pid].p_flags |= WAITING; } else { /* no child at all */ MESSAGE msg; msg.type = SYSCALL_RET; msg.PID = NO_TASK; send_recv(SEND, pid, &msg); } }
Makefile
######################### # Makefile for Orange'S # ######################### # Entry point of Orange'S # It must have the same value with 'KernelEntryPointPhyAddr' in load.inc! ENTRYPOINT = 0x1000 # Offset of entry point in kernel file # It depends on ENTRYPOINT ENTRYOFFSET = 0x400 # Programs, flags, etc. ASM = nasm DASM = objdump CC = gcc LD = ld ASMBFLAGS = -I boot/include/ ASMKFLAGS = -I include/ -I include/sys/ -f elf CFLAGS = -I include/ -I include/sys/ -m32 -c -fno-builtin -fno-stack-protector LDFLAGS = -s -melf_i386 -Ttext $(ENTRYPOINT) -Map krnl.map DASMFLAGS = -D # This Program ORANGESBOOT = boot/boot.bin boot/loader.bin ORANGESKERNEL = kernel.bin OBJS = kernel/kernel.o lib/syscall.o kernel/start.o kernel/main.o\ kernel/clock.o kernel/keyboard.o kernel/tty.o kernel/console.o\ kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\ kernel/systask.o kernel/hd.o\ lib/printf.o lib/vsprintf.o\ lib/kliba.o lib/klib.o lib/string.o lib/misc.o\ lib/open.o lib/read.o lib/write.o lib/close.o lib/unlink.o\ lib/getpid.o lib/syslog.o\ fs/main.o fs/open.o fs/misc.o fs/read_write.o\ lib/fork.o lib/exit.o lib/wait.o\ mm/main.o mm/forkexit.o\ fs/link.o\ fs/disklog.o DASMOUTPUT = kernel.bin.asm # All Phony Targets .PHONY : everything final image clean realclean disasm all buildimg # Default starting position nop : @echo "why not \`make image' huh? :)" everything : $(ORANGESBOOT) $(ORANGESKERNEL) all : realclean everything image : realclean everything clean buildimg clean : rm -f $(OBJS) realclean : rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL) disasm : $(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT) # We assume that "a.img" exists in current folder buildimg : mkdir tmp sleep 1 sudo mount -o loop a.img tmp sleep 1 sudo cp -fv boot/loader.bin tmp sudo cp -fv kernel.bin tmp sleep 1 sudo umount tmp sleep 1 rmdir tmp boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc $(ASM) $(ASMBFLAGS) -o $@ $< boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc $(ASM) $(ASMBFLAGS) -o $@ $< $(ORANGESKERNEL) : $(OBJS) $(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS) kernel/kernel.o : kernel/kernel.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/syscall.o : lib/syscall.asm $(ASM) $(ASMKFLAGS) -o $@ $< kernel/start.o: kernel/start.c $(CC) $(CFLAGS) -o $@ $< kernel/main.o: kernel/main.c $(CC) $(CFLAGS) -o $@ $< kernel/clock.o: kernel/clock.c $(CC) $(CFLAGS) -o $@ $< kernel/keyboard.o: kernel/keyboard.c $(CC) $(CFLAGS) -o $@ $< kernel/tty.o: kernel/tty.c $(CC) $(CFLAGS) -o $@ $< kernel/console.o: kernel/console.c $(CC) $(CFLAGS) -o $@ $< kernel/i8259.o: kernel/i8259.c $(CC) $(CFLAGS) -o $@ $< kernel/global.o: kernel/global.c $(CC) $(CFLAGS) -o $@ $< kernel/protect.o: kernel/protect.c $(CC) $(CFLAGS) -o $@ $< kernel/proc.o: kernel/proc.c $(CC) $(CFLAGS) -o $@ $< lib/printf.o: lib/printf.c $(CC) $(CFLAGS) -o $@ $< lib/vsprintf.o: lib/vsprintf.c $(CC) $(CFLAGS) -o $@ $< kernel/systask.o: kernel/systask.c $(CC) $(CFLAGS) -o $@ $< kernel/hd.o: kernel/hd.c $(CC) $(CFLAGS) -o $@ $< lib/klib.o: lib/klib.c $(CC) $(CFLAGS) -o $@ $< lib/misc.o: lib/misc.c $(CC) $(CFLAGS) -o $@ $< lib/kliba.o : lib/kliba.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/string.o : lib/string.asm $(ASM) $(ASMKFLAGS) -o $@ $< lib/open.o: lib/open.c $(CC) $(CFLAGS) -o $@ $< lib/read.o: lib/read.c $(CC) $(CFLAGS) -o $@ $< lib/write.o: lib/write.c $(CC) $(CFLAGS) -o $@ $< lib/close.o: lib/close.c $(CC) $(CFLAGS) -o $@ $< lib/unlink.o: lib/unlink.c $(CC) $(CFLAGS) -o $@ $< lib/getpid.o: lib/getpid.c $(CC) $(CFLAGS) -o $@ $< lib/syslog.o: lib/syslog.c $(CC) $(CFLAGS) -o $@ $< lib/fork.o: lib/fork.c $(CC) $(CFLAGS) -o $@ $< lib/exit.o: lib/exit.c $(CC) $(CFLAGS) -o $@ $< lib/wait.o: lib/wait.c $(CC) $(CFLAGS) -o $@ $< mm/main.o: mm/main.c $(CC) $(CFLAGS) -o $@ $< mm/forkexit.o: mm/forkexit.c $(CC) $(CFLAGS) -o $@ $< fs/main.o: fs/main.c $(CC) $(CFLAGS) -o $@ $< fs/open.o: fs/open.c $(CC) $(CFLAGS) -o $@ $< fs/read_write.o: fs/read_write.c $(CC) $(CFLAGS) -o $@ $< fs/link.o: fs/link.c $(CC) $(CFLAGS) -o $@ $< fs/disklog.o: fs/disklog.c $(CC) $(CFLAGS) -o $@ $<
![]() |
執行畫面 |
留言
張貼留言