Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select EBADF : which FD is bad?

Tags:

c

linux

We have a long standing bug in our production code. This is essentially a socket based daemon. It listens to a bunch of filedescriptors using select.

Occasionally (once a day or so), select will return with EBADF.

I have written code to search for the bad filedescriptor, that loops over each fd and calls select on it. These calls never return EBADF. I also tried fstat. They also never return EBADF.

I also rewrote the daemon to use poll. This did not help.

Does anyone have some other ideas ? (apart from i made a dumb mistake, which is all to easy to do with select).

like image 327
user109425 Avatar asked May 19 '09 14:05

user109425


People also ask

Does select System Call Block?

If timeout is a NULL pointer, the select() call blocks until a socket becomes ready. To poll the sockets and return immediately, timeout should be a non-NULL pointer to a timeval structure with a value of 0.

Does select () block?

If the timeout argument points to an object of type struct timeval whose members are 0, select() does not block. If the timeout argument is a null pointer, select() blocks until an event causes one of the masks to be returned with a valid (non-zero) value.

When select system call returns 0 What does it indicate?

If the timeout happened, the select function will return 0 forever.

How does select work in C?

select() works by blocking until something happens on a file descriptor (aka a socket). What's 'something'? Data coming in or being able to write to a file descriptor -- you tell select() what you want to be woken up by.


2 Answers

I agree with James. With poll(), you have revents per fd which can easily be checked.

I.e.

struct pollfd fds[NUM_FDS];
int ret, i;

...

ret = poll(fds, NUM_FDS, POLL_TIMEOUT);
for (i = 0; i < NUM_FDS; i++)
  if (fds[i].revents & POLLHUP || fds[i].revents & POLLNVAL)
     ... do something ...

Of course you would not implement it that way in the real world, its just an example. I stopped using select() a long time ago, poll() is a much better interface. You're correct, its just too easy to shoot yourself in the foot with select().

like image 77
Tim Post Avatar answered Sep 21 '22 07:09

Tim Post


Most likely the select is called on a closed file descriptor. The usual source of that is reusing the fd_set without re-initializing it. Do you have anything going on in the signal handlers? (like re-opening a log file on a HUP?)

like image 34
Nikolai Fetissov Avatar answered Sep 18 '22 07:09

Nikolai Fetissov