winealsa: block callback while holding critical section

Jan Zerebecki jan.wine at zerebecki.de
Fri Aug 25 09:29:01 CDT 2006


If this patch is rejected from inclusion, please tell me why, as
I would have to ask anyway.

From: Jan Zerebecki <jan.wine at zerebecki.de>
Changelog:
winealsa: block callback while holding critical section
This prevents a race condition.
---

 dlls/winmm/winealsa/Makefile.in |    2 +-
 dlls/winmm/winealsa/audio.c     |   25 ++++++++++++++++++++++++-
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/dlls/winmm/winealsa/Makefile.in b/dlls/winmm/winealsa/Makefile.in
index d5a254c..b5fa00c 100644
--- a/dlls/winmm/winealsa/Makefile.in
+++ b/dlls/winmm/winealsa/Makefile.in
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = winealsa.drv
 IMPORTS   = winmm user32 advapi32 kernel32 ntdll
-EXTRALIBS = -ldxguid -luuid @ALSALIBS@
+EXTRALIBS = -ldxguid -luuid @ALSALIBS@ -lpthread
 
 C_SRCS = \
 	audio.c \
diff --git a/dlls/winmm/winealsa/audio.c b/dlls/winmm/winealsa/audio.c
index 9eec364..9c3a5ad 100644
--- a/dlls/winmm/winealsa/audio.c
+++ b/dlls/winmm/winealsa/audio.c
@@ -38,6 +38,7 @@ #endif
 #include <errno.h>
 #include <limits.h>
 #include <fcntl.h>
+#include <signal.h>
 #ifdef HAVE_SYS_IOCTL_H
 # include <sys/ioctl.h>
 #endif
@@ -3040,6 +3041,10 @@ struct IDsDriverBufferImpl
     /* IDsDriverBufferImpl fields */
     IDsDriverImpl*	      drv;
 
+    /* alsa-lib uses a sigaction handler for the callback. To
+     * avoid a race condition, we mask the signal (to block the
+     * callback) while holding the critical section. */
+    sigset_t                  sig_mask;
     CRITICAL_SECTION          mmap_crst;
     LPVOID                    mmap_buffer;
     DWORD                     mmap_buflen_bytes;
@@ -3100,7 +3105,9 @@ static void DSDB_MMAPCopy(IDsDriverBuffe
     TRACE("avail=%d, mul=%d\n", (int)avail, mul);
 
     frames = pdbi->mmap_buflen_frames;
-	
+
+    if( ( err = pthread_sigmask(SIG_BLOCK, &pdbi->sig_mask, NULL) ) )
+        ERR("pthread_sigmask block returned: %d", err);
     EnterCriticalSection(&pdbi->mmap_crst);
 
     /* we want to commit the given number of periods, or the whole lot */
@@ -3129,6 +3136,8 @@ static void DSDB_MMAPCopy(IDsDriverBuffe
     }
 
     LeaveCriticalSection(&pdbi->mmap_crst);
+    if( ( err = pthread_sigmask(SIG_UNBLOCK, &pdbi->sig_mask, NULL) ) )
+        ERR("pthread_sigmask unblock returned: %d", err);
 }
 
 static void DSDB_PCMCallback(snd_async_handler_t *ahandler)
@@ -3215,6 +3224,16 @@ static int DSDB_CreateMMAP(IDsDriverBuff
 	return DSERR_GENERIC;
     }
 
+    if( ( err = sigemptyset(&pdbi->sig_mask) ) )
+        ERR("sigemptyset returned: %d error: %d", err, errno);
+    if( 0 > ( err = snd_async_handler_get_signo(pdbi->mmap_async_handler) ) )
+    {
+        ERR("snd_async_handler_get_signo returned: %d", err);
+        err = SIGIO;
+    }
+    if( ( err = sigaddset(&pdbi->sig_mask, err) ) )
+        ERR("sigaddset returned: %d errno: %d", err, errno);
+
     return DS_OK;
 }
 
@@ -3338,6 +3357,8 @@ static HRESULT WINAPI IDsDriverBufferImp
     /** we need to track down buffer underruns */
     DSDB_CheckXRUN(This);    
 
+    if( ( err = pthread_sigmask(SIG_BLOCK, &This->sig_mask, NULL) ) )
+        ERR("pthread_sigmask block returned: %d", err);
     EnterCriticalSection(&This->mmap_crst);
     hw_ptr = This->mmap_ppos;
     
@@ -3350,6 +3371,8 @@ static HRESULT WINAPI IDsDriverBufferImp
     if (lpdwWrite)
 	*lpdwWrite = snd_pcm_frames_to_bytes(wwo->pcm, hw_ptr + period_size * 2) % This->mmap_buflen_bytes;
     LeaveCriticalSection(&This->mmap_crst);
+    if( ( err = pthread_sigmask(SIG_UNBLOCK, &This->sig_mask, NULL) ) )
+        ERR("pthread_sigmask unblock returned: %d", err);
 
     TRACE("hw_ptr=0x%08x, playpos=%ld, writepos=%ld\n", (unsigned int)hw_ptr, lpdwPlay?*lpdwPlay:-1, lpdwWrite?*lpdwWrite:-1);
     return DS_OK;



More information about the wine-patches mailing list