Date: Wed, 08 Jan 2020 07:30:12 -0800 From: "Ronald F. Guilmette" <rfg@tristatelogic.com> To: freebsd-questions@freebsd.org Subject: Re: Independence of file descriptor flags across forks (or lack thereof) Message-ID: <99921.1578497412@segfault.tristatelogic.com> In-Reply-To: <20200108114244.b431a9ae0170ec947e6fb7d8@sohara.org>
next in thread | previous in thread | raw e-mail | index | archive | help
In message <20200108114244.b431a9ae0170ec947e6fb7d8@sohara.org>, Steve O'Hara-Smith <steve@sohara.org> wrote: >> that are currently open in the parent process, the child would also get >> its own independent copy of the system-maintained "flags word" for each >> of those inherited file descriptor copies. > > The fork manpage tells you that the descriptors reference the same >underlying object. It is that object (the open file) which holds the "flags >word". I am not persuaded. I do not wish to be impertinent, but can you point me to the place in the UFS file system specification that will show me where the per-file blocking/ non-blocking bits are stored? >> So dear friends, I must ask you, am I delusional? Is this all just some >> massive misunderstanding on my part? > > Yep. I am sorry to disagree, but I am still not persuaded. Yes, the underyling thing is the same for the child and parent processes, but this fact alone does not imply that both the parent and child have the exact same view of that underlying thing -or- the exact same capabilities with respect to that underyling thing. If one or the other, parent process or child process, closes the file, then is the file also closed as far as the other process is concerned, from that time onward? Of course not. This fact alone proves that a given process' relationship with a file descriptor (or a message queue descriptor) is different and distinct from the underyling file itself. There must be maintained (somewhere) an open/closed bit which is a characteristic not of the underlying file itself, but rather of one particular process' current relationship with and to that underyling file. So there is clearly (a) the underlying thing, and then there is (b) each process' relationship to, and current capabilities in relation to that underlying thing. A file itself is neither blocking nor non-blocking, even if the underyling thing is some FIFO, pipe, or socket. It is still just a thing which can be acted upon by some process. One process can act on the thing, e.g. attempting to read from it, in a non-blocking manner, while the other process may elect, for its own reasons, to read from that some underlying thing with blocking semantics, i.e. waiting for data to be present before returning from the call to read() or mq_receive(). There is no contradition here, and indeed, I have found an instance in which what I habe just described is quite pragmatically useful. Unfortunately, neither of us have so far cited to any authority which might settle this matter definitively. I will now cite to an authority, but if I am to be intellectually honest then I will have to admit that even what I will now cite to may not clearly or definitively settle the matter. All I really have to go on, here with me, is a very old and yellowed hardcopy of IEEE "POSIX" 1003.1b-1993. In this hardcopy document, Section 6.5.2.2 seems most relevant, since it discusses various file attributes that can be read or written with the fcntl() system call. The fcntl operations and their respective descriptions that seem mosty directly relevant are these: F_GETFD F_SETFD F_GETFL F_SETFL Of course, the document that I am looking at dates from 1993, and thus may have been totally superceeded and rewritten by now, but I have also done a search for "fcntl" in the "system interfaces" section at this location: https://pubs.opengroup.org/onlinepubs/9699919799/ and I assume that this gives me more up-to-date information on the current semnatics of "POSIX-conformant" systems. Sadly however, all I get back in this case is something that looks an awful lot like a man page for fcntl() and it largely or entirely just repeats the same text as is present in my old hardcopy copy of the 1993 POSIX standard. Here are relevant passages: F_GETFD Get the file descriptor flags defined in <fcntl.h> that are associated with the file descriptor fildes. File descriptor flags are associated with a single file descriptor and do not affect other file descriptors that refer to the same file. F_SETFD Set the file descriptor flags defined in <fcntl.h>, that are associated with fildes, to the third argument, arg, taken as type int. If the FD_CLOEXEC flag in the third argument is 0, the file descriptor shall remain open across the exec functions; otherwise, the file descriptor shall be closed upon successful execution of one of the exec functions. F_GETFL Get the file status flags and file access modes, defined in <fcntl.h>, for the file description associated with fildes. The file access modes can be extracted from the return value using the mask O_ACCMODE, which is defined in <fcntl.h>. File status flags and file access modes are associated with the file description and do not affect other file descriptors that refer to the same file with different open file descriptions. The flags returned may include non-standard file status flags which the application did not set, provided that these additional flags do not alter the behavior of a conforming application. F_SETFL Set the file status flags, defined in <fcntl.h>, for the file description associated with fildes from the corresponding bits in the third argument, arg, taken as type int. Bits corresponding to the file access mode and the file creation flags, as defined in <fcntl.h>, that are set in arg shall be ignored. If any bits in arg other than those mentioned here are changed by the application, the result is unspecified. If fildes does not support non-blocking operations, it is unspecified whether the O_NONBLOCK flag will be ignored. As I say, all of the above is almost entirely just a reprint/reiteration of almost identical text which is present also in the hardcopy of the 1993 POSIX standard document that I have here. The only possibly relevant difference is that the POSIX document I have here, in its description of F_GETFL and F_SETFL makes explict reference to the attributes listed in table 6-5, where table 6-5, on the preceeding page, includes all of the following: O_APPEND O_DSYNC O_NONBLOCK O_RSYNC O_SYNC I believe that my position, i.e. that flags (such as O_NONBLOCK) must be maintained separately for each separate file descriptor, including even those that are derived from a "parent" file descriptor, is supported by the passage, reproduced above in relation to F_GETFL, that says explicitly: File status flags and file access modes are associated with the file description and do not affect other file descriptors that refer to the same file with different open file descriptions. Why else would the authors of this standard have included such stilted and, admittedly, imprecise language as that if they were NOT attempting to say exactly what I have said? And just to reiterate, what I have said is that the standard appears to me to require that there must exist a unique set of attribute bits, associated with each and every open file descriptor, -and- that POSIX requires that such a set of attributs must be maninated -separately- for each FD in each process, even for a pair of file descriptors that happen to be related by blood (i.e. one descending from the other). That is my reading of it anyway. Furthermore the section of this same standards document that talks about the fork() system call is at pains to say explicitly that the forked child obtains "a copy" of the parent's file descriptors, NOT the parent's file descriptors themselves. Based on that, after a fork(), if the parent had one FD, then there now exist *two* FDs in its place. And likewise, if the parent had two FDs, then after the fork() we can say that there now exist four FDs. This makes clear, I think, the special meaning of the phrasing "... do not affect other file descriptors that refer to the same file ...". After a fork() there are now twice as many FDs as there were before, and they are all separate and distinct things, in and of themselves, and fiddling the flags (such as the O_NONBLOCK) flag on one is *not* supposed to affect the setting of that same flag in any of the others. That is my interpretation anyway. But I welcome any reasonable challenge to the above reasoning. Regards, rfg
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?99921.1578497412>