shithub: openh264

Download patch

ref: d0a81355b0b2677f38c49d1b55adce584f3f5449
parent: de32455d87be611cdfaad08cb0f8c72c22501729
author: Martin Storsjö <[email protected]>
date: Mon Mar 3 11:33:22 EST 2014

Add support for using a separate "master event" in WelsMultipleEventsWait*Blocking

This allows making the WelsMultipleEventsWaitSingleBlocking
function work properly in unix, without polling. If a master
event is provided, the function first waits for a signal on
that event - once such a signal is received, it is assumed that
one of the individual events in the list have been signalled as
well. Then the function can proceed to check each of the semaphores
in the list using sem_trywait to find the first one of them that
has been signalled. Assuming that the master event is signalled
in pair with the other events, one of the sem_trywait calls
should succeed.

The same master event is also used in
WelsMultipleEventsWaitAllBlocking, to keep the semaphore values
in sync across calls to the both functions.

--- a/codec/common/WelsThreadLib.cpp
+++ b/codec/common/WelsThreadLib.cpp
@@ -118,11 +118,14 @@
 }
 
 WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitSingleBlocking (uint32_t nCount,
-    WELS_EVENT* event_list) {
+    WELS_EVENT* event_list, WELS_EVENT* master_event) {
+  // Don't need/use the master event for anything, since windows has got WaitForMultipleObjects
   return WaitForMultipleObjects (nCount, event_list, FALSE, INFINITE);
 }
 
-WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitAllBlocking (uint32_t nCount, WELS_EVENT* event_list) {
+WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitAllBlocking (uint32_t nCount,
+    WELS_EVENT* event_list, WELS_EVENT* master_event) {
+  // Don't need/use the master event for anything, since windows has got WaitForMultipleObjects
   return WaitForMultipleObjects (nCount, event_list, TRUE, INFINITE);
 }
 
@@ -338,13 +341,25 @@
 }
 
 WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitSingleBlocking (uint32_t nCount,
-    WELS_EVENT* event_list) {
+    WELS_EVENT* event_list, WELS_EVENT* master_event) {
   uint32_t nIdx = 0;
-  const uint32_t kuiAccessTime = 2;	// 2 us once
+  uint32_t uiAccessTime = 2;	// 2 us once
 
   if (nCount == 0)
     return WELS_THREAD_ERROR_WAIT_FAILED;
 
+  if (master_event != NULL) {
+    // This design relies on the events actually being semaphores;
+    // if multiple events in the list have been signalled, the master
+    // event should have a similar count (events in windows can't keep
+    // track of the actual count, but the master event isn't needed there
+    // since it uses WaitForMultipleObjects).
+    int32_t err = sem_wait (*master_event);
+    if (err != WELS_THREAD_ERROR_OK)
+      return err;
+    uiAccessTime = 0; // no blocking, just quickly loop through all to find the one that was signalled
+  }
+
   while (1) {
     nIdx = 0;	// access each event by order
     while (nIdx < nCount) {
@@ -359,9 +374,9 @@
         err = sem_trywait (event_list[nIdx]);
         if (WELS_THREAD_ERROR_OK == err)
           return WELS_THREAD_ERROR_WAIT_OBJECT_0 + nIdx;
-        else if (wait_count > 0)
+        else if (wait_count > 0 || uiAccessTime == 0)
           break;
-        usleep (kuiAccessTime);
+        usleep (uiAccessTime);
         ++ wait_count;
       } while (1);
       // we do need access next event next time
@@ -368,12 +383,21 @@
       ++ nIdx;
     }
     usleep (1);	// switch to working threads
+    if (master_event != NULL) {
+      // A master event was used and was signalled, but none of the events in the
+      // list was found to be signalled, thus wait a little more when rechecking
+      // the list to avoid busylooping here.
+      // If we ever hit this codepath it's mostly a bug in the code that signals
+      // the events.
+      uiAccessTime = 2;
+    }
   }
 
   return WELS_THREAD_ERROR_WAIT_FAILED;
 }
 
-WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitAllBlocking (uint32_t nCount, WELS_EVENT* event_list) {
+WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitAllBlocking (uint32_t nCount,
+    WELS_EVENT* event_list, WELS_EVENT* master_event) {
   uint32_t nIdx = 0;
   uint32_t uiCountSignals = 0;
   uint32_t uiSignalFlag	= 0;	// UGLY: suppose maximal event number up to 32
@@ -389,7 +413,21 @@
       if ((uiSignalFlag & kuiBitwiseFlag) != kuiBitwiseFlag) { // non-blocking mode
         int32_t err = 0;
 //				fprintf( stderr, "sem_wait(): start to wait event %d..\n", nIdx );
-        err = sem_wait (event_list[nIdx]);
+        if (master_event == NULL) {
+          err = sem_wait (event_list[nIdx]);
+        } else {
+          err = sem_wait (*master_event);
+          if (err == WELS_THREAD_ERROR_OK) {
+            err = sem_wait (event_list[nIdx]);
+            if (err != WELS_THREAD_ERROR_OK) {
+              // We successfully waited for the master event,
+              // but waiting for the individual event failed (e.g. EINTR?).
+              // Increase the master event count so that the next retry will
+              // work as intended.
+              sem_post (*master_event);
+            }
+          }
+        }
 //				fprintf( stderr, "sem_wait(): wait event %d result %d errno %d..\n", nIdx, err, errno );
         if (WELS_THREAD_ERROR_OK == err) {
 //					int32_t val = 0;
--- a/codec/common/WelsThreadLib.h
+++ b/codec/common/WelsThreadLib.h
@@ -110,8 +110,10 @@
 WELS_THREAD_ERROR_CODE    WelsEventSignal (WELS_EVENT* event);
 WELS_THREAD_ERROR_CODE    WelsEventWait (WELS_EVENT* event);
 WELS_THREAD_ERROR_CODE    WelsEventWaitWithTimeOut (WELS_EVENT* event, uint32_t dwMilliseconds);
-WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitSingleBlocking (uint32_t nCount, WELS_EVENT* event_list);
-WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitAllBlocking (uint32_t nCount, WELS_EVENT* event_list);
+WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitSingleBlocking (uint32_t nCount, WELS_EVENT* event_list,
+    WELS_EVENT* master_event = NULL);
+WELS_THREAD_ERROR_CODE    WelsMultipleEventsWaitAllBlocking (uint32_t nCount, WELS_EVENT* event_list,
+    WELS_EVENT* master_event = NULL);
 
 WELS_THREAD_ERROR_CODE    WelsThreadCreate (WELS_THREAD_HANDLE* thread,  LPWELS_THREAD_ROUTINE  routine,
     void* arg, WELS_THREAD_ATTR attr);