CVS: winex/dlls/winmm/winealsa audio.c,1.46,1.47

[email protected]
Newsgroups gmane.comp.emulators.winex.cvs
Message-ID <[email protected]>
Subject: winex/dlls/winmm/winealsa audio.c,1.46,1.47Update of /var/lib/cvsd/cvsroot/winex/dlls/winmm/winealsa
In directory agravaine:/tmp/cvs-serv24792/dlls/winmm/winealsa

Modified Files:
	audio.c 
Log Message:
Previously, if the asynchronous PCM callback was called while the critical
section was already being held by the same thread, bad things could happen,
including loss of audio or even deadlocks. I've attempted to prevent this
from happening by managing the critical section locking more carefully.


Index: audio.c
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/winmm/winealsa/audio.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -d -r1.46 -r1.47
--- audio.c	30 Mar 2007 21:32:40 -0000	1.46
+++ audio.c	30 Mar 2007 21:34:31 -0000	1.47
@@ -2036,9 +2036,30 @@
     snd_pcm_uframes_t         mmap_app_position;
     const snd_pcm_channel_area_t * mmap_areas_last;
     snd_pcm_uframes_t         mmap_async_commit;
+    LONG                      mmap_copy_pending;
     BOOL playing;
 };
 
+#define INIT_COPY(dsdb) \
+  do { \
+    EnterCriticalSection(&(dsdb)->mmap_crst); \
+    DSDB_MMAPCopy(dsdb); \
+    LeaveCriticalSection(&(dsdb)->mmap_crst); \
+  } while (0)
+#define ENTER_LOCK(dsdb) \
+  do { \
+    EnterCriticalSection(&(dsdb)->mmap_crst); \
+  } while (0)
+#define LEAVE_LOCK(dsdb) \
+  do { \
+    LONG recursion = (dsdb)->mmap_crst.RecursionCount; \
+    LeaveCriticalSection(&(dsdb)->mmap_crst); \
+    if (recursion <= 1) { \
+      while (InterlockedExchange(&(dsdb)->mmap_copy_pending, 0)) \
+        INIT_COPY(dsdb); \
+    } \
+  } while (0)
+
 static inline snd_pcm_t* DSDB_get_handle(IDsDriverBufferImpl* pdbi)
 {
     return WOutDev[pdbi->drv->wDevID].p_handle;
@@ -2166,7 +2187,19 @@
     /* snd_pcm_t *               handle = snd_async_handler_get_pcm(ahandler); */
     IDsDriverBufferImpl*      pdbi = snd_async_handler_get_callback_private(ahandler);
     TRACE("callback called\n");
+    /* try to acquire critical section (must not block) */
+    if (!TryEnterCriticalSection(&pdbi->mmap_crst)) {
+        InterlockedIncrement(&pdbi->mmap_copy_pending);
+        return;
+    }
+    /* don't accept a recursive lock, it means we interrupted something */
+    if (pdbi->mmap_crst.RecursionCount > 1) {
+        InterlockedIncrement(&pdbi->mmap_copy_pending);
+        LeaveCriticalSection(&pdbi->mmap_crst);
+        return;
+    }
     DSDB_MMAPCopy(pdbi);
+    LeaveCriticalSection(&pdbi->mmap_crst);
 }
 
 static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi)
@@ -2198,6 +2231,7 @@
     pdbi->mmap_buflen_frames = frames;
     pdbi->mmap_buflen_bytes = snd_pcm_frames_to_bytes( handle, frames );
     pdbi->mmap_async_commit = 0;
+    pdbi->mmap_copy_pending = 0;
 #if 0
     pdbi->mmap_buffer = HeapAlloc(GetProcessHeap(),0,pdbi->mmap_buflen_bytes);
     if (!pdbi->mmap_buffer)
@@ -2330,7 +2364,7 @@
 
     DSDB_CheckXRUN(This);
 
-    EnterCriticalSection(&This->mmap_crst);
+    ENTER_LOCK(This);
     handle = DSDB_get_handle(This);
 
     /* get playing position */
@@ -2443,7 +2477,7 @@
 	    err = snd_pcm_mmap_begin(handle, &This->mmap_areas_last, &offset, &frames);
 	    if (err < 0) {
 		ERR("mmap_begin failed, reason: %s\n", snd_strerror(err));
-		LeaveCriticalSection(&This->mmap_crst);
+		LEAVE_LOCK(This);
 		return E_FAIL;
 	    }
 
@@ -2500,7 +2534,7 @@
 	if (pdwLen2) *pdwLen2 = 0;
     }
 
-    LeaveCriticalSection(&This->mmap_crst);
+    LEAVE_LOCK(This);
 
     TRACE("=>(%p,%ld,%p,%ld)\n", *ppvAudio1, *pdwLen1,
 				 ppvAudio2 ? *ppvAudio2 : NULL,
@@ -2526,7 +2560,7 @@
 
     DSDB_CheckXRUN (This);
 
-    EnterCriticalSection(&This->mmap_crst);
+    ENTER_LOCK(This);
     handle = DSDB_get_handle(This);
 
     dwWritePos = ((LPBYTE)pvAudio1) - ((LPBYTE)This->mmap_areas_last[0].addr);
@@ -2626,7 +2660,7 @@
 	    move = snd_pcm_mmap_commit(handle, offset, left);
 	    if (move < 0) {
 		ERR("mmap_commit failed, reason: %s\n", snd_strerror(move));
-		LeaveCriticalSection(&This->mmap_crst);
+		LEAVE_LOCK(This);
 		return E_FAIL;
 	    }
 	    if (!move) {
@@ -2641,7 +2675,7 @@
     }
     TRACE("app_pos=%ld\n", This->mmap_app_position);
 
-    LeaveCriticalSection(&This->mmap_crst);
+    LEAVE_LOCK(This);
 
     state = snd_pcm_state(handle);
     if ( state == SND_PCM_STATE_PREPARED && This->playing )
@@ -2807,7 +2841,7 @@
     /** we need to track down buffer underruns */
     DSDB_CheckXRUN(This);
 
-    EnterCriticalSection(&This->mmap_crst);
+    ENTER_LOCK(This);
     handle = DSDB_get_handle(This);
 
     if (!handle) {
@@ -2816,7 +2850,7 @@
 	    *lpdwPlay = 0;
 	if (lpdwWrite)
 	    *lpdwWrite = 0;
-	LeaveCriticalSection(&This->mmap_crst);
+	LEAVE_LOCK(This);
 	return DS_OK;
     }
 
@@ -2855,7 +2889,7 @@
 	    *lpdwWrite = snd_pcm_frames_to_bytes(handle, hw_ptr) % This->mmap_buflen_bytes;
     }
 #endif
-    LeaveCriticalSection(&This->mmap_crst);
+    LEAVE_LOCK(This);
 
     TRACE("hw_ptr=%ld, playpos=%ld, writepos=%ld\n", hw_ptr, lpdwPlay?*lpdwPlay:-1, lpdwWrite?*lpdwWrite:-1);
     return DS_OK;
@@ -2879,7 +2913,7 @@
     if ( state == SND_PCM_STATE_PREPARED )
     {
 	if (This->mmap_async_commit)
-	    DSDB_MMAPCopy(This);
+	    INIT_COPY(This);
 	err = snd_pcm_start(handle);
     }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.