Subject: lib/25961: pthread_cond_timedwait() before creating other threads
To: None <gnats-bugs@gnats.NetBSD.org>
From: J.T. Conklin <jtc@acorntoolworks.com>
List: netbsd-bugs
Date: 06/18/2004 04:23:44
>Number:         25961
>Category:       lib
>Synopsis:       pthread_cond_timedwait() before creating other threads
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 18 04:25:01 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     J.T. Conklin
>Release:        NetBSD 2.0_BETA
>Organization:
J.T. Conklin
>Environment:
	
	
System: NetBSD orac 2.0_BETA NetBSD 2.0_BETA (GENERIC.MP) #0: Fri May 7 20:39:51 PDT 2004 jtc@orac:/home/jtc/netbsd/NetBSD-2.0/obj/sys/arch/i386/compile/GENERIC.MP i386
Architecture: i386
Machine: i386
>Description:

"Message_Queue_Test" from the ACE (ADAPTIVE Communication Environment)
regression test suite fails because pthread_cond_timedwait() is called
before additional threads have been created.

pthread_cond_timedwait() is called with a timespec representing "now",
the current time, as a timeout.  This timespec represents the absolute
timeout, and is converted to a timeval representing a relative timeout
in pthread_cond_wait_nothread().  

If the absolute timeout has already been reached, this can result in a
negative value that is passed to select().  This causes select to fail
returning -1, which causes pthread_cond_wait_nothread to return 0
instead of ETIMEDOUT.

>How-To-Repeat:

This program demonstrates the problem.  pthread_cond_timedwait()
returns different values depending on whether the pthread_create line
is enabled/commented out.

#include <pthread.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

pthread_mutex_t m;
pthread_cond_t c;
pthread_t t;

void *
thr(void *arg)
{
    sleep(5);
}

main()
{
    struct timeval tv;
    struct timespec ts;
    int err;

    gettimeofday(&tv, 0);
    TIMEVAL_TO_TIMESPEC(&tv, &ts);
    sleep(1); // ensure absolute timeout is in the "past"

#if 0
    pthread_create(&t, 0, thr, 0);
#endif

    pthread_mutex_init(&m, 0);
    pthread_cond_init(&c, 0);

    pthread_mutex_lock(&m);
    err = pthread_cond_timedwait(&c, &m, &ts);
    printf("%d: %s\n", err, strerror(err));
    pthread_mutex_unlock(&m);

    exit (0);
}


>Fix:
If the absolute timeout is in the past, clear the timeval that is
passed to select().

Index: pthread_cond.c
===================================================================
RCS file: /cvsroot/src/lib/libpthread/pthread_cond.c,v
retrieving revision 1.14.2.1
diff -c -r1.14.2.1 pthread_cond.c
*** pthread_cond.c	6 May 2004 05:34:18 -0000	1.14.2.1
--- pthread_cond.c	18 Jun 2004 03:54:05 -0000
***************
*** 374,380 ****
  		tvp = &tv;
  		gettimeofday(&now, NULL);
  		TIMESPEC_TO_TIMEVAL(tvp, abstime);
! 		timersub(tvp, &now, tvp);
  	}
  
  	/*
--- 374,385 ----
  		tvp = &tv;
  		gettimeofday(&now, NULL);
  		TIMESPEC_TO_TIMEVAL(tvp, abstime);
! 
! 		if  (timercmp(tvp, &now, <)) { 
! 			timerclear(tvp);
! 		} else {
! 			timersub(tvp, &now, tvp);
! 		}
  	}
  
  	/*

>Release-Note:
>Audit-Trail:
>Unformatted: