Linux-0.11内核分析04:进程2的创建及执行

--- init --- main.c --- sched_init()
 |                   |- init() --- setup() --- int 0x80
 |                              |- open("/dev/tty0") --- int 0x80
 |                              |- dup(0) --- int 0x80//建立标准输出文件
 |                              |- dup(0) --- int 0x80//标准错误文件
 |                              |- pid=fork() --- int 0x80
 |                              |- if(!pid) --- Yes --- close(0)
 |                                           |       |- open("/etc/rc")
 |                                           |       |- execve("/bin/sh")
 |                                           |- No --- 等待pid==wait(&i)//切换到进程2,并等待其退出
 |                                                  |- fork() --- int 0x80
 |                                                  |- close(0);close(1);close(2);
 |                                                  |- open("/dev/tty0")
 |                                                  |- dup(0);dup(0);
 |                                                  |- execve("/bin/sh")//重启shell进程
 |                                                     //由于打开的是标准输入设备,因此不会退出
 |                                                     //系统进入怠速模式
 |
 |- kernel --- sched.c --- sched_init() --- set_system_gate(0x80,&system_call)
 |          |
 |          |- system_call.s --- system_call() --- sys_call_table(,%eax,4)
 |          |                 |- sys_execve() --- eax指向堆栈中eip指针处
 |          |                                  |- do_execve()
 |          |
 |          |- exit.c --- sys_waitpid --- 找到current的子进程*p,也就是进程2
 |                     |               |- p处于僵死态,则返回(*p)->pid
 |                     |               |  否则继续运行  
 |                     |               |- 设置current->state为等待状态
 |                     |               |- schedule()//切换到进程2
 |                     |               |- 检测到SIGCHLD信号量,返回第1条执行
 |                     |- sys_exit() --- do_exit()
 |                     |- do_exit() --- 释放shell进程所占据的内存页面
 |                                   |- 将update的父进程设置为进程1
 |                                   |- 关闭当前进程打开着的所有文件
 |                                   |- 把当前进程置为僵死状态
 |                                   |- tell_father()//通知父进程
 |                                   |- schedule()//发现进程1收到信号,切换到进程1
 |
 |- include --- linux --- sys_call_table[] --- sys_open()
 |                                          |- sys_dup(0)
 |                                          |- sys_fork()//复制父进程
 |                                          |- sys_waitpid()
 |                                          |- sys_close()
 |                                          |- sys_read()
 |                                          |- sys_exit()
 |
 |- fs --- open.c --- sys_open(pathname) --- 找到current中空闲filp[fd]
 |      |          |                      |- 在file_table[64]中获取空闲项的地址f
 |      |          |                      |- filp[fd]=f
 |      |          |                      |- 文件引用计数加1
 |      |          |                      |- open_namei(pathname,&inode)
 |      |          |                      |- current->tty = MINOR(inode->i_zone[0])
 |      |          |                      |- f->f_inode = inode//设置file_table[0]
 |      |          |- sys_close() --- filp = current->filp[fd]
 |      |                          |- current->filp[fd] = NULL
 |      |                          |- filp->f_count减1  
 |      |
 |      |- namei.c --- open_namei() --- dir=get_dir(pathname,&namelen,&namebase)
 |      |           |                |  //获取dev目录inode,以及'tty0'的长度和首地址
 |      |           |                |- find_entry(&dir,namebase,namelen,&de)
 |      |           |                |  //根据上面的信息得到目录项de
 |      |           |                |- inr=de->inode; dev=dir->i_dev
 |      |           |                |- 保存inr和dev在table_inode[32]中
 |      |           |                |- inode=iget(inr,dev)//得到tty0的i节点
 |      |           |- get_dir() --- inode = current->root
 |      |                         |- pathname指向'd'
 |      |                         |- thisname = pathname
 |      |                         |- 获取thisname的长度namelen
 |      |                         |- pathname指向下一个目录
 |      |                         |- pathname是最后一个目录则返回inode
 |      |                         |- find_entry(&inode,thisname,namelen,&de)
 |      |                         |  //根据上面的信息得到目录项de
 |      |                         |- inr=de->inode; dev=dir->i_dev
 |      |                         |- iput(inode)
 |      |                         |- inode=iget(idev,inr)
 |      |                         |- 返回3执行
 |      |
 |      |- fcntl.c --- sys_dup() --- dupfd(0,0)
 |      |           |- dupfd() --- 在进程1的filp[20]中寻找空闲项filp[arg]
 |      |                       |- filp[arg]指向目标文件
 |      |
 |      |- exec.c --- do_execve() --- inode=namei(filename)
 |      |                          |- bh = bread(inode->i_dev,inode->i_zone[0])
 |      |                          |- ex = *((struct exec *) bh->b_data)
 |      |                          |- eip[0] = ex.a_entry//eip指向shell程序
 |      |                             //由于该线性空间对应的程序内容未加载,因此会触发 page_fault
 |      |
 |      |- read_write.c --- sys_read() --- 如果是普通文件,读取完成后返回-ERROR
 |
 |- mm --- page.s --- page_fault() --- do_no_page()
        |- memery.c --- do_no_page() --- page = get_free_page()
                     |                |- bread_page(page,current->executable->i_dev,nr)
                     |                |- put_page(page)//建立页表映射关系,之后shell程序开始执行
                     |                   //中断退出后,shell程序执行
                     |- put_page() --- page_table = (address>>20) & 0xffc
                                    |- page_table[(address>>12) & 0x3ff] = page | 7   


--- bin --- sh --- 读取/etc/rc文件,并执行
 |
 |- etc --- rc --- /etc/update &//创建update程序,挂起后返回进程2
                |- echo "/dev/hd1 /" > /etc/mtab --- read() --- int 0x80  
                |- 返回错误则执行exit() --- int 0x80                

猜你喜欢

转载自blog.csdn.net/egean/article/details/81000818