]> git.sesse.net Git - vlc/blobdiff - src/win32/thread.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / win32 / thread.c
index f231e496f8415e990c9b29e34fc272c16818f482..1d25b90320dcbb061e7f5e3d37aad0a93e8a2283 100644 (file)
@@ -191,6 +191,7 @@ void vlc_mutex_lock (vlc_mutex_t *p_mutex)
 {
     if (!p_mutex->dynamic)
     {   /* static mutexes */
+        int canc = vlc_savecancel ();
         assert (p_mutex != &super_mutex); /* this one cannot be static */
 
         vlc_mutex_lock (&super_mutex);
@@ -202,6 +203,7 @@ void vlc_mutex_lock (vlc_mutex_t *p_mutex)
         }
         p_mutex->locked = true;
         vlc_mutex_unlock (&super_mutex);
+        vlc_restorecancel (canc);
         return;
     }
 
@@ -247,17 +249,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 +286,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 +303,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 +323,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;
 }
@@ -474,6 +505,7 @@ struct vlc_entry_data
 {
     void * (*func) (void *);
     void *  data;
+    vlc_sem_t ready;
 #ifdef UNDER_CE
     HANDLE  cancel_event;
 #endif
@@ -481,18 +513,17 @@ struct vlc_entry_data
 
 static unsigned __stdcall vlc_entry (void *p)
 {
+    struct vlc_entry_data *entry = p;
     vlc_cancel_t cancel_data = VLC_CANCEL_INIT;
-    struct vlc_entry_data data;
-
-    memcpy (&data, p, sizeof (data));
-    free (p);
+    void *(*func) (void *) = entry->func;
+    void *data = entry->data;
 
 #ifdef UNDER_CE
-    cancel_data.cancel_event = data.cancel_event;
+    cancel_data.cancel_event = entry->cancel_event;
 #endif
-
     vlc_threadvar_set (cancel_key, &cancel_data);
-    data.func (data.data);
+    vlc_sem_post (&entry->ready);
+    func (data);
     return 0;
 }
 
@@ -507,6 +538,7 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
         return ENOMEM;
     entry_data->func = entry;
     entry_data->data = data;
+    vlc_sem_init (&entry_data->ready, 0);
 
 #ifndef UNDER_CE
     /* When using the MSVCRT C library you have to use the _beginthreadex
@@ -521,15 +553,7 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
         goto error;
     }
 
-    /* Thread closes the handle when exiting, duplicate it here
-     * to be on the safe side when joining. */
-    if (!DuplicateHandle (GetCurrentProcess (), hThread,
-                          GetCurrentProcess (), p_handle, 0, FALSE,
-                          DUPLICATE_SAME_ACCESS))
-    {
-        CloseHandle (hThread);
-        goto error;
-    }
+    *p_handle = hThread;
 
 #else
     vlc_thread_t th = malloc (sizeof (*th));
@@ -563,9 +587,17 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
     if (priority)
         SetThreadPriority (hThread, priority);
 
+    /* Prevent cancellation until cancel_data is initialized. */
+    /* XXX: This could be postponed to vlc_cancel() or avoided completely by
+     * passing the "right" pointer to vlc_cancel_self(). */
+    vlc_sem_wait (&entry_data->ready);
+    vlc_sem_destroy (&entry_data->ready);
+    free (entry_data);
+
     return 0;
 
 error:
+    vlc_sem_destroy (&entry_data->ready);
     free (entry_data);
     return err;
 }
@@ -605,8 +637,12 @@ void vlc_detach (vlc_thread_t handle)
 /* APC procedure for thread cancellation */
 static void CALLBACK vlc_cancel_self (ULONG_PTR dummy)
 {
+    vlc_cancel_t *nfo = vlc_threadvar_get (cancel_key);
+
+    if (likely(nfo != NULL))
+        nfo->killed = true;
+
     (void)dummy;
-    vlc_control_cancel (VLC_DO_CANCEL);
 }
 
 void vlc_cancel (vlc_thread_t thread_id)
@@ -654,7 +690,7 @@ void vlc_testcancel (void)
         for (vlc_cleanup_t *p = nfo->cleaners; p != NULL; p = p->next)
              p->proc (p->data);
 #ifndef UNDER_CE
-        _endthread ();
+        _endthreadex(0);
 #else
         ExitThread(0);
 #endif
@@ -674,10 +710,6 @@ void vlc_control_cancel (int cmd, ...)
     va_start (ap, cmd);
     switch (cmd)
     {
-        case VLC_DO_CANCEL:
-            nfo->killed = true;
-            break;
-
         case VLC_CLEANUP_PUSH:
         {
             /* cleaner is a pointer to the caller stack, no need to allocate