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

**好的,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里面找到一个空闲项。

进程的flip数组大小是20,系统的file_table大小是64,每个进程最多打开20个文件,整个系统最多打开64个文件。

  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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神仙诙谐代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值