0
点赞
收藏
分享

微信扫一扫

用大白话说操作系统(十三)

酷子腿长一米八 2022-04-29 阅读 37

**好的,OK,上次我们说到了加载根文件系统,我们可以根据根inode找到所有的文件。

void init(void) {
    setup((void *) &drive_info);
    (void) open("/dev/tty0",O_RDWR,0);
    (void) dup(0);
    (void) dup(0);
}

我们可以看到下一行就是一个open函数,之前说过open函数使用系统调用l打开文件/dev/tty0,之后后面还有两个dup。
open函数会触发0x80中断,通过调用sys_open这个系统调用函数。

open.c

struct file file_table[64] = {0};

int sys_open(const char * filename,int flag,int mode) {
    struct m_inode * inode;
    struct file * f;
    int i,fd;
    mode &= 0777 & ~current->umask;

    for(fd=0 ; fd<20; fd++)
        if (!current->filp[fd])
            break;
    if (fd>=20)
        return -EINVAL;
    current->close_on_exec &= ~(1<<fd);

    f=0+file_table;
    for (i=0 ; i<64 ; i++,f++)
        if (!f->f_count) break;
    if (i>=64)
        return -EINVAL;

    (current->filp[fd]=f)->f_count++;

    i = open_namei(filename,flag,mode,&inode);

    if (S_ISCHR(inode->i_mode))
        if (MAJOR(inode->i_zone[0])==4) {
            if (current->leader && current->tty<0) {
                current->tty = MINOR(inode->i_zone[0]);
                tty_table[current->tty].pgrp = current->pgrp;
            }
        } else if (MAJOR(inode->i_zone[0])==5)
            if (current->tty<0) {
                iput(inode);
                current->filp[fd]=NULL;
                f->f_count=0;
                return -EPERM;
            }
    if (S_ISBLK(inode->i_mode))
        check_disk_change(inode->i_zone[0]);

    f->f_mode = inode->i_mode;
    f->f_flags = flag;
    f->f_count = 1;
    f->f_inode = inode;
    f->f_pos = 0;
    return (fd);
}

在这里插入图片描述

  1. 在进程描述符数组filp中找到一个空闲项。在进程的数据结构task_struct里面有一个filp数组的字段,这个就是文件描述符数组,空闲的地方索引值fd。
  2. 在系统文件表file_table里面找到一个空闲项。
  1. 将进程的文件描述符数组项和系统的文件表项对应起来。
  2. 根据文件名从文件系统中找到这个文件。
  3. 填充file数据,就是初始化这个f,包括刚刚找到的inode值,最后返回给上层文件描述符fd的值,也就是0.
    open函数返回的0号fd,作为标准输入设备,接下来的dup为1号fd赋值,作为标准输出设备,接下来的dup为2号fd赋值,作为标准错误输出设备,这就是常说的stdin.stdout,stderr。
int sys_dup(unsigned int fildes) {
   return dupfd(fildes,0);
}

// fd 是要复制的文件描述符
// arg 是指定新文件描述符的最小数值
static int dupfd(unsigned int fd, unsigned int arg) {
   ...
   while (arg < 20)
       if (current->filp[arg])
           arg++;
       else
           break;
   ...
   (current->filp[arg] = current->filp[fd])->f_count++;
   return arg;
}

dup就是从进程的filp中找到下一个空闲项,然后把要复制的文件描述符fd的信息,复制到这里。
**进程1比进程0多了与外设交互的能力,进程1创建之后通过setup加载根文件系统,open打开tty0设备文件,使得进程1具备了与外设交互的能力。
好的,继续往下看下去。

void init(void) {
   ...
   if (!(pid=fork())) {
       close(0);
       open("/etc/rc",O_RDONLY,0);
       execve("/bin/sh",argv_rc,envp_rc);
       _exit(2);
   }
   ...
}
  1. fork一个新的子进程,就是进程2.
  2. 在进程2里面关闭0号文件描述符
  3. 只读形式打开rc文件
  4. 执行sh文件

除此之外,进程1fork进程2会复制一份filp数组,这样进程2和进程1一样有了与外设交互的能力。
进程0复制进程1页表复制只有160项,也就是640K,而之后的复制都是1024项,也就是4M空间。
close()函数

int sys_close(unsigned int fd) {   
    ...
    current->filp[fd] = NULL;
    ...
}

open()函数

void init(void) {
    ...
    if (!(pid=fork())) {
        ...
        open("/etc/rc",O_RDONLY,0);
        ...
    }
    ...
}

这里的open函数打开的/etc/rc文件正好占据了0号文件描述符的位置。

举报

相关推荐

0 条评论