bug-hurd
[Top][All Lists]
Advanced

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

Re: Implementation of condition_timedwait() in libthreads


From: Richard Braun
Subject: Re: Implementation of condition_timedwait() in libthreads
Date: Sun, 16 Apr 2006 21:12:52 +0200
User-agent: Mutt/1.5.9i

On Sun, Apr 16, 2006 at 12:50:47AM +0200, Richard Braun wrote:
> 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 :

The patch I sent in my first message has been incorrectly generated.
Here is the complete patch (with a small improvement in the
condition_timedwait() function itself) :


2006-04-16 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 libthreads.orig/cancel-cond.c libthreads/cancel-cond.c
--- libthreads.orig/cancel-cond.c       2006-04-16 16:32:53.000000000 +0000
+++ libthreads/cancel-cond.c    2006-04-16 16:50:01.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 libthreads.orig/cprocs.c libthreads/cprocs.c
--- libthreads.orig/cprocs.c    2006-04-16 16:32:53.000000000 +0000
+++ libthreads/cprocs.c 2006-04-16 16:53:30.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,44 @@ 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;
+       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 +837,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 +855,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 +1009,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 +1166,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-16 16:32:53.000000000 +0000
+++ libthreads/cthread_internals.h      2006-04-16 16:49:24.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-16 16:32:53.000000000 +0000
+++ libthreads/cthreads.h       2006-04-16 16:49:24.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]