bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Implementation of condition_timedwait() in libthreads


From: Richard Braun
Subject: Implementation of condition_timedwait() in libthreads
Date: Sun, 16 Apr 2006 00:50:47 +0200
User-agent: Mutt/1.5.9i

Hello,

During my work on the BPF translator, I was told translators shouldn't
use pthreads for now. So I switched to cthreads and noticed there was
no condition_timedwait() function. Here is a patch that adds this
function to the Hurd. I wasn't brave enough to write
hurd_condition_timedwait() - a cancellable version of condition_timedwait().

Basically, condition_timedwait() is at the same time like condition_wait()
and pthread_cond_timedwait(). A third parameter of type struct timespec *
was added. If that parameter is NULL, condition_timedwait() acts the same
as condition_wait(). That function could be implemented as a macro, but
I let it in place so that the global symbol still exists (otherwise, I
guess many applications would break).

condition_timedwait() returns TRUE if a timeout occurred, FALSE otherwise.
Here is the patch :



2006-04-15 Richard Braun <syn@hurdfr.org>

        * 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 libthreads.orig/cprocs.c libthreads/cprocs.c
--- libthreads.orig/cprocs.c    2006-04-15 20:23:45.000000000 +0000
+++ libthreads/cprocs.c 2006-04-15 20:36:43.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,42 @@ cproc_create(void)
 void
 condition_wait(condition_t c, mutex_t m)
 {
+       condition_timedwait(c, m, NULL);
+}
+
+int
+condition_timedwait(condition_t c, mutex_t m, const struct timespec *t)
+{
        register cproc_t p = cproc_self();
+       mach_msg_timeout_t timeout;
+
+       if (t == NULL)
+               timeout = MACH_MSG_TIMEOUT_NONE;
+       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 +835,12 @@ condition_wait(condition_t c, mutex_t m)
 
        spin_lock(&p->lock);
        if (p->state & CPROC_SWITCHING) {
-               cproc_block();
+               cproc_block(timeout);
        } else {
                p->state = CPROC_RUNNING;
                spin_unlock(&p->lock);
        }
 
-
 #ifdef WAIT_DEBUG
        p->waiting_for = (char *)0;
 #endif  /* WAIT_DEBUG */
@@ -799,6 +849,8 @@ condition_wait(condition_t c, mutex_t m)
         * Re-acquire the mutex and return.
         */
        mutex_lock(m);
+
+       return (p->state & CPROC_TIMEDOUT) ? TRUE : FALSE;
 }
 
 /* Declare that IMPLICATOR should consider IMPLICATAND's waiter queue
@@ -951,7 +1003,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 +1160,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 libthreads.orig/cthread_internals.h libthreads/cthread_internals.h
--- libthreads.orig/cthread_internals.h 2006-04-15 20:23:45.000000000 +0000
+++ libthreads/cthread_internals.h      2006-04-15 20:38:01.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 libthreads.orig/cthreads.h libthreads/cthreads.h
--- libthreads.orig/cthreads.h  2006-04-15 20:23:45.000000000 +0000
+++ libthreads/cthreads.h       2006-04-15 20:39:43.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,

-- 
Richard Braun

Attachment: signature.asc
Description: Digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]