侯捷 - C++ Startup 揭密:C++ 程序的生前和死后 (四)

前言

I/O泛指程序和外界的各种交互作用,包括file,pipe,network,console,semaphore等等。或者泛指能被OS理解为file的任何事物——file是一种广义概念。

FILE *fp=fopen("xxx.dat",“wb”);

 很少人去关注这个FILE是个什么东西,这关系到我们接下来要谈的启动代码startcode对于I/O的初始化。

struct _iobuf{...};
typedef struct _iobuf FILE;

C语言层面通过一个pointer to FILE 来进行file操作。

在OS操作系统层面,Linux对应于FILE的是File Desriptor(fd),Windows对应的则是file handle。两者都是来映射kernel file object,但经过包装最后都成为了C语言所认识的pointer to FILE。

我们在编程时,只需要关注的时C语言层面的pointer to FILE,但是其与操作系统OS的fd或file handle有着一一对应的关系。我们现在就把这层关系挖出来。我们就能了解_IO_INIT在做什么。

fd是什么

fd 具体是个index of opened file table ——process个别拥有的这个table是个array of pointers,每个point指向一个kernel opened object。当client开启一个file,OS会建立一个(kernel)opened file object 并找到上述table中的一个idle entry指向之,然后以该entry 的 index 当作 fd。 此table位于kernel mode,因此client客户即使拥有fd亦无法获取table address。Linux的fd 0,1,2分别代表stdin,stdout,stderr。

C的FILE 与 Linux的 fd 必有一对一关系。只要有table address p,p+fd 就指向opened file table 的某个entry,从而可得kernel file object。(kernel mode所在得地址,使用者user mode是永远拿不到的)

Windows的file handle和Linux的fd大同小异,但handle不是idex,而是index经某种变种后的结果

I/O initialization就是要在client space 中建立起stdin、stdout、stderr及其对应的FILEs,使程序进入main()之后立即可以使用printf()、scanf()等函数。

_io_init() 与 fopen() 总览

1._io_init行为

下图右侧的备注建议好好阅读下。

注意图中序号对应部分。

①:ioinfo是什么?其对应到C/C++程序对应的fopen得到的变量(FILE *fp=fopen("xxx.dat",“wb”)中的FILE* 变量)。Linux对应于FILE的是File Desriptor(fd),Windows对应的则是file handle

每个进程至少有三个file handle(stdin,stdout,stderr),接下来的动作就是把继承下来的这三个或更多的file handle抄录到struct ioinfo。所以,一个进程最多可以开出64*32=2048个FILE,其中包括从父进程继承下来的部分。

③:操作系统怎么把继承而来的这三个或更多的file handle拷贝到struct ioinfo?

⑥:注意相同颜色部分。C语言开启一个FILE以后得到指针指向_iobuf这么一个结构。其中的_file(2^11=2048)怎么解释呢?其中的六个bit(#5~#10)表示第一维索引,共2^6=64。其他五个bit(#0~#4)表示第二维索引,共2^5=32个ioinfo。.

2.kernel mode 与 user mode 之间的桥梁

lpReserved2 将指向 inherited handles info 。字节0~3表示一个N值,代表了继承了几个file handle(原则上一般至少有stdin、stdout、stderr 三个file handle)。  N value for OSfile 则是 ioinfo 结构体中的 char os file,N OS handle values 则是ioinfo结构体中的 long osfhnd。

借由调用GetstartupInfo函数,取得lpReserved2指针,指向inherited handles info,取出N,OSfile,osfhnd,copy填入到ioinfo的结构体中。借由这种方式去登记/记载 父进程继承而来的file handle。

由上可知一个进程最多可以容纳/拥有/开启 32*64=2048 个ioinfo 。而fopen()会去寻找一个还没有使用的.

实验

参考:博览网——侯捷 - C++ Startup 揭密:C++ 程序的生前和死后

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值