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