ag6
ag6

Reputation: 21

select() times out immediately after long runtime (C++)

Most of the time this code works just fine. But sometimes when the executable has been running for a while, select() appears to time out immediately, then get into a weird state where it keeps getting called, timing out immediately, over and over. Then it has to be killed from the outside.

My guess would be that the way that standard input changes overtime is at fault - that is what select is blocking on.

Looking around on StackOverflow, most of people's select() troubles seem to be solved by making sure to reset with the macros (FD_ZERO & FD_SET) every time and using the right initial parameter to select. I don't think those are the issues here.

int            rc     = 0;
fd_set         fdset;
struct timeval timeout;

// -- clear out the response -- //
readValue = "";

// -- set the timeout -- //
timeout.tv_sec = passedInTimeout;  // 5 seconds
timeout.tv_usec = 0;

// -- indicate which file descriptors to select from -- //
FD_ZERO(&fdset);
FD_SET(passedInFileDescriptor, &fdset); //passedInFileDescriptor = 0

// -- perform the selection operation, with timeout -- //
rc = select(1, &fdset, NULL, NULL, &timeout);


if (rc == -1)  // -- select failed -- //
{
    result = TR_ERROR;
}
else if (rc == 0)  // -- select timed out -- //
{
    result = TR_TIMEDOUT;
}
else 
{
    if (FD_ISSET(mFileDescriptor, &fdset))
    {
        if(rc = readData(readValue) <= 0)
        {
            result = TR_ERROR;
        }
    } else {
       result = TR_SUCCESS;
    }
}

Upvotes: 2

Views: 1644

Answers (4)

Gui13
Gui13

Reputation: 13541

Look at this code:

if (FD_ISSET(mFileDescriptor, &fdset))
{
    if(rc = readData(readValue) <= 0)
    {
        result = TR_ERROR;
    }
} else { 
   result = TR_SUCCESS;
}

There are two things bothering me here:

  1. if your FD has no data in it (like, say, an error occured), FD_ISSET() will return false and your function returns TR_SUCCESS !?
  2. you FD_SET(passedInFileDescriptor, &fdset), but check on another value: FD_ISSET(mFileDescriptor, &fdset). If mFileDescriptor != passedInFileDescriptor at some point, you'll fall into my first assumption.

It should be looking like this:

if (FD_ISSET(passedInFileDescriptor, &fdset))
{
    if(rc = readData(readValue) <= 0)
    {
        result = TR_ERROR;
    }
    else 
    {
        result = TR_SUCCESS;
    }
}
else
{
    result = TR_ERROR;
}

No?

(Edit: also, this answer also points the problem of your use of select() with a bad high_fd value)

Another edit: well, looks like the guys never came back... frustrating.

Upvotes: 0

Walt C.
Walt C.

Reputation: 51

I'm having the same problem, it works fine on windows but not on linux and I have the maxfd set to last socket + 1. It occurs periodically after long runs. I pick up the connection on accept and then the first call to select periodically times out.

Upvotes: 1

Jeff
Jeff

Reputation: 1857

On some OSes, timeout is modified when calling select to reflect the amount of time not slept. It doesn't look like you're reusing timeout in your example, but make sure that you are indeed reinitializing it to 5 seconds every time before calling select.

Upvotes: 1

Giuseppe Guerrini
Giuseppe Guerrini

Reputation: 4426

Beware that some implementaions of "select" apply strictly the specification: "nfds is the highest-numbered file descriptor in any of the three sets, plus 1". So, you'd better to change "1" with "passedInFileDescriptor+1" as first parameter. I don't know if this can solve your problem, but at least your code becomes more... uhm... "traditional" ;)

Bye

Upvotes: 1

Related Questions