TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Fundamentals of non blocking I/O on Linux/BSD

4 pointsby blopeurover 7 years ago

1 comment

wahernover 7 years ago
<p><pre><code> &gt; the file entry data structure maintains a file offset for &gt; every process </code></pre> File table entries aren&#x27;t per-process. That&#x27;s dangerously misleading. Without getting lost in the weeds, just remember that new file table entries are usually created for every open() or socket() call, in addition to a new descriptor table entry. Contrast that with dup() or fork(), which create new descriptor table entries that point to shared file table entries.<p>Why would this matter? Because as the article suggests (albeit ambiguously), a fork() has semantics similar to dup() in that the new process gets a cloned descriptor table. <i>but</i> with pointers to _shared_ file table entries. Why this matters, and why the article is misleading, is because when two processes perform reads through a shared file table entry for a regular file, the order of reads will matter as between the two processes because of the shared cursor; the sequence of data each process reads could differ based on random scheduling latencies.<p>File position cursors really only matter for regular files, not pipes or sockets. But another thing to keep in mind is the distinction between descriptor flags and file entry flags[1]. O_CLOEXEC is a descriptor flag, which means it&#x27;s not inherited when you dup() a descriptor (it is inherited across a fork, but that&#x27;s because you&#x27;re getting a clone of the entry which is thereafter distinct). However, flags like O_NONBLOCK are file entry flags, which means if process A forks process B and process B does fcntl(fd4, F_SETFL, O_NONBLOCK), all of a sudden fd4 will behave in a non-blocking manner in process A. Likewise, if you do dup2(fd4, fd5) then fcntl(fd5, F_SETFL, O_NONBLOCK), all of a sudden fd4 is non-blocking.<p>One interesting distinction between BSD and Linux is that on BSD opening &#x2F;dev&#x2F;fd&#x2F;N is identical to calling dup(); even though you&#x27;re using open() you get a shared file table entry. However, Linux symlinks &#x2F;dev&#x2F;fd to &#x2F;proc&#x2F;self&#x2F;fd and you get regular open() semantics with an unshared file table entry.<p>On Linux, at least, you can create a new file table entry for an existing pipe through &#x2F;proc&#x2F;self&#x2F;fd. But AFAIK you can&#x27;t open sockets through &#x2F;proc&#x2F;self&#x2F;fd. I&#x27;ve never really run into the need to do this, though. But it&#x27;s good to keep all of this in mind for regular files because shared cursors could easily cause headaches, perhaps even security issues.<p>FWIW, Unix descriptor passing has dup() semantics.<p>[1] Technically the term is file status flags, but when discussing this I prefer file entry flags (or file table entry flags) to highlight the relationship to descriptor flags.
评论 #15556033 未加载