linux内核剖析之main.c

main函数主要做一些初始化,比如内存,块设备、字符设备等的初始化,然后创建子进程打开bin/sh

    mem_init(main_memory_start,memory_end);
    trap_init();    // 陷阱门(硬件中断向量)初始化。(kernel/traps.c)
    blk_dev_init();    // 块设备初始化。(kernel/blk_dev/ll_rw_blk.c)
    chr_dev_init();    // 字符设备初始化。(kernel/chr_dev/tty_io.c)空,为以后扩展做准备。
    tty_init();        // tty 初始化。(kernel/chr_dev/tty_io.c)
    time_init();    // 设置开机启动时间 -> startup_time。
    sched_init();    // 调度程序初始化(加载了任务0 的tr, ldtr) (kernel/sched.c)
    buffer_init(buffer_memory_end);// 缓冲管理初始化,建内存链表等。(fs/buffer.c)
    hd_init();        // 硬盘初始化。(kernel/blk_dev/hd.c)
    floppy_init();    // 软驱初始化。(kernel/blk_dev/floppy.c)

在任务0中创建任务1

    if (!fork()) {        /* we count on this going ok */
        init();
    }

init函数:初始化shell环境,执行bin/sh
void init(void)
{
    int pid,i;

// 读取硬盘参数包括分区表信息并建立虚拟盘和安装根文件系统设备。
// 该函数是在25 行上的宏定义的,对应函数是sys_setup(),在kernel/blk_drv/hd.c。
    setup((void *) &drive_info);

    (void) open("/dev/tty0",O_RDWR,0);    // 用读写访问方式打开设备“/dev/tty0”,
                                        // 这里对应终端控制台。
                                        // 返回的句柄号0 -- stdin 标准输入设备。
    (void) dup(0);        // 复制句柄,产生句柄1 号-- stdout 标准输出设备。
    (void) dup(0);        // 复制句柄,产生句柄2 号-- stderr 标准出错输出设备。
    printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, \
        NR_BUFFERS*BLOCK_SIZE);    // 打印缓冲区块数和总字节数,每块1024 字节。
    printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);//空闲内存字节数。

// 下面fork()用于创建一个子进程(子任务)。对于被创建的子进程,fork()将返回0 值,
// 对于原(父进程)将返回子进程的进程号。所以if (!(pid=fork())) {...} 内是子进程执行的内容。
// 该子进程关闭了句柄0(stdin),以只读方式打开/etc/rc 文件,并执行/bin/sh 程序,所带参数和
// 环境变量分别由argv_rc 和envp_rc 数组给出。参见后面的描述。
    if (!(pid=fork())) {
        close(0);
        if (open("/etc/rc",O_RDONLY,0))
            _exit(1);    // 如果打开文件失败,则退出(/lib/_exit.c)。
        execve("/bin/sh",argv_rc,envp_rc);    // 装入/bin/sh 程序并执行。(/lib/execve.c)
        _exit(2);    // 若execve()执行失败则退出(出错码2,“文件或目录不存在”)。
    }

// 下面是父进程执行的语句。wait()是等待子进程停止或终止,其返回值应是子进程的
// 进程号(pid)。这三句的作用是父进程等待子进程的结束。&i 是存放返回状态信息的
// 位置。如果wait()返回值不等于子进程号,则继续等待。
    if (pid>0)
        while (pid != wait(&i))
        {    /* nothing */;}

// --
// 如果执行到这里,说明刚创建的子进程的执行已停止或终止了。下面循环中首先再创建
// 一个子进程,如果出错,则显示“初始化程序创建子进程失败”的信息并继续执行。对
// 于所创建的子进程关闭所有以前还遗留的句柄(stdin, stdout, stderr),新创建一个
// 会话并设置进程组号,然后重新打开/dev/tty0 作为stdin,并复制成stdout 和stderr。
// 再次执行系统解释程序/bin/sh。但这次执行所选用的参数和环境数组另选了一套(见上面)。
// 然后父进程再次运行wait()等待。如果子进程又停止了执行,则在标准输出上显示出错信息
//        “子进程pid 停止了运行,返回码是i”,
// 然后继续重试下去…,形成“大”死循环。
    while (1) {
        if ((pid=fork())<0) {
            printf("Fork failed in init\r\n");
            continue;
        }
        if (!pid) {
            close(0);close(1);close(2);
            setsid();
            (void) open("/dev/tty0",O_RDWR,0);
            (void) dup(0);
            (void) dup(0);
            _exit(execve("/bin/sh",argv,envp));
        }
        while (1)
            if (pid == wait(&i))
                break;
        printf("\n\rchild %d died with code %04x\n\r",pid,i);
        sync();
    }
    _exit(0);    /* NOTE! _exit, not exit() */
}

猜你喜欢

转载自blog.csdn.net/wyyy2088511/article/details/108367223
今日推荐