babyos2(17)—— exit, wait

babyos2一个进程跑起来之后一直无法退出,因为fork出一个新进程,并执行exec后,通过中断返回设置的frame->eip进入新进程main入口函数,栈上并无正确的返回地址,所以若进程所有代码执行完成,到末尾return时会发生错误,因为系统下一步不知道该执行哪了。
目前一方面为了测试,一方面为了进程不会挂,init和shell进程都会执行一个while(1)然后定时打印一个字母。如果不while (1):
这里写图片描述

可以发现因为执行了随机的指令,进程访问了非法地址,导致Segment fault。

  1. exit
    一个比较简单的exit大约需要做下面几件事情:
    1)释放自己的资源
    2)将自己的所有孩子过继给init
    3)进程状态设置为ZOMBIE
    4)通知父进程收尸
    5)主动调度出去,不会再调度回来

  2. wait
    一个简单的wait需要:
    1)找到指定pid的儿子,若pid==-1则找任意儿子
    2)若未找到,可能没有这么个儿子,wait结束,继续运行
    3)若找到,且儿子已经ZOMBIE,释放process结构,wait结束,继续运行
    4)若找到,且儿子未死,则睡眠等待
    5)等到有儿子挂了,会唤醒自己,此时再检查一遍,是不是等的那个儿子,若是,wait结束,继续运行


void process_t::adope_children()
{
    process_t* child_reaper = os()->get_arch()->get_cpu()->get_child_reaper();
    list_t<process_t *>::iterator it = m_children.begin();
    while (it != m_children.end()) {
        (*it)->m_parent = child_reaper;
        it++;
    }
}

void process_t::notify_parent()
{
    // SIGCHLD is needed, but now not support signal
    // so just wake up parent
    os()->get_arch()->get_cpu()->wake_up_process(m_parent);
}

int32 process_t::wait_children(int32 pid)
{
repeat:
    cli();
    m_state = PROCESS_ST_SLEEP;
    list_t<process_t *>::iterator it = m_children.begin();

    bool flag = false;
    for (it; it != m_children.end(); it++) {
        process_t* p = *it;
        if (pid != -1 && pid != p->m_pid) {
            continue;
        }

        // find pid, or any child if pid == -1
        flag = true;

        if (p->m_state != PROCESS_ST_ZOMBIE) {
            continue;
        }

        // this child has be ZOMBIE, free it
        os()->get_mm()->free_pages(p, 1);
        goto end_wait;
    }
    sti();

    // if find pid, or any child if pid == -1
    if (flag) {
        // sleep to wait child exit
        os()->get_arch()->get_cpu()->schedule();

        // wake up by a exited child, repead to check
        goto repeat;
    }

end_wait:
    // continue to run
    m_state = PROCESS_ST_RUNABLE;
    return 0;
}

int32 process_t::exit()
{
    // remove the resource, now only memory 
    m_vmm.release();

    // adope children to init
    adope_children();

    // do not schedule before finish to notify parent
    cli();

    m_state = PROCESS_ST_ZOMBIE;

    // let parent wake up, and mourn us
    notify_parent();

    sti();

    os()->get_arch()->get_cpu()->schedule();

    return 0;
}

这里写图片描述

init创建出shell来之后,调用wait等待子进程退出,shell开始执行后每隔2s打印一个S,打印4次后调用exit退出进程。
可以发现shell成功退出,退出后init被唤醒,之后init每隔2s打印一个I.

wait queue:

/*
 * 2018-01-02
 * guzhoudiaoke@126.com
 */

#ifndef _WAIT_QUEUE_H_
#define _WAIT_QUEUE_H_

#include "types.h"
#include "spinlock.h"
#include "list.h"

class process_t;
class wait_queue_t {
public:
    void init();
    void add(process_t* proc);
    void remove(process_t* proc);
    void wake_up();
private:
    spinlock_t              m_lock;
    list_t<process_t *>     m_procs;
};

#endif


/*
 * 2018-01-02
 * guzhoudiaoke@126.com
 */

#include "waitqueue.h"
#include "process.h"
#include "babyos.h"

void wait_queue_t::init()
{
    m_lock.init();
    m_procs.init();
}

void wait_queue_t::add(process_t* proc)
{
    m_lock.lock_irqsave();
    m_procs.push_back(proc);
    m_lock.unlock_irqrestore();
}

void wait_queue_t::remove(process_t* proc)
{
    m_lock.lock_irqsave();
    list_t<process_t *>::iterator it = m_procs.begin();
    while (it != m_procs.end()) {
        if (*it == proc) {
            m_procs.erase(it);
            break;
        }
        it++;
    }
    m_lock.unlock_irqrestore();
}

void wait_queue_t::wake_up()
{
    m_lock.lock_irqsave();
    if (!m_procs.empty()) {
        list_t<process_t *>::iterator it = m_procs.begin();
        os()->get_arch()->get_cpu()->wake_up_process((*it));
    }
    m_lock.unlock_irqrestore();
}


int32 process_t::wait_children(int32 pid)
{
    current->m_wait_child.add(current);
repeat:
    cli();
    m_state = PROCESS_ST_SLEEP;
    list_t<process_t *>::iterator it = m_children.begin();

    bool flag = false;
    for (it; it != m_children.end(); it++) {
        process_t* p = *it;
        if (pid != -1 && pid != p->m_pid) {
            continue;
        }

        // find pid, or any child if pid == -1
        flag = true;

        if (p->m_state != PROCESS_ST_ZOMBIE) {
            continue;
        }

        // this child has be ZOMBIE, free it
        os()->get_arch()->get_cpu()->release_process(p);
        goto end_wait;
    }
    sti();

    // if find pid, or any child if pid == -1
    if (flag) {
        // sleep to wait child exit
        os()->get_arch()->get_cpu()->schedule();

        // wake up by a exited child, repead to check
        goto repeat;
    }

end_wait:
    // continue to run
    m_state = PROCESS_ST_RUNABLE;
    current->m_wait_child.remove(current);
    return 0;
}



void process_t::notify_parent()
{
    // SIGCHLD is needed, but now not support signal
    // so just wake up parent
    m_parent->m_wait_child.wake_up();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值