2012-04-19 59 views
0

调用read后居然会发生什么:读取后会发生什么叫做一个Linux插座

n = read(fd, buf, try_read_size); 

这里fd是一个TCP套接字描述符。 buf是缓冲区。 try_read_size是程序试图读取的字节数。

我想这可能会最终调用一个系统调用内核。但任何人都可以提供一些细节?说在glibc或内核源代码中的源代码实现?

+1

内核的细节实在是太复杂了短,所以回答。顺便说一句,你为什么不自己检查一下? – 2012-04-19 10:38:50

+0

@KarolyHorvath我试过但完全迷路了。任何方向或建议获取细节?我会高度赞赏它。 – ericzma 2012-04-19 10:46:48

+0

从linux内核源代码读取fs/read_write.c,看看发生了什么。 – strkol 2012-04-19 10:50:36

回答

4

从高层的角度来看,这是会发生什么:

  • 由glibc的发明提供一种包装函数被调用
  • 包装器函数将在堆栈上传递到寄存器中的参数,并设置系统调用编号在专用于该目的(例如EAX在x86)寄存器
  • 包装函数执行陷阱或等效指令(例如SYSENTER)
  • 的CPU切换到的ring0,和陷阱处理程序被调用
  • 陷阱处理程序检查系统调用号的有效性并在跳转表中查找它以查找内核函数
  • 相应的内核函数检查参数是否有效(例如,范围bufbuf+try_read_size指的是可访问的内存页面,fd实际上是一个文件描述符)。如果出现错误,会生成负面的错误代码(例如-EFAULT),将CPU切换回用户模式,然后调用返回到包装器。
  • 另一个功能是根据文件描述符的类型,称为(你的情况插座,但人们可以从一个块设备或proc项或更多的东西异国读)
  • 套接字的输入缓冲区检查:
    • 如果缓冲区中存在一些数据,则将min(available, try_read_size)复制到buf,将数量写入返回码寄存器(x86上的EAX),CPU将切换回用户模式,并且调用返回到包装。
    • 如果输入缓冲器是空的
      • 如果连接已经关闭,零被写进到返回码寄存器中,CPU切换回用户模式和呼叫返回到包装
      • 如果连接已经被关闭
        • 负的错误代码(-EAGAIN)被写入到如果套接字非阻塞的返回码寄存器中,CPU切换回用户模式和呼叫返回到包装。
        • 如果套接字不无阻塞
  • 包装函数检查返回值是否是负的(错误)的处理暂停。
    • 如果为正数或零,则返回该值。
    • 如果为负,它设置errno为否定值(报道一积极错误),并返回-1
+0

+1,非常好。如果进程暂停,它会阻塞,直到至少接收到一个字节的数据或接收到一个FIN,或者在套接字上发布错误,则包含此信息的最外面的项目符号重新开始。 – EJP 2012-04-22 23:14:56