Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pthread_cond_timedwait returning immediately

I'm having a strange problem. I have the following code:

    dbg("condwait: timeout = %d, %d\n", 
        abs_timeout->tv_sec, abs_timeout->tv_nsec);
    ret = pthread_cond_timedwait( &q->q_cond, &q->q_mtx, abs_timeout );
    if (ret == ETIMEDOUT)
    {
      dbg("cond timed out\n");
      return -ETIMEDOUT;
    }

dbg calls gettimeofday before every line and prepends the line with the time. It results in the following output:

    7.991151: condwait: timeout = 5, 705032704
    7.991158: cond timed out

As you can see, only 7 microseconds passed in between the two debug lines, yet pthread_cond_timedwait returned ETIMEDOUT. How can this happen? I even tried setting the clock to something else when initializing the cond variable:

int ret;
ret = pthread_condattr_init(&attributes);
if (ret != 0) printf("CONDATTR INIT FAILED: %d\n", ret);
ret = pthread_condattr_setclock(&attributes, CLOCK_REALTIME);
if (ret != 0) printf("SETCLOCK FAILED: %d\n", ret);
ret = pthread_cond_init( &q->q_cond, &attributes );
if (ret != 0) printf("COND INIT FAILED: %d\n", ret);

(none of the error messages are printed out). I tried both CLOCK_REALTIME and CLOCK_MONOTONIC.

This code is part of a blocking queue. I need functionality such that if nothing gets put on this queue in 5 seconds, something else happens. The mutex and the cond are both initialized, as the blocking queue works fine if I don't use pthread_cond_timedwait.

like image 743
Claudiu Avatar asked Mar 19 '09 03:03

Claudiu


2 Answers

pthread_cond_timedwait takes an absolute time, not a relative time. You need to make your wait time absolute by adding to the current time to your timeout value.

like image 76
Aaron Saarela Avatar answered Oct 18 '22 16:10

Aaron Saarela


Overflow in timespec is usually the culprit for weird timeouts.
Check for EINVAL:

void timespec_add(struct timespec* a, struct timespec* b, struct timespec* out)
{
    time_t sec = a->tv_sec + b->tv_sec;
    long nsec = a->tv_nsec + b->tv_nsec;

    sec += nsec / 1000000000L;
    nsec = nsec % 1000000000L;

    out->tv_sec = sec;
    out->tv_nsec = nsec;
}
like image 41
Bejesus Avatar answered Oct 18 '22 15:10

Bejesus