(莱昂氏unix源代码分析导读-45) 文件与“资源”

                                    by cszhao1980

我们已经知道文件会占用很多资源,如磁盘inode资源、盘块资源,访问时还要占用inode

数组资源,等等。

 

除此之外,unix v6还使用file数组来记录整个系统中被open开的文件,file数组的定义如下:

5507: struct file

5508: {

5509:      char f_flag;

5510:      char f_count;     /* reference count */

5511:      int f_inode;       /* pointer to inode structure */

5512:      char *f_offset[2];   /* read/write character pointer */

5513: } file[NFILE];

 

而每个进程都记录了本进程“引用”的文件,记录在u_ofile数组之中:

0438: int u_ofile[NOFILE]; /* pointers to file structures of open files */

 

数组中每一项都指向一个file数组中的一个file

 

falloc()函数就用来申请这两种资源:

(1)         首先调用u falloc()在进程的u_ofile数组中占用一个空闲项,其indexi

(2)         然后在file数组中占用一空闲项,指针为fp

(3)         使u_ofile[i] = fp

 

为进一步了解资源占用情况,我们来看几个例子。

首先是open() sys call,用来打开一个已经存在的文件,该函数的实现非常简单:

5765: open()

5766: {

5767:     register *ip;

5768:     extern uchar;

5769:

5770:     ip = namei(&uchar, 0);

5771:     if(ip == NULL)

5772:         return;

5773:     u.u_arg[1]++;

5774:     open1(ip, u.u_arg[1], 0);

5775: }

 

首先,调用namei读取了文件的inode并占用了inode数组资源;

然后,调用open1()完成剩余的操作。

 

【注】: 5773行,莱昂解释说“这是由在用户程序设计约定和内部数据表示之间失配而造成的。”

                 举例说明就比较容易理解了:

(1)         用户接口中,使用012表示3种情况;

(2)         内部使用123代指这3种情况。

所以,对用户接口传入的该参数,使用前需要+1

 

open1(ip, mode, trf)相对比较复杂,它有三个参数:

(1)         ip:要open的文件的inode

(2)         mode open模式——FREADFWRITE等;

(3)         trf

i.       0:要打开一个已存在的文件;

ii.     2:输入的inode为新建inode(文件内容不存在);

iii.    1:文件存在,但需要删除,然后复用该inode

 

i用于open sys call

iiiii用于create sys call,我们呆会儿会讲到。

 

(1)         5813 ~ 5821进行权限控制,如果trf2,则该文件其实还不存在,故无需作此种检查;

(2)         if(trf)  itrunc(rip);

删除原有文件,其实将条件改为trf==1更好——对trf==2的情况,itrunc等同于空操作;

 

(3)         5827 ~ 5830 分配file数组和u_ofile数组资源,并进行设置;

 

(4)         5831~5832 行调用的openi()函数用于特殊设备处理,但普通文件视为空操作。

 

下面看看create sys call

5781: creat()

5782: {

5783:     register *ip;

5784:     extern uchar;

5785:

5786:     ip = namei(&uchar, 1);

5787:     if(ip == NULL) {

5788:         if(u.u_error)

5789:              return;

5790:         ip = maknode(u.u_arg[1]&07777&(~ISVTX));

5791:         if (ip==NULL)

5792:              return;

5793:         open1(ip, FWRITE, 2);

5794:     } else

5795:         open1(ip, FWRITE, 1);

5796: }

 

相比较open,它稍显复杂——分为两种情况:

1.              文件已经存在

      调用open1(ip, FWRITE, 1)——删除原有文件,复用其inode

 

2.              文件不存在

(1)   调用maknode()新建一inode

      makenode7455)是个简单的函数,它内部调用ialloc()分配磁盘inode资源,进行简单

     设置后,调用wdir()将此inode写入磁盘。

 

(2)   调用open1(ip, FWRITE, 2)分配file数组和u_ofile数组资源。

 

当操作成功时,opencreate函数没有显式的返回,这很令人惊奇。熟悉unix的同学都知道,

这里应该返回所谓的“文件描述符”。呵呵,如果您足够细心的话,您会在ufalloc中找到答案

——该函数将u_ar0[R0]设置为其所分配的u_ofile数组项的index——即“文件描述符”。

 

getf(f)将“文件描述符”转化为file数组指针——很简单,返回u_ofile[f]即可。

 

接着让我们看一下close()函数,它是open的“反”函数,用于释放各种资源:

5846: close()

5847: {

5848:     register *fp;

5849:

5850:     fp = getf(u.u_ar0[R0]);                      //得到file指针

5851:     if(fp == NULL)

5852:         return;

5853:     u.u_ofile[u.u_ar0[R0]] = NULL;              //释放占用的u_ofile数组项

5854:     closef(fp);                     

5855: }

 

6643: closef(fp)

6644: int *fp;

6645: {

6646:     register *rfp, *ip;

6647:

6648:     rfp = fp;

6649:     if(rfp->f_flag&FPIPE) {                                       //管道,skip

         ….

6654: }

6655:     if(rfp->f_count <= 1)          

6656:         closei(rfp->f_inode, rfp->f_flag&FWRITE);  //对普通设备,等同于调用iput(),释放inode资源

6657:     rfp->f_count--;                                                    //引用计数减1

6658: }

 

很奇怪,这里似乎缺少了释放file数组项的代码——其实不然,当引用计数为0时,则表示该数组项空闲。

 

最后,让我们看一下文件的读写函数。

首先是readwrite,它们是个壳函数,通过内部调用rdwr完成真正的操作。莱昂对这些函数进行了详细

的介绍——包括其参数的传递方式,在此不再赘述。

 

最后,看一下seek,即所谓的随机读写函数。它有三个参数:

(1)         文件描述符;

(2)         文件Offset

(3)         模式;

其参数传递同前者类似,即参数1r0传入;其余参数由u_arg[]数组传入。

 

unix/linux比较熟悉的同学会马上想起lseek函数——seek完成的确实是类似的功能。但相较而言,seek

显得更复杂——其主要原因在于unix v6使用两个word模拟一个32bit数来描述文件offset;而我们熟悉

lseek则使用1long型值(我们熟悉的32位机上,就是64 bit)就搞定了。

 

这个函数的解析就留给大家吧。

 

博客地址:http://blog.csdn.net/cszhao1980

博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值