]> Repos - portaudio/commitdiff
wasapi: use InterlockedXXX APIs to secure inter-thread r/w access to variables to...
authordmitrykos <dmitrykos@neutroncode.com>
Wed, 24 Aug 2016 19:04:17 +0000 (22:04 +0300)
committerdmitrykos <dmitrykos@neutroncode.com>
Wed, 24 Aug 2016 19:04:17 +0000 (22:04 +0300)
src/hostapi/wasapi/pa_win_wasapi.c

index 4564826b1f3df0ba8376380faaeeb768ae268122..367b87d071e1de5c51ed05a7c3ebe96fae301ed2 100644 (file)
@@ -543,7 +543,7 @@ typedef struct PaWasapiStream
 
        // must be volatile to avoid race condition on user query while
        // thread is being started
-    volatile BOOL running;
+    volatile LONG running;
 
     PA_THREAD_ID dwThreadId;
     HANDLE hThread;
@@ -1237,8 +1237,8 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d
 typedef struct PaActivateAudioInterfaceCompletionHandler
 {
        IActivateAudioInterfaceCompletionHandler parent;
-       ULONG refs;
-       volatile BOOL done;
+       volatile LONG refs;
+       volatile LONG done;
        struct
        {
                HRESULT hr;
@@ -1256,7 +1256,8 @@ static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Quer
        // From MSDN:
        // "The IAgileObject interface is a marker interface that indicates that an object 
        //  is free threaded and can be called from any apartment."
-       if (IsEqualIID(riid, &IID_IAgileObject))
+       if (IsEqualIID(riid, &IID_IUnknown) || 
+               IsEqualIID(riid, &IID_IAgileObject))
        {
                handler->parent.lpVtbl->AddRef((IActivateAudioInterfaceCompletionHandler *)handler);
                (*ppvObject) = handler;
@@ -1270,20 +1271,23 @@ static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef
     IActivateAudioInterfaceCompletionHandler *This)
 {
        PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
-       return ++ handler->refs;
+
+       return InterlockedIncrement(&handler->refs);
 }
         
 static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)( 
     IActivateAudioInterfaceCompletionHandler *This)
 {
        PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This;
-       if (handler->refs == 0)
+       ULONG refs;
+
+       if ((refs = InterlockedDecrement(&handler->refs)) == 0)
        {
                PaUtil_FreeMemory(handler->parent.lpVtbl);
                PaUtil_FreeMemory(handler);
-               return 0;
        }
-       return -- handler->refs;
+
+       return refs;
 }
         
 static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)( 
@@ -1311,7 +1315,9 @@ static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Acti
        else
                handler->out.hr = hr;
        
-       handler->done = TRUE;
+       // Got client object, stop busy waiting in ActivateAudioInterface_WINRT
+       InterlockedExchange(&handler->done, TRUE);
+
        return hr;
 }
 
@@ -1324,6 +1330,7 @@ static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCom
        handler->parent.lpVtbl->AddRef            = &PaActivateAudioInterfaceCompletionHandler_AddRef;
        handler->parent.lpVtbl->Release           = &PaActivateAudioInterfaceCompletionHandler_Release;
        handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted;
+       handler->refs = 1;
        return (IActivateAudioInterfaceCompletionHandler *)handler;
 }
 #endif
@@ -1360,7 +1367,7 @@ static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo
     IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
 
        // Wait in busy loop for async operation to complete
-       while (SUCCEEDED(hr) && !handlerImpl->done)
+       while (SUCCEEDED(hr) && !InterlockedCompareExchange(&handlerImpl->done, FALSE, FALSE))
        {
                Sleep(1);
        }
@@ -3849,7 +3856,7 @@ static PaError StartStream( PaStream *s )
                stream->out.clientProc = stream->out.clientParent;
 
                // Signal: stream running.
-               stream->running = TRUE;
+               InterlockedExchange(&stream->running, TRUE);
        }
 
     return result;
@@ -3891,7 +3898,8 @@ void _StreamFinish(PaWasapiStream *stream)
        // Cleanup handles
        _StreamCleanup(stream);
 
-    stream->running = FALSE;
+       // Notify: not running
+    InterlockedExchange(&stream->running, FALSE);
 }
 
 // ------------------------------------------------------------------------------------------
@@ -3906,6 +3914,18 @@ void _StreamCleanup(PaWasapiStream *stream)
        SAFE_CLOSE(stream->hBlockingOpStreamWR);
 }
 
+// ------------------------------------------------------------------------------------------
+static BOOL _IsStreamRunning(PaWasapiStream *stream)
+{
+       LONG retv;
+       do 
+       {
+               retv = stream->running;
+       } 
+       while (InterlockedCompareExchange(&stream->running, FALSE, FALSE) != retv);
+       return retv;
+}
+
 // ------------------------------------------------------------------------------------------
 static PaError StopStream( PaStream *s )
 {
@@ -3925,13 +3945,13 @@ static PaError AbortStream( PaStream *s )
 // ------------------------------------------------------------------------------------------
 static PaError IsStreamStopped( PaStream *s )
 {
-       return !((PaWasapiStream *)s)->running;
+       return !_IsStreamRunning((PaWasapiStream *)s);
 }
 
 // ------------------------------------------------------------------------------------------
 static PaError IsStreamActive( PaStream *s )
 {
-    return ((PaWasapiStream *)s)->running;
+    return _IsStreamRunning((PaWasapiStream *)s);
 }
 
 // ------------------------------------------------------------------------------------------
@@ -3965,7 +3985,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
        ThreadIdleScheduler sched;
 
        // validate
-       if (!stream->running)
+       if (!_IsStreamRunning(stream))
                return paStreamIsStopped;
        if (stream->captureClient == NULL)
                return paBadStreamPtr;
@@ -4144,7 +4164,7 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram
        ThreadIdleScheduler sched;
 
        // validate
-       if (!stream->running)
+       if (!_IsStreamRunning(stream))
                return paStreamIsStopped;
        if (stream->renderClient == NULL)
                return paBadStreamPtr;
@@ -4258,7 +4278,7 @@ static signed long GetStreamReadAvailable( PaStream* s )
        UINT32  available = 0;
 
        // validate
-       if (!stream->running)
+       if (!_IsStreamRunning(stream))
                return paStreamIsStopped;
        if (stream->captureClient == NULL)
                return paBadStreamPtr;
@@ -4284,7 +4304,7 @@ static signed long GetStreamWriteAvailable( PaStream* s )
        UINT32  available = 0;
 
        // validate
-       if (!stream->running)
+       if (!_IsStreamRunning(stream))
                return paStreamIsStopped;
        if (stream->renderClient == NULL)
                return paBadStreamPtr;
@@ -5074,7 +5094,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
        }
 
        // Signal: stream running
-       stream->running = TRUE;
+       InterlockedExchange(&stream->running, TRUE);
 
        // Notify: thread started
        SetEvent(stream->hThreadStart);
@@ -5141,7 +5161,7 @@ thread_end:
                CoUninitialize();
 
        // Notify: not running
-       stream->running = FALSE;
+       InterlockedExchange(&stream->running, FALSE);
 
        // Notify: thread exited
        SetEvent(stream->hThreadExit);
@@ -5308,7 +5328,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
        }
 
        // Signal: stream running
-       stream->running = TRUE;
+       InterlockedExchange(&stream->running, TRUE);
 
        // Notify: thread started
        SetEvent(stream->hThreadStart);
@@ -5663,7 +5683,7 @@ thread_end:
                CoUninitialize();
 
        // Notify: not running
-       stream->running = FALSE;
+       InterlockedExchange(&stream->running, FALSE);
 
        // Notify: thread exited
        SetEvent(stream->hThreadExit);