Subject: lib/28700: pthread_cond_timedwait() hang with "zero" absolute time
To: None <lib-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: J.T. Conklin <jtc@acorntoolworks.com>
List: netbsd-bugs
Date: 12/18/2004 06:42:00
>Number:         28700
>Category:       lib
>Synopsis:       pthread_cond_timedwait() hang with "zero" absolute time
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Dec 18 06:42:00 +0000 2004
>Originator:     J.T. Conklin
>Release:        NetBSD 2.0_RC5
>Organization:
>Environment:
	
	
System: NetBSD orac 2.0_RC5 NetBSD 2.0_RC5 (ORAC) #0: Sat Dec 11 15:17:07 PST 2004 jtc@orac:/home/jtc/netbsd/NetBSD-2.0/src/sys/arch/i386/compile/ORAC i386
Architecture: i386
Machine: i386
>Description:
The next ACE/TAO release is due out soon, so I've been making another
pass making sure it will run well on NetBSD.  This evening, I've been
investigating why the TP_Reactor_Test hangs.

I discovered that this was caused by a "zero" ACE_Time_Value being
used as a timeout in a message queue getq() call.  The intent of this
is to return a message block if one is present, otherwise to time out
immediately.  Tracking this through the ACE C++ facades, I found that
this resulted in pthread_cond_timedwait() being called with a zero
absolute timeout (tv_sec = 0, tv_nsec = 0).  Other values before "now"
correctly return ETIMEDOUT -- only "zero" fails.

The test program I've enclosed below demostrates the problem.

>How-To-Repeat:
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <time.h>

void *threadfunc(void *arg);

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;

int
main()
{
    pthread_t new;
    struct timespec ts;
    int retval;

    retval = pthread_mutex_lock(&m);
    assert (retval == 0);
    
    retval = pthread_create(&new, NULL, threadfunc, NULL);
    assert (retval == 0);

#if 0
    // set timeout one second in the future
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += 1;
#else
    // set zero timeout
    ts.tv_sec = 0;
    ts.tv_nsec = 0;
#endif

    retval = pthread_cond_timedwait(&c, &m, &ts);
    printf("%d\n", retval);

    retval = pthread_mutex_unlock(&m);
    assert (retval == 0);
    
    retval = pthread_join(new, NULL);
    assert (retval == 0);
}

void *
threadfunc(void *arg)
{
	pthread_mutex_lock(&m);

	// wait a few seconds to make sure the main thread waits on
	// the condvar.
	sleep (5);
	
	pthread_cond_signal(&c);
	
	pthread_mutex_unlock(&m);

	return NULL;
}

>Fix:
	

>Unformatted: