0

A service-side UDP socket was created without the O_NONBLOCK flag, then in a while loop, the select() call returns (no error) and the socket fd is tested true from FD_ISSET. However, subsequently when I read from the socket using recvmsg(), the call blocks.

The simplified code is as follows:

int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sock;
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = <some IP>;
sock.sin_port = htons(<some port number>);
int rc = bind(fd, (struct sockaddr *)&sock, sizeof(sock));
// no error

while (1) {
   fd_set rset; // read
   FD_ZERO(&rset);
   FD_SET(fd, rset);
   rc = select(fd + 1, &rset, NULL, NULL, NULL); // no timeout
   if (rc <= 0) {
       // handles error or zero fd
       continue;
   }

   if (FD_ISSET(fd, rset)) {
       struct msghdr msg;
       // set up msg ...
       ret = recvmsg(fd, &msg, 0); // <------- blocks here
       // check ret
   }
}

What are some of the conditions that the UDP socket is readable but reading it would block?

जलजनक
  • 3,072
  • 2
  • 24
  • 30
  • The only way I know of for `recvmsg()` to block after `select()` reports the socket is readable is if another thread reads from the socket before `recvfrom()` is called. Are you using the `fd` descriptor across multiple threads? In any case, what is the point of calling `select()` with no timeout just to detect when to call `recvmsg()` without blocking? You are not doing anything else in between, and are going to block the calling thread either way until the socket is readable, so you may as well just get rid of `select()` altogether and let `recvmsg()` block normally. – Remy Lebeau Apr 04 '22 at 20:04
  • 1
    Likely related: https://stackoverflow.com/questions/858282/spurious-readiness-notification-for-select-system-call – Jeremy Friesner Apr 05 '22 at 05:43
  • @RemyLebeau Thanks for your comment. The particular UDP fd shouldn't be subject to any race condition. It is created & managed by a single thread and by a rather small block of code. This is an existing code base & I omitted some details in the original post. The select() call was guarding multiple fds, one of them is a timer fd created from timerfd_create(). – cs3cl4type Apr 05 '22 at 21:51
  • @JeremyFriesner Thanks for the reference. Ah, it's right in the man page! – cs3cl4type Apr 05 '22 at 21:54

0 Answers0