Andrew Eikum : dsound: Don' t destroy primary buffer until device is released.

Alexandre Julliard julliard at winehq.org
Wed May 9 13:46:18 CDT 2012


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

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Wed May  9 08:48:56 2012 -0500

dsound: Don't destroy primary buffer until device is released.

---

 dlls/dsound/buffer.c         |   44 ++++++++++++++++++++++++++---------------
 dlls/dsound/dsound.c         |    5 ----
 dlls/dsound/dsound_private.h |    1 +
 dlls/dsound/primary.c        |   33 +++++++++++++++++++++++-------
 dlls/dsound/sound3d.c        |    9 ++++---
 dlls/dsound/tests/dsound.c   |    9 ++++++++
 6 files changed, 68 insertions(+), 33 deletions(-)

diff --git a/dlls/dsound/buffer.c b/dlls/dsound/buffer.c
index 5f9e455..08f4ba7 100644
--- a/dlls/dsound/buffer.c
+++ b/dlls/dsound/buffer.c
@@ -327,16 +327,22 @@ static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
 {
     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref was %d\n", This, ref + 1);
+    ULONG ref;
+
+    if (is_primary_buffer(This)){
+        ref = capped_refcount_dec(&This->ref);
+        if(!ref)
+            capped_refcount_dec(&This->numIfaces);
+        TRACE("(%p) ref is now: %d\n", This, ref);
+        return ref;
+    }
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces)) {
-        if (is_primary_buffer(This))
-            primarybuffer_destroy(This);
-        else
+    ref = InterlockedDecrement(&This->ref);
+    if (!ref && !InterlockedDecrement(&This->numIfaces))
             secondarybuffer_destroy(This);
-    }
+
+    TRACE("(%p) ref is now %d\n", This, ref);
+
     return ref;
 }
 
@@ -1077,16 +1083,22 @@ static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
 {
     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
-    ULONG ref = InterlockedDecrement(&This->refiks);
+    ULONG ref;
+
+    if (is_primary_buffer(This)){
+        ref = capped_refcount_dec(&This->refiks);
+        if(!ref)
+            capped_refcount_dec(&This->numIfaces);
+        TRACE("(%p) ref is now: %d\n", This, ref);
+        return ref;
+    }
 
-    TRACE("(%p) ref was %d\n", This, ref + 1);
+    ref = InterlockedDecrement(&This->refiks);
+    if (!ref && !InterlockedDecrement(&This->numIfaces))
+        secondarybuffer_destroy(This);
+
+    TRACE("(%p) ref is now %d\n", This, ref);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces)) {
-        if (is_primary_buffer(This))
-            primarybuffer_destroy(This);
-        else
-            secondarybuffer_destroy(This);
-    }
     return ref;
 }
 
diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index 91184c9..2429042 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -1255,11 +1255,6 @@ ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
                 secondarybuffer_destroy(device->buffers[i]);
         }
 
-        if (device->primary) {
-            WARN("primary buffer not released\n");
-            IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
-        }
-
         hr = DSOUND_PrimaryDestroy(device);
         if (hr != DS_OK)
             WARN("DSOUND_PrimaryDestroy failed\n");
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 8c6f60b..bed6959 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -288,6 +288,7 @@ HRESULT primarybuffer_create(DirectSoundDevice *device, IDirectSoundBufferImpl *
     const DSBUFFERDESC *dsbd) DECLSPEC_HIDDEN;
 void primarybuffer_destroy(IDirectSoundBufferImpl *This) DECLSPEC_HIDDEN;
 HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) DECLSPEC_HIDDEN;
+LONG capped_refcount_dec(LONG *ref) DECLSPEC_HIDDEN;
 
 /* duplex.c */
  
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index c39da8a..b5a09f8 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -258,6 +258,13 @@ HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device)
 	EnterCriticalSection(&(device->mixlock));
 
 	DSOUND_PrimaryClose(device);
+
+	if(device->primary && (device->primary->ref || device->primary->numIfaces))
+		WARN("Destroying primary buffer while references held (%u %u)\n", device->primary->ref, device->primary->numIfaces);
+
+	HeapFree(GetProcessHeap(), 0, device->primary);
+	device->primary = NULL;
+
 	HeapFree(GetProcessHeap(),0,device->pwfx);
 	device->pwfx=NULL;
 
@@ -756,21 +763,31 @@ static ULONG WINAPI PrimaryBufferImpl_AddRef(IDirectSoundBuffer *iface)
     return ref;
 }
 
-void primarybuffer_destroy(IDirectSoundBufferImpl *This)
+/* Decreases *out by 1 to no less than 0.
+ * Returns the new value of *out. */
+LONG capped_refcount_dec(LONG *out)
 {
-    This->device->primary = NULL;
-    HeapFree(GetProcessHeap(), 0, This);
-    TRACE("(%p) released\n", This);
+    LONG ref, oldref;
+    do {
+        ref = *out;
+        if(!ref)
+            return 0;
+        oldref = InterlockedCompareExchange(out, ref - 1, ref);
+    } while(oldref != ref);
+    return ref - 1;
 }
 
 static ULONG WINAPI PrimaryBufferImpl_Release(IDirectSoundBuffer *iface)
 {
     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer(iface);
-    DWORD ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %d\n", This, ref + 1);
+    ULONG ref;
+
+    ref = capped_refcount_dec(&This->ref);
+    if(!ref)
+        capped_refcount_dec(&This->numIfaces);
+
+    TRACE("(%p) primary ref is now %d\n", This, ref);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        primarybuffer_destroy(This);
     return ref;
 }
 
diff --git a/dlls/dsound/sound3d.c b/dlls/dsound/sound3d.c
index c57aa2e..604d19b 100644
--- a/dlls/dsound/sound3d.c
+++ b/dlls/dsound/sound3d.c
@@ -699,12 +699,13 @@ static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(IDirectSound3DListener *if
 static ULONG WINAPI IDirectSound3DListenerImpl_Release(IDirectSound3DListener *iface)
 {
     IDirectSoundBufferImpl *This = impl_from_IDirectSound3DListener(iface);
-    ULONG ref = InterlockedDecrement(&This->ref3D);
+    ULONG ref;
 
-    TRACE("(%p) ref was %d\n", This, ref + 1);
+    ref = capped_refcount_dec(&This->ref3D);
+    if(!ref)
+        capped_refcount_dec(&This->numIfaces);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-            primarybuffer_destroy(This);
+    TRACE("(%p) ref is now %d\n", This, ref);
 
     return ref;
 }
diff --git a/dlls/dsound/tests/dsound.c b/dlls/dsound/tests/dsound.c
index c68a5de..4c46f67 100644
--- a/dlls/dsound/tests/dsound.c
+++ b/dlls/dsound/tests/dsound.c
@@ -493,6 +493,15 @@ static HRESULT test_primary(LPGUID lpGuid)
                     !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0,FALSE,0);
 
         ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references\n",ref);
+
+        ref=IDirectSoundBuffer_AddRef(primary);
+        ok(ref==1,"IDirectSoundBuffer_AddRef() primary has %d references\n",ref);
+
+        ref=IDirectSoundBuffer_Release(primary);
+        ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references\n",ref);
+
+        ref=IDirectSoundBuffer_Release(primary);
         ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, "
            "should have 0\n",ref);
     }




More information about the wine-cvs mailing list