From 4664903d1eb3949a6d84b8c950c2a1f46534f381 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Wed, 29 May 2002 19:04:41 +0000 Subject: [PATCH] Some other synchronisation issues. --- dlls/winmm/mmsystem.c | 222 ++++++++++++++++++++++++------------------ dlls/winmm/winemm.h | 18 ++-- 2 files changed, 135 insertions(+), 105 deletions(-) diff --git a/dlls/winmm/mmsystem.c b/dlls/winmm/mmsystem.c index 5a51ff39dca..6e54f29781c 100644 --- a/dlls/winmm/mmsystem.c +++ b/dlls/winmm/mmsystem.c @@ -93,6 +93,9 @@ static BOOL MULTIMEDIA_CreateIData(HINSTANCE hInstDLL) iData->lpNextIData = lpFirstIData; lpFirstIData = iData; InitializeCriticalSection(&iData->cs); + iData->cs.DebugInfo = (void*)__FILE__ ": WinMM"; + iData->psStopEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + iData->psLastEvent = CreateEventA(NULL, TRUE, FALSE, NULL); TRACE("Created IData (%p) for pid %08lx\n", iData, iData->dwThisProcess); return TRUE; } @@ -116,6 +119,9 @@ static void MULTIMEDIA_DeleteIData(void) } /* FIXME: should also free content and resources allocated * inside iData */ + CloseHandle(iData->psStopEvent); + CloseHandle(iData->psLastEvent); + DeleteCriticalSection(&iData->cs); HeapFree(GetProcessHeap(), 0, iData); } } @@ -245,17 +251,12 @@ static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName) static WCHAR wszSounds[] = {'S','o','u','n','d','s',0}; static WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0}; - static WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\','\\', - 'S','c','h','e','m','e','s','\\','\\', + static WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\', + 'S','c','h','e','m','e','s','\\', 'A','p','p','s',0}; static WCHAR wszDotDefault[] = {'.','D','e','f','a','u','l','t',0}; static WCHAR wszNull[] = {0}; - /* FIXME: we should also look up the registry under - * HKCU\AppEvents\Schemes\Apps\.Default - * HKCU\AppEvents\Schemes\Apps\ - */ - TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName)); GetProfileStringW(wszSounds, (LPWSTR)lpszName, wszNull, str, sizeof(str)/sizeof(str[0])); if (lstrlenW(str) == 0) @@ -269,14 +270,16 @@ static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName) hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); if (hmmio != 0) return hmmio; next: + /* we look up the registry under + * HKCU\AppEvents\Schemes\Apps\.Default + * HKCU\AppEvents\Schemes\Apps\ + */ if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none; if (uFlags & SND_APPLICATION) { - err = 1; + err = 1; /* error */ if (GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0]))) { - LPWSTR ptr; - for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--) { if (*ptr == '.') *ptr = 0; @@ -303,7 +306,7 @@ static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName) count = sizeof(str)/sizeof(str[0]); err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count); RegCloseKey(hSnd); - if (err != 0) goto none; + if (err != 0 || !*str) goto none; hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); if (hmmio) return hmmio; none: @@ -348,6 +351,77 @@ static void PlaySound_WaitDone(struct playsound_data* s) } } +static BOOL PlaySound_IsString(DWORD fdwSound, const void* psz) +{ + /* SND_RESOURCE is 0x40004 while + * SND_MEMORY is 0x00004 + */ + switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME)) + { + case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */ + case SND_MEMORY: return FALSE; + case SND_ALIAS: /* what about ALIAS_ID ??? */ + case SND_FILENAME: + case 0: return TRUE; + default: FIXME("WTF\n"); return FALSE; + } +} + +static void PlaySound_Free(WINE_PLAYSOUND* wps) +{ + LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData(); + WINE_PLAYSOUND** p; + + EnterCriticalSection(&iData->cs); + for (p = &iData->lpPlaySound; *p && *p != wps; p = &((*p)->lpNext)); + if (*p) *p = (*p)->lpNext; + if (iData->lpPlaySound == NULL) SetEvent(iData->psLastEvent); + LeaveCriticalSection(&iData->cs); + if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound); + HeapFree(GetProcessHeap(), 0, wps); +} + +static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod, + DWORD fdwSound, BOOL bUnicode) +{ + WINE_PLAYSOUND* wps; + + wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps)); + if (!wps) return NULL; + + wps->hMod = hmod; + wps->fdwSound = fdwSound; + if (PlaySound_IsString(fdwSound, pszSound)) + { + if (bUnicode) + { + if (fdwSound & SND_ASYNC) + { + wps->pszSound = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pszSound)+1) * sizeof(WCHAR)); + if (!wps->pszSound) goto oom_error; + lstrcpyW((LPWSTR)wps->pszSound, pszSound); + wps->bAlloc = TRUE; + } + else + wps->pszSound = pszSound; + } + else + { + wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound); + if (!wps->pszSound) goto oom_error; + wps->bAlloc = TRUE; + } + } + else + wps->pszSound = pszSound; + + return wps; + oom_error: + PlaySound_Free(wps); + return NULL; +} + static DWORD WINAPI proc_PlaySound(LPVOID arg) { WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg; @@ -385,7 +459,6 @@ static DWORD WINAPI proc_PlaySound(LPVOID arg) data = (void*)wps->pszSound; /* construct an MMIO stream (either in memory, or from a file */ -/* hmmio = 0; */ /* to catch errors */ if (wps->fdwSound & SND_MEMORY) { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */ MMIOINFO mminfo; @@ -482,9 +555,11 @@ static DWORD WINAPI proc_PlaySound(LPVOID arg) s.dwEventCount = 1L; /* for first buffer */ mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET); - while (left) { - if (wps->bStop) { - wps->bStop = wps->bLoop = FALSE; + while (left) + { + if (WaitForSingleObject(iData->psStopEvent, 0) == WAIT_OBJECT_0) + { + wps->bLoop = FALSE; break; } count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left)); @@ -515,38 +590,15 @@ errCleanUp: if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100); if (hmmio) mmioClose(hmmio, 0); - SetEvent(wps->hReadyEvent); - iData->lpPlaySound = NULL; - - if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound); - CloseHandle(wps->hReadyEvent); - HeapFree(GetProcessHeap(), 0, wps); + PlaySound_Free(wps); return bRet; } -static BOOL MULTIMEDIA_IsString(DWORD fdwSound, const void* psz) -{ - /* SND_RESOURCE is 0x40004 while - * SND_MEMORY is 0x00004 - */ - switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME)) - { - case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */ - case SND_MEMORY: return FALSE; - case SND_ALIAS: /* what about ALIAS_ID ??? */ - case SND_FILENAME: - case 0: return TRUE; - default: FIXME("WTF\n"); return FALSE; - } -} - static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode) { WINE_PLAYSOUND* wps = NULL; - DWORD id; LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData(); - BOOL bRet = FALSE; TRACE("pszSound='%p' hmod=%04X fdwSound=%08lX\n", pszSound, hmod, fdwSound); @@ -554,74 +606,52 @@ static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSo /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP ! * there could be one if several sounds can be played at once... */ - if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound) + if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && iData->lpPlaySound != NULL) return FALSE; + + /* alloc internal structure, if we need to play something */ + if (pszSound && !(fdwSound & SND_PURGE)) + { + if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode))) + return FALSE; + } - do { - HANDLE hEvt = 0; + EnterCriticalSection(&iData->cs); + /* since several threads can enter PlaySound in parallel, we're not + * sure, at this point, that another thread didn't start a new playsound + */ + while (iData->lpPlaySound != NULL) + { + ResetEvent(iData->psLastEvent); + /* FIXME: doc says we have to stop all instances of pszSound if it's non + * NULL... as of today, we stop all playing instances */ + SetEvent(iData->psStopEvent); - /* Trying to stop if playing */ - EnterCriticalSection(&iData->cs); - if (iData->lpPlaySound) { - LPWINE_PLAYSOUND ps2stop = iData->lpPlaySound; - - hEvt = ps2stop->hReadyEvent; - ps2stop->bStop = TRUE; - } LeaveCriticalSection(&iData->cs); - /* Waiting playing thread to get ready. I think 10 secs is ok & if not then leave - * FIXME: race here (if hEvt is destroyed and reallocated - as a handle - to - * another object)... unlikely but possible - */ - if (hEvt) WaitForSingleObject(hEvt, 1000*10); + WaitForSingleObject(iData->psLastEvent, INFINITE); + EnterCriticalSection(&iData->cs); - if (!pszSound || (fdwSound & SND_PURGE)) - return TRUE; /* We stopped playing so leaving */ + ResetEvent(iData->psStopEvent); + } - if (wps == NULL) - { - wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps)); - if (!wps) return FALSE; - - wps->hMod = hmod; - wps->fdwSound = fdwSound; - wps->bAlloc = FALSE; - if (MULTIMEDIA_IsString(fdwSound, pszSound)) - { - if (bUnicode) - { - if (fdwSound & SND_ASYNC) - { - wps->pszSound = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pszSound)+1) * sizeof(WCHAR)); - lstrcpyW((LPWSTR)wps->pszSound, pszSound); - wps->bAlloc = TRUE; - } - else - wps->pszSound = pszSound; - } - else - { - wps->pszSound = HEAP_strdupAtoW(GetProcessHeap(), 0, pszSound); - wps->bAlloc = TRUE; - } - } - else - wps->pszSound = pszSound; - if ((wps->hReadyEvent = CreateEventA(NULL, TRUE, FALSE, NULL)) == 0) - goto cleanup; - } - } while (InterlockedCompareExchangePointer((void**)&iData->lpPlaySound, wps, NULL) != NULL); + wps->lpNext = iData->lpPlaySound; + iData->lpPlaySound = wps; + LeaveCriticalSection(&iData->cs); + + if (!pszSound || (fdwSound & SND_PURGE)) return TRUE; if (fdwSound & SND_ASYNC) { - wps->bLoop = fdwSound & SND_LOOP; - /* FIXME: memory leak in case of error & cs is still locked */ - return ((wps->hThread = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0); + DWORD id; + wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE; + if (CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id) != 0) + return TRUE; } + else return proc_PlaySound(wps); - bRet = proc_PlaySound(wps); - cleanup: - return bRet; + /* error cases */ + PlaySound_Free(wps); + return FALSE; } /************************************************************************** diff --git a/dlls/winmm/winemm.h b/dlls/winmm/winemm.h index 4840b9c943a..6d7b1c399f3 100644 --- a/dlls/winmm/winemm.h +++ b/dlls/winmm/winemm.h @@ -156,14 +156,12 @@ typedef struct tagWINE_MMIO { } WINE_MMIO, *LPWINE_MMIO; typedef struct tagWINE_PLAYSOUND { - HANDLE hThread; - HANDLE hReadyEvent; - BOOL bStop; - LPCWSTR pszSound; - HMODULE hMod; - DWORD fdwSound; - BOOL bLoop; - BOOL bAlloc; + BOOL bLoop : 1, + bAlloc : 1; + LPCWSTR pszSound; + HMODULE hMod; + DWORD fdwSound; + struct tagWINE_PLAYSOUND* lpNext; } WINE_PLAYSOUND, *LPWINE_PLAYSOUND; typedef struct tagWINE_MM_IDATA { @@ -190,7 +188,9 @@ typedef struct tagWINE_MM_IDATA { /* mmio part */ LPWINE_MMIO lpMMIO; /* playsound and sndPlaySound */ - LPWINE_PLAYSOUND lpPlaySound; + WINE_PLAYSOUND* lpPlaySound; + HANDLE psLastEvent; + HANDLE psStopEvent; } WINE_MM_IDATA, *LPWINE_MM_IDATA; /* function prototypes */