Maarten Lankhorst : quartz: Make the file source rotate around the 'first' sample, to prevent starvation of a single stream.

Alexandre Julliard julliard at winehq.org
Fri Jul 11 08:44:06 CDT 2008


Module: wine
Branch: master
Commit: 2865c727de7e8732fb6646d473b7818271cef0fa
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=2865c727de7e8732fb6646d473b7818271cef0fa

Author: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date:   Thu Jul 10 14:33:53 2008 -0700

quartz: Make the file source rotate around the 'first' sample, to prevent starvation of a single stream.

This prevents the file source from starving a single thread off.

---

 dlls/quartz/filesource.c |   62 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/dlls/quartz/filesource.c b/dlls/quartz/filesource.c
index 99f8852..2a063e2 100644
--- a/dlls/quartz/filesource.c
+++ b/dlls/quartz/filesource.c
@@ -768,6 +768,7 @@ typedef struct FileAsyncReader
     /* Why would you need more? Every sample has its own handle */
     LONG queued_number;
     LONG samples;
+    LONG oldest_sample;
     CRITICAL_SECTION csList; /* critical section to prevent concurrency issues */
     DATAREQUEST *sample_list;
 
@@ -1018,9 +1019,10 @@ done:
         }
 
         This->samples = pProps->cBuffers;
+        This->oldest_sample = 0;
         TRACE("Samples: %u\n", This->samples);
         This->sample_list = CoTaskMemAlloc(sizeof(This->sample_list[0]) * pProps->cBuffers);
-        This->handle_list = CoTaskMemAlloc(sizeof(HANDLE) * (pProps->cBuffers + 1));
+        This->handle_list = CoTaskMemAlloc(sizeof(HANDLE) * pProps->cBuffers * 2);
 
         if (This->sample_list && This->handle_list)
         {
@@ -1029,6 +1031,8 @@ done:
             for (x = 0; x < This->samples; ++x)
             {
                 This->sample_list[x].ovl.hEvent = This->handle_list[x] = CreateEventW(NULL, 0, 0, NULL);
+                if (x + 1 < This->samples)
+                    This->handle_list[This->samples + 1 + x] = This->handle_list[x];
             }
             This->handle_list[This->samples] = CreateEventW(NULL, 1, 0, NULL);
             This->pin.allocProps = *pProps;
@@ -1064,7 +1068,6 @@ static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample
     REFERENCE_TIME Stop;
     FileAsyncReader *This = impl_from_IAsyncReader(iface);
     LPBYTE pBuffer = NULL;
-    DWORD wait;
 
     TRACE("(%p, %lx)\n", pSample, dwUser);
 
@@ -1085,12 +1088,6 @@ static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample
         return VFW_E_WRONG_STATE;
     }
 
-    wait = WaitForMultipleObjectsEx(This->samples, This->handle_list, FALSE, 0, FALSE);
-    if (wait < This->samples - 1)
-        SetEvent(This->handle_list[wait]);
-    else
-        wait = This->samples;
-
     if (SUCCEEDED(hr))
     {
         DWORD dwLength = (DWORD) BYTES_FROM_MEDIATIME(Stop - Start);
@@ -1098,21 +1095,22 @@ static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader * iface, IMediaSample
         int x;
 
         /* Try to insert above the waiting sample if possible */
-        for (x = wait + 1; x < This->samples; ++x)
+        for (x = This->oldest_sample; x < This->samples; ++x)
         {
             if (!This->sample_list[x].pSample)
                 break;
         }
 
         if (x >= This->samples)
-            for (x = 0; x < This->samples; ++x)
+            for (x = 0; x < This->oldest_sample; ++x)
             {
                 if (!This->sample_list[x].pSample)
                     break;
             }
 
+        /* There must be a sample we have found */
         assert(x < This->samples);
-        InterlockedIncrement(&This->queued_number);
+        ++This->queued_number;
 
         pDataRq = This->sample_list + x;
 
@@ -1154,16 +1152,32 @@ static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dw
     *ppSample = NULL;
     *pdwUser = 0;
 
+    EnterCriticalSection(&This->csList);
     if (!This->bFlushing)
     {
+        LONG oldest = This->oldest_sample;
+
         if (!This->queued_number)
         {
             /* It could be that nothing is queued right now, but that can be fixed */
             WARN("Called without samples in queue and not flushing!!\n");
         }
+        LeaveCriticalSection(&This->csList);
 
         /* wait for an object to read, or time out */
-        buffer = WaitForMultipleObjectsEx(This->samples+1, This->handle_list, FALSE, dwTimeout, TRUE);
+        buffer = WaitForMultipleObjectsEx(This->samples+1, This->handle_list + oldest, FALSE, dwTimeout, TRUE);
+
+        EnterCriticalSection(&This->csList);
+        if (buffer <= This->samples)
+        {
+            /* Re-scale the buffer back to normal */
+            buffer += oldest;
+
+            /* Uh oh, we overshot the flusher handle, renormalize it back to 0..Samples-1 */
+            if (buffer > This->samples)
+                buffer -= This->samples + 1;
+            assert(buffer <= This->samples);
+        }
 
         if (buffer >= This->samples)
         {
@@ -1172,11 +1186,10 @@ static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dw
             hr = VFW_E_TIMEOUT;
             buffer = ~0;
         }
-        else if (buffer < This->samples)
-            InterlockedDecrement(&This->queued_number);
+        else
+            --This->queued_number;
     }
 
-    EnterCriticalSection(&This->csList);
     if (This->bFlushing && buffer == ~0)
     {
         for (buffer = 0; buffer < This->samples; ++buffer)
@@ -1194,7 +1207,7 @@ static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dw
         }
         else
         {
-            InterlockedDecrement(&This->queued_number);
+            --This->queued_number;
             hr = S_OK;
         }
     }
@@ -1239,6 +1252,23 @@ static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader * iface, DWORD dw
             assert(rtStop == rtStart);
 
         This->sample_list[buffer].pSample = NULL;
+        assert(This->oldest_sample < This->samples);
+
+        if (buffer == This->oldest_sample)
+        {
+            LONG x;
+            for (x = This->oldest_sample + 1; x < This->samples; ++x)
+                if (This->sample_list[x].pSample)
+                    break;
+            if (x >= This->samples)
+                for (x = 0; x < This->oldest_sample; ++x)
+                    if (This->sample_list[x].pSample)
+                        break;
+            if (This->oldest_sample == x)
+                /* No samples found, reset to 0 */
+                x = 0;
+            This->oldest_sample = x;
+        }
     }
     LeaveCriticalSection(&This->csList);
 




More information about the wine-cvs mailing list