I am having problem with select() call on an multi-socket app.
Here is how it is supposed to work.
Writer writes: [0010]HelloWorld
on a socket, where the the first 4 character are always digits representing the payload size.
Reader should do the following:
- call
select()
to verify if a given socket is readable, thenread
first 4 character, change char to digit to get size of buffer in number, and allocate a buffer of that size. - copy characters (after the first 4 characters) from the socket and paste to the buffer for further processing
read
4 characters again, which should fail and upon failure to read any data, the app should clean exit the program.
Problem is in the 3rd select
call. select
followed by read
iteration, every time we check select()
for readability of socket and once that is verified, we proceed with the read
. While the socket is valid and almost whole process works just fine, except for last point at step 3 before read
is expected to fail, I call select()
system call for last time, and it completely freezes the thread upon calling select
.
I am not finding any sources online which can explain this weird phenomenon. To verify that the thread is not returning I have created a dummy object just before making the system call select()
and logged it on destruction. Unformtunately, the distructor is never getting called.
Source code is propriotery, cannot be shared.
snippet:
fd_set f_set;
int err = 0;
while(check_edge_case())
{
if(time_out_valid())
{
int nfds = GetFileDescriptor();
FD_ZERO(&f_set);
FD_SET(nfds, &f_set);
for_each (clients, [&](client_t &client)
{
int fd = client.descriptor;
if(fd)
{
FD_SET(fd, &f_set);
nfds = std::max(nfds, fd);
}
});
++nfds;
// perform select
if(time_out_valid())
{
struct timeval_t time_val = GetTimeOut();
err = select(nfds, &f_set, 0,0, &time_val);
}
else
{
err = select(nfds, &f_set, 0, 0, 0); // blocks in this statement
}
// check for error
if(!err)
{
err = 0;
continue;
}
else if (err = -1 && errno == EINTR)
{
err = 0;
continue;
}
else if (err < 0)
{
retunr errno;
}
if(FD_ISSET(GetFileDescriptor(), &f_set))
{
return ECANCELED;
}
// further processing for read operation
bool executed = false;
for_each (clients, [&](client_t &client)
{
int fd = client.descriptor;
if(FD_ISSET(fd, &f_set))
{
if(client.f_read) err = client.f_read();
else err = 0;
executed = true;
break;
}
});
if(!found) return ENODATA;
}
}