vlc_cond_init_daytime: condition variable with the wall clock
authorRémi Denis-Courmont <remi@remlab.net>
Mon, 8 Feb 2010 16:46:02 +0000 (18:46 +0200)
committerRémi Denis-Courmont <remi@remlab.net>
Mon, 8 Feb 2010 16:46:31 +0000 (18:46 +0200)
include/vlc_threads.h
src/libvlccore.sym
src/misc/pthread.c
src/win32/thread.c

index c303420..8bff238 100644 (file)
@@ -134,7 +134,12 @@ typedef struct
 } vlc_mutex_t;
 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
 
-typedef HANDLE  vlc_cond_t;
+typedef struct
+{
+    HANDLE   handle;
+    unsigned clock;
+} vlc_cond_t;
+
 typedef HANDLE  vlc_sem_t;
 
 typedef struct
@@ -165,6 +170,7 @@ VLC_EXPORT( void, vlc_mutex_lock, ( vlc_mutex_t * ) );
 VLC_EXPORT( int,  vlc_mutex_trylock, ( vlc_mutex_t * ) LIBVLC_USED );
 VLC_EXPORT( void, vlc_mutex_unlock, ( vlc_mutex_t * ) );
 VLC_EXPORT( void, vlc_cond_init,     ( vlc_cond_t * ) );
+VLC_EXPORT( void, vlc_cond_init_daytime, ( vlc_cond_t * ) );
 VLC_EXPORT( void, vlc_cond_destroy,  ( vlc_cond_t * ) );
 VLC_EXPORT( void, vlc_cond_signal, (vlc_cond_t *) );
 VLC_EXPORT( void, vlc_cond_broadcast, (vlc_cond_t *) );
index d608ab3..e0c53b3 100644 (file)
@@ -476,6 +476,7 @@ VLC_Compiler
 vlc_cond_broadcast
 vlc_cond_destroy
 vlc_cond_init
+vlc_cond_init_daytime
 vlc_cond_signal
 vlc_cond_timedwait
 vlc_cond_wait
index 4522db0..ca422cf 100644 (file)
@@ -256,10 +256,10 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
     VLC_THREAD_ASSERT ("unlocking mutex");
 }
 
-/*****************************************************************************
- * vlc_cond_init: initialize a condition variable
- *****************************************************************************/
-void vlc_cond_init( vlc_cond_t *p_condvar )
+/**
+ * Initializes a condition variable.
+ */
+void vlc_cond_init (vlc_cond_t *p_condvar)
 {
     pthread_condattr_t attr;
 
@@ -280,6 +280,17 @@ void vlc_cond_init( vlc_cond_t *p_condvar )
 }
 
 /**
+ * Initializes a condition variable.
+ * Contrary to vlc_cond_init(), the wall clock will be used as a reference for
+ * the vlc_cond_timedwait() time-out parameter.
+ */
+void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
+{
+    if (unlikely(pthread_cond_init (p_condvar, NULL)))
+        abort ();
+}
+
+/**
  * Destroys a condition variable. No threads shall be waiting or signaling the
  * condition.
  * @param p_condvar condition variable to destroy
@@ -351,7 +362,11 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
 
 /**
  * Waits for a condition variable up to a certain date.
- * This works like vlc_cond_wait(), except for the additional timeout.
+ * This works like vlc_cond_wait(), except for the additional time-out.
+ *
+ * If the variable was initialized with vlc_cond_init(), the timeout has the
+ * same arbitrary origin as mdate(). If the variable was initialized with
+ * vlc_cond_init_daytime(), the timeout is expressed from the Unix epoch.
  *
  * @param p_condvar condition variable to wait on
  * @param p_mutex mutex which is unlocked while waiting,
index f231e49..08de712 100644 (file)
@@ -247,17 +247,34 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
 }
 
 /*** Condition variables ***/
-void vlc_cond_init( vlc_cond_t *p_condvar )
+enum
+{
+    CLOCK_MONOTONIC,
+    CLOCK_REALTIME,
+};
+
+static void vlc_cond_init_common (vlc_cond_t *p_condvar, unsigned clock)
 {
     /* Create a manual-reset event (manual reset is needed for broadcast). */
-    *p_condvar = CreateEvent (NULL, TRUE, FALSE, NULL);
-    if (!*p_condvar)
+    p_condvar->handle = CreateEvent (NULL, TRUE, FALSE, NULL);
+    if (!p_condvar->handle)
         abort();
+    p_condvar->clock = clock;
+}
+
+void vlc_cond_init (vlc_cond_t *p_condvar)
+{
+    vlc_cond_init_common (p_condvar, CLOCK_MONOTONIC);
+}
+
+void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
+{
+    vlc_cond_init_common (p_condvar, CLOCK_REALTIME);
 }
 
 void vlc_cond_destroy (vlc_cond_t *p_condvar)
 {
-    CloseHandle (*p_condvar);
+    CloseHandle (p_condvar->handle);
 }
 
 void vlc_cond_signal (vlc_cond_t *p_condvar)
@@ -267,12 +284,12 @@ void vlc_cond_signal (vlc_cond_t *p_condvar)
      * waiting, which is also wrong. However both of these issues are allowed
      * by the provision for spurious wakeups. Better have too many wakeups
      * than too few (= deadlocks). */
-    SetEvent (*p_condvar);
+    SetEvent (p_condvar->handle);
 }
 
 void vlc_cond_broadcast (vlc_cond_t *p_condvar)
 {
-    SetEvent (*p_condvar);
+    SetEvent (p_condvar->handle);
 }
 
 void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
@@ -284,14 +301,14 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
     {
         vlc_testcancel ();
         LeaveCriticalSection (&p_mutex->mutex);
-        result = WaitForSingleObjectEx (*p_condvar, INFINITE, TRUE);
+        result = WaitForSingleObjectEx (p_condvar->handle, INFINITE, TRUE);
         EnterCriticalSection (&p_mutex->mutex);
     }
     while (result == WAIT_IO_COMPLETION);
 
     assert (result != WAIT_ABANDONED); /* another thread failed to cleanup! */
     assert (result != WAIT_FAILED);
-    ResetEvent (*p_condvar);
+    ResetEvent (p_condvar->handle);
 }
 
 int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
@@ -304,20 +321,32 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
     {
         vlc_testcancel ();
 
-        mtime_t total = (deadline - mdate ())/1000;
+        mtime_t total;
+        switch (p_condvar->clock)
+        {
+            case CLOCK_MONOTONIC:
+                total = mdate();
+                break;
+            case CLOCK_REALTIME: /* FIXME? sub-second precision */
+                total = CLOCK_FREQ * time (NULL);
+                break;
+            default:
+                assert (0);
+        }
+        total = (deadline - total) / 1000;
         if( total < 0 )
             total = 0;
 
         DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
         LeaveCriticalSection (&p_mutex->mutex);
-        result = WaitForSingleObjectEx (*p_condvar, delay, TRUE);
+        result = WaitForSingleObjectEx (p_condvar->handle, delay, TRUE);
         EnterCriticalSection (&p_mutex->mutex);
     }
     while (result == WAIT_IO_COMPLETION);
 
     assert (result != WAIT_ABANDONED);
     assert (result != WAIT_FAILED);
-    ResetEvent (*p_condvar);
+    ResetEvent (p_condvar->handle);
 
     return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
 }