babyos2一个进程跑起来之后一直无法退出,因为fork出一个新进程,并执行exec后,通过中断返回设置的frame->eip进入新进程main入口函数,栈上并无正确的返回地址,所以若进程所有代码执行完成,到末尾return时会发生错误,因为系统下一步不知道该执行哪了。
目前一方面为了测试,一方面为了进程不会挂,init和shell进程都会执行一个while(1)然后定时打印一个字母。如果不while (1):
可以发现因为执行了随机的指令,进程访问了非法地址,导致Segment fault。
exit
一个比较简单的exit大约需要做下面几件事情:
1)释放自己的资源
2)将自己的所有孩子过继给init
3)进程状态设置为ZOMBIE
4)通知父进程收尸
5)主动调度出去,不会再调度回来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();
}