⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fork.c

📁 一个用于学习的操作系统
💻 C
字号:
#include <fairysky/defs.h>#include <fairysky/types.h>#include <fairysky/kernel.h>#include <asm/system.h>#include <fairysky/string.h>#include <fairysky/scheduler.h>#include <fairysky/system_call.h>#include <fairysky/errno.h>#include <asm/memory.h>extern void add_run_queue(task_struct_t *task);extern task_struct_t *current;extern s32 last_pid;void verify_area(void * addr, size_t size){}//获取空闲的pidstatic s32 get_free_pid(){    task_struct_t *tmp;getnextpid:        ++last_pid;        if (last_pid == 0) {            last_pid = 1;        }        TASK_EACH(sleep_task, tmp) {            if (tmp->pid == last_pid) {                goto getnextpid;            }        }        TASK_EACH(pinit_task, tmp) {            if (tmp->pid == last_pid) {                goto getnextpid;            }        }    return last_pid;}//复制一个进程的全部空间,复制页目录和页表//from_page_dir:父进程的页目录地址//to_page_dir:进程的页目录地址static void copy_mem(u32 to_page_dir, u32 from_page_dir){    if (copy_page_table(to_page_dir, from_page_dir)) {        panic("copy_mem failure\n");    }}#ifdef WINDOWS_CYGWIN    #define CHILD_RET_FROM_SYS_CALL child_ret_from_sys_call#else    #define CHILD_RET_FROM_SYS_CALL _child_ret_from_sys_call#endifextern void CHILD_RET_FROM_SYS_CALL();//系统调用fork的实现//这里不再处理子进程的返回值了,在子进程第一次进入ring3时处理,//具体在_child_ret_from_sys_call,在system_call_entry.asm文件中pid_t sys_fork(    long EBX,    long ECX,    long EDX,    long ESI,    long EDI,    long EBP,    long FS,    long GS,    long ES,    long DS,    long EIP,    long CS,    long EFLAG,    long ESP3,    long SS3){    addr_t *ptmp;    task_struct_t *tmp_task = NULL;    //分配pcb空间,4k    int index = get_free_page();    if (! index) {        return ENOMEM;    }    tmp_task = (task_struct_t *) index_to_vaddr(index);    //memset(tmp_task, 0, sizeof(task_struct_t));    index = get_free_page();    //分配进程的页目录    if (!index) {        free_page((u32) tmp_task);     //如果失败,则释放pcb空间        return -1;    }    INIT_LIST_HEAD(&(tmp_task->list));    *tmp_task = *current;    tmp_task->state = TASK_STOPPED;    //复制父进程的页目录和页表    copy_mem(index_to_vaddr(index), paddr_to_vaddr(current->tss.cr3));    //复制父进程的堆栈给子进程,但EAX修改为0,以下代码先实现之,以后再优化    ptmp = (addr_t *)((u8 *)tmp_task + PAGE_SIZE - 4);    *ptmp-- = SS3 & 0x00FF;         //0ffc    *ptmp-- = ESP3;                 //0ff8    *ptmp-- = EFLAG;                //0ff4    *ptmp-- = CS & 0x00FF;          //0ff0    *ptmp-- = EIP;                  //0fec    *ptmp-- = DS & 0x00FF;          //0fe8    *ptmp-- = ES & 0x00FF;          //0fe4    *ptmp-- = GS & 0x00FF;          //0fe0    *ptmp-- = FS & 0x00FF;          //0fdc    *ptmp-- = EBP;                  //0fd8    *ptmp-- = EDI;                  //0fd4    *ptmp-- = ESI;                  //0fd0    *ptmp-- = EDX;                  //0fcc    *ptmp-- = ECX;                  //0fc8    *ptmp = EBX;                    //0fc4    //子进程的页目录地址    tmp_task->tss.cr3 = (u32)index_to_paddr(index);    tmp_task->tss.esp0 = (u32)ptmp;// tmp_task + PAGE_SIZE;    tmp_task->tss.eip = (u32)CHILD_RET_FROM_SYS_CALL;       //因为是子进程,所以当被调度时,直接从这里运行返回用户空间    tmp_task->state = TASK_RUNNING;                         //进程状态    tmp_task->counter = current->counter / 2;               //运行时间片,对进程0来说是没有用的,只有没有其他进程可调度的情况下才会调度进程0    tmp_task->priority = current->priority;                 //优先级,对进程0来说也没有用的    tmp_task->uid = tmp_task->euid = tmp_task->suid = 0;    tmp_task->gid = tmp_task->egid = tmp_task->sgid = 0;    tmp_task->signal = 0;                   //信号,按位    tmp_task->signal_blocked = 0;           //被掩码的信号,位图    tmp_task->pid = get_free_pid();         //进程的pid    tmp_task->pgrp = 0;                     //组id    tmp_task->session = 0;                  //    tmp_task->leader = 0;                   //    tmp_task->p_original_parent = current;  //原始的父进程    tmp_task->p_parent = current;           //父进程    tmp_task->p_child = NULL;               //子进程    tmp_task->p_younger_sibling = NULL;     //弟进程    tmp_task->p_older_sibling = current->p_child;       //兄进程    if (tmp_task->p_older_sibling) {        //如果存在兄进程,则给兄进程设置弟进程        tmp_task->p_older_sibling->p_younger_sibling = tmp_task;    }    tmp_task->uid = 0;                      //用户id    tmp_task->euid = 0;                     //有效用户id    tmp_task->suid = 0;                     //保存的用户id,好像没有用啊    tmp_task->gid = 0;                      //组id    tmp_task->egid = 0;                     //有效组id    tmp_task->sgid = 0;                     //保存的组id    tmp_task->alarm = 0;    tmp_task->user_time = 0;                //用户态运行时间(滴答数)    tmp_task->system_time = 0;              //内核态运行时间(滴答数)    //cutime,                               //子进程用户态运行时间(滴答数),好像没有用啊    //cstime,                               //子进程内核态运行时间(滴答数),好像没有用啊    tmp_task->start_time = 0;               //进程开始的时间    tmp_task->rss = 0;                      //常驻内存的页面数,暂时不用    tmp_task->tty = -1;                     //如果等于-1,则表示没有tty    tmp_task->umask = 0;                    //文件创建属性屏蔽位    tmp_task->pwd = NULL;                   //当前工作目录i节点    tmp_task->root = NULL;                  //根目录i节点    tmp_task->executable = NULL;            //执行文件i节点    tmp_task->original_esp0 = (u32)tmp_task + PAGE_SIZE;    current->p_child = tmp_task;    cli();    add_run_queue(tmp_task);                 //加入可调度任务队列    sti();    return tmp_task->pid;                    //返回子进程的pid}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -