Hacker News new | comments | show | ask | jobs | submit login

From the man page...

> Q6 Will closing a file descriptor cause it to be removed from all epoll sets automatically?

> A6 Yes, but be aware of the following point. A file descriptor is a reference to an open file description (see open(2)). Whenever a file descriptor is duplicated via dup(2), dup2(2), > fcntl(2) F_DUPFD, or fork(2), a new file descriptor referring to the same open file description is created. An open file description continues to exist until all file descriptors refer‐ > ring to it have been closed. A file descriptor is removed from an epoll set only after all the file descriptors referring to the underlying open file description have been closed (or > before if the file descriptor is explicitly removed using epoll_ctl(2) EPOLL_CTL_DEL). This means that even after a file descriptor that is part of an epoll set has been closed, events > may be reported for that file descriptor if other file descriptors referring to the same underlying file description remain open.

EDIT:

Lots of comments here seem to think this should be unexpected or is a bug. Closing a FD you are using is a bug. I think epoll does a fairly good job of letting the user know that it is watching the description and not the descriptor. Failing to read the man page for dup would also leave you in a blind spot. I have been writing code for linux a while now and I did not think it was any secret that a file is still open until all of the fds pointing to it are closed. That is why you have to take care and close your duplicated fds at the right time otherwise you will end up with file handles leaking. The example code provided illustrates this perfectly.

As a side note using dup2 to get your original FD passed to epoll associated with the still open description from the duped fd should allow you to remove it.




> Closing a FD you are using is a bug.

Sort of, but think of the problem epoll is addressing: having an epoll-registered descriptor is semantically equivalent to having an active read() on the thing. That's sort of the whole point, of course. Calling close() on a descriptor blocked in read() works fine and produces the expected (synchronous EOF) behavior. Doing it on the epoll one produces surprising behavior depending on whether or not it got dup'd somewhere (which can have been somewhere outside your process!).

It's a bug for sure. Not sure it rises to the level of "fundamentally broken", but it's a bug.


POSIX does not require EOF to be returned from a blocking read() if the same file descriptor is passed to close() in another thread. Even if it appears to work on some particular OS, consider the case where the reading thread may have called read() but is preempted just before entering the kernel. If another thread then closes the file descriptor, expecting the first thread to see EBADF or EOF, but then the file descriptor is reused (e.g. by accept()) before the first thread resumes, the reading thread may block reading from an unrelated socket. Even if you can guarantee that accept(), open(), or other calls that explicitly allocate a file descriptor will not be called, ordinary library functions are generally allowed to use file descriptors internally (e.g. to read a configuration file), so closing the file descriptor while another thread is reading from it is almost certainly a bug.


epoll and read are different calls though, expecting them to behave the same when they have very different uses is weird to me.

If it is a bug, then why does the man page call out this case, and other cases with dup and dup2 as use cases? Was the man page edited after the fact to cover up the bug? If so why not change how it works?

I really disagree calling something somebody finds surprising a bug, even more so when the man page covers the "surprising" behaviour.

Edit:

Something was bugging me so I checked it out myself. You are actually wrong. and read does work the same way epoll works. If if you dup your fd, launch a pthread that will wait a while and then close the fd, and then start your blocking read call on the fd. If the thread closes your original fd while the read is active you will not get a EOF, and you will continue to receive data from the server. Only using the FD to a system call after the fd has been closed will generate an error.

This is very much what we are seeing with epoll. We pass a fd to a system call. It is now doing its thing. We then close the fd, and are now surprised that the system call has no clue what you are talking about? The thing to remember there is a table from FD to file (or description). That table is how we talk to the kernel about files. If that table is missing a entry it won't know what file we are talking about.


> Lots of comments here seem to think this should be unexpected or is a bug. Closing a FD you are using is a bug. I think epoll does a fairly good job of letting the user know that it is watching the description and not the descriptor.

Then why is it reporting events for the file descriptor (not description) that was closed? Am I misunderstanding that?

There's nothing wrong with dup'ing an fd and closing either the original one or the second one while continuing to use the other. It's very strange that something would emit events on the fd that was closed.


You are not getting the events on the FD. You are getting the events on the file. When. You set up the event you told the kennel let me know about changes on a file -- but let use the int when we talk about this file. This actually happens at open. You setup the system to say hey when I do things on this file let's short hand it and just use this number which we will call a FD from now on.

The confusion is this king the FD is the file. It is not.

Also a FD can't be open or closed it is simply in the FD lookup table is not. Files are what are opened and closed. A FD is a designation.

Open sets up the designation close removes it. So to say you are getting events on a fd is okay, but not painting the full picture. You are getting events from the kennel about a file and the kennel thinks you know this file by it's designation.

Closing a FD does not close a file unless it is the last FD referencing that file.

Also please see my other big post. I hate typing on a phone.


Maybe I'm skimming over some important point, but it seems to me that the biggest problem here is the way the man page answers that question. I think it would be better with the first sentence deleted altogether, and much better if that sentence were actually a summary of the following explanation instead of basically contradicting it.


What's the rationale for watching the underlying file description instead of the fd?


epoll works with files at the kernel level. You have to use descriptors from the user side to tell the kernel what file you are wanting to work with. Because epoll uses the kernel objects ref count closing a fd that is NOT the last fd referencing the kernel object will not remove it from the set or trigger the close.

Lets not forget that system calls are not user libraries, but are controlled access to the kernel.


So why is Linux literally the only one who does it like that? It results in a behaviour that's surprising to the application developer and is then hard to control and get right. All I'm hearing are philosophical excuses, but nobody seems to have studied the systems that came before and can point out a concrete reason why the Linux way is better. Meanwhile everyone else is having trouble using the interface correctly.


> So why is Linux literally the only one who does it like that?

That is such a weird question. That is like asking why are you you. It's linux. That's why. This is how its system calls fd, and files work. Also you should know, epoll is just ONE of the ways ways you can get events on files, and people are mostly interested in it for the same reasons that this article hates it. Because it happens at the kernel level it is event driven, vs a polling system.

> It results in a behaviour that's surprising to the application developer and is then hard to control and get right.

It is only surprising because the user of the function did not read the man page and made assumptions on about how things work without fully understanding how they do work.

> All I'm hearing are philosophical excuses, but nobody seems to have studied the systems that came before and can point out a concrete reason why the Linux way is better.

There has not been any excuses, it's a matter of fact of how things work and how system calls work. Could things have been done differently? For sure. But even those differently done things could have been done differently.

The article and most of the post in this thread are not talking about "why Linux is way better". And I don't think anything I have said has argued either way. That being said, maybe it is not better. But it is what runs the internet and most of the top companies you frequent on the internet today -- so it can't be all that bad.

Also who is this that you expected to study? Why have you not done it? You do realize Linux is one of the most successful opens source project with thousands of developers around the world working to make it better every day? And that a lot of thought goes into adding new system calls and improving the existing systems? Even if you wanted epoll to make magic ponies for you it still could only do so with the restraints the systems it works with impose. For you to come along after 20 years and casually ask these questions is just insane.

> Meanwhile everyone else is having trouble using the interface correctly.

If you look closely lots of people who don't read man pages before using system calls find things surprising and likely use them incorrectly. Just because people refuse to understand the system they are wanting work with in full before using it -- and make assumptions how it should work without understanding the layers that live below it work -- does not make something faulty, broken, or wrong. As a systems programmer it is your responsibility to not only understand the APIs you are using, but understand what is under the hood of those APIs. If you fail to do that you are going to have a bad day. Meanwhile a awful lot of good software uses epoll and has no problems.

For all the moaning about how epoll works, or anything related to linux you guys/girls do know it is open? That if you truly think the system call interface or a particular set of system calls could be improved on then I encourage you to put your pitchforks and ranty blog post down and do something about it.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: