2006-09-10 Richard Braun <syn@hurdfr.org>

	* libthreads/cancel-cond.c: call to cproc_block() updated.
	* libthreads/cprocs.c: Implemented condition_timedwait(), modified
	cproc_block() to use a timeout.
	* libthreads/cthread_internals.h: Added CPROC_TIMEDOUT macro.
	* libthreads/cthreads.h: added the prototype for
	condition_timedwait().

diff -Nurp hurd.orig/libthreads/cancel-cond.c hurd/libthreads/cancel-cond.c
--- hurd.orig/libthreads/cancel-cond.c	2006-08-25 14:37:50.000000000 +0000
+++ hurd/libthreads/cancel-cond.c	2006-09-10 09:59:56.000000000 +0000
@@ -83,7 +83,7 @@ hurd_condition_wait (condition_t c, mute
 
       spin_lock (&p->lock);
       if (p->state & CPROC_SWITCHING)
-	cproc_block ();
+	cproc_block (MACH_MSG_TIMEOUT_NONE);
       else
 	{
 	  /* We were woken up someplace before reacquiring P->lock.
diff -Nurp hurd.orig/libthreads/cprocs.c hurd/libthreads/cprocs.c
--- hurd.orig/libthreads/cprocs.c	2006-08-25 14:37:50.000000000 +0000
+++ hurd/libthreads/cprocs.c	2006-09-10 10:05:17.000000000 +0000
@@ -239,6 +239,9 @@
 #include <mach/message.h>
 #include <hurd/threadvar.h>	/* GNU */
 #include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
 
 /*
  * Port_entry's are used by cthread_mach_msg to store information
@@ -629,7 +632,7 @@ cproc_waiter(void)
  */
 
 void
-cproc_block(void)
+cproc_block(mach_msg_timeout_t timeout)
 {
   extern unsigned int __hurd_threadvar_max; /* GNU */
 	register cproc_t waiter, new, p = cproc_self();
@@ -640,9 +643,22 @@ cproc_block(void)
 		kern_return_t r;
 
 		spin_unlock(&p->lock);
-		MACH_CALL(mach_msg(&msg, MACH_RCV_MSG,
-				   0, sizeof msg, p->wired,
-				   MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL), r);
+
+		if (timeout == MACH_MSG_TIMEOUT_NONE)
+			MACH_CALL(mach_msg(&msg, MACH_RCV_MSG,
+					   0, sizeof msg, p->wired,
+					   MACH_MSG_TIMEOUT_NONE,
+					   MACH_PORT_NULL), r);
+
+		else {
+			MACH_CALL(mach_msg(&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
+					   0, sizeof msg, p->wired,
+					   timeout,  MACH_PORT_NULL), r);
+
+			if (r == EMACH_RCV_TIMED_OUT)
+				p->state |= CPROC_TIMEDOUT;
+		}
+
 		return;
 	}
 	p->state = CPROC_SWITCHING;
@@ -769,7 +785,47 @@ cproc_create(void)
 void
 condition_wait(condition_t c, mutex_t m)
 {
+	int timedout;
+
+	timedout = condition_timedwait(c, m, NULL);
+	assert(timedout == FALSE);
+}
+
+int
+condition_timedwait(condition_t c, mutex_t m, const struct timespec *t)
+{
 	register cproc_t p = cproc_self();
+	mach_msg_timeout_t timeout;
+	boolean_t timedout;
+
+	if (t == NULL) {
+		timeout = MACH_MSG_TIMEOUT_NONE;
+		timedout = FALSE;
+	} else {
+		struct timeval now;
+		error_t err;
+
+		/*
+		 * Taken from libpthread (sysdeps/mach/pt-timedblock.c).
+		 */
+		err = gettimeofday(&now, NULL);
+		assert(!err);
+
+		if (now.tv_sec > t->tv_sec
+		    || (now.tv_sec == t->tv_sec
+			&& now.tv_usec > ((t->tv_nsec + 999) / 1000)))
+			return TRUE;
+
+		timeout = (t->tv_sec - now.tv_sec) * 1000;
+
+		if (((t->tv_nsec + 999) / 1000) >= now.tv_usec)
+			timeout -= (((t->tv_nsec + 999) / 1000)
+				   - now.tv_usec + 999) / 1000;
+
+		else
+			timeout -= 1000 + ((t->tv_nsec + 999999) / 1000000)
+				   - (now.tv_usec + 999) / 1000;
+	}
 
 	p->state = CPROC_CONDWAIT | CPROC_SWITCHING;
 
@@ -784,13 +840,16 @@ condition_wait(condition_t c, mutex_t m)
 
 	spin_lock(&p->lock);
 	if (p->state & CPROC_SWITCHING) {
-		cproc_block();
+		cproc_block(timeout);
+		timedout = (p->state & CPROC_TIMEDOUT) ? TRUE : FALSE;
+
+		if (timedout)
+			p->state &= ~CPROC_TIMEDOUT;
 	} else {
 		p->state = CPROC_RUNNING;
 		spin_unlock(&p->lock);
 	}
 
-
 #ifdef	WAIT_DEBUG
 	p->waiting_for = (char *)0;
 #endif	 /* WAIT_DEBUG */
@@ -799,6 +858,8 @@ condition_wait(condition_t c, mutex_t m)
 	 * Re-acquire the mutex and return.
 	 */
 	mutex_lock(m);
+
+	return timedout;
 }
 
 /* Declare that IMPLICATOR should consider IMPLICATAND's waiter queue
@@ -951,7 +1012,7 @@ __mutex_lock_solid(void *ptr)
 			if (!queued) cthread_queue_enq(&m->queue, p);
 			spin_lock(&p->lock);
 			spin_unlock(&m->lock);
-			cproc_block();
+			cproc_block(MACH_MSG_TIMEOUT_NONE);
 			if (spin_try_lock(&m->held)) {
 #ifdef	WAIT_DEBUG
 			    p->waiting_for = (char *)0;
@@ -1108,7 +1169,7 @@ cthread_mach_msg(register mach_msg_heade
 #ifdef	WAIT_DEBUG
 		    p->waiting_for = (char *)port_entry;
 #endif	 /* WAIT_DEBUG */
-		    cproc_block();
+		    cproc_block(MACH_MSG_TIMEOUT_NONE);
 		} else {
 		    port_entry->held++;
 		    spin_unlock(&port_entry->lock);
diff -Nurp hurd.orig/libthreads/cthread_internals.h hurd/libthreads/cthread_internals.h
--- hurd.orig/libthreads/cthread_internals.h	2006-08-25 14:37:50.000000000 +0000
+++ hurd/libthreads/cthread_internals.h	2006-09-10 09:59:56.000000000 +0000
@@ -186,6 +186,7 @@ typedef struct cproc {
 #define CPROC_SWITCHING 1
 #define CPROC_BLOCKED	2
 #define CPROC_CONDWAIT	4
+#define CPROC_TIMEDOUT	8
 
 	mach_port_t wired;		/* is cthread wired to kernel thread */
 	void *busy;			/* used with cthread_msg calls */
diff -Nurp hurd.orig/libthreads/cthreads.h hurd/libthreads/cthreads.h
--- hurd.orig/libthreads/cthreads.h	2006-08-25 14:37:50.000000000 +0000
+++ hurd/libthreads/cthreads.h	2006-09-10 09:59:56.000000000 +0000
@@ -497,6 +497,12 @@ extern void	cond_broadcast(condition_t _
 extern void	condition_wait(condition_t _cond, mutex_t _mutex);
 extern int	hurd_condition_wait(condition_t _cond, mutex_t _mutex);
 
+/*
+ * Return TRUE if no signal was received before timeout.
+ */
+extern int	condition_timedwait(condition_t _cond, mutex_t _mutex,
+				    const struct timespec *_abstime);
+
 extern void	condition_implies(condition_t _implicator,
 				  condition_t _implicatand);
 extern void	condition_unimplies(condition_t _implicator,
