diff --git a/dlls/winmm/mmsystem.c b/dlls/winmm/mmsystem.c index d13ff1b43e2..bef26db50d7 100644 --- a/dlls/winmm/mmsystem.c +++ b/dlls/winmm/mmsystem.c @@ -2529,7 +2529,7 @@ MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize) if (wSize >= sizeof(*lpTime)) { lpTime->wType = TIME_MS; TIME_MMTimeStart(); - lpTime->u.ms = WINMM_IData->mmSysTimeMS; + lpTime->u.ms = WINMM_SysTimeMS; TRACE("=> %lu\n", lpTime->u.ms); } diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c index c8540bac083..a6148836be2 100644 --- a/dlls/winmm/time.c +++ b/dlls/winmm/time.c @@ -42,6 +42,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(mmtime); +static HANDLE TIME_hMMTimer; +static LPWINE_TIMERENTRY TIME_TimersList; +static HANDLE TIME_hKillEvent; +DWORD WINMM_SysTimeMS; + /* * FIXME * We're using "1" as the mininum resolution to the timer, @@ -90,15 +95,18 @@ static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer) */ static void CALLBACK TIME_MMSysTimeCallback(LPWINE_MM_IDATA iData) { - LPWINE_TIMERENTRY lpTimer, lpNextTimer; - DWORD delta = GetTickCount() - iData->mmSysTimeMS; +static int nSizeLpTimers; +static LPWINE_TIMERENTRY lpTimers; + + LPWINE_TIMERENTRY timer, *ptimer, *next_ptimer; + DWORD delta = GetTickCount() - WINMM_SysTimeMS; int idx; TRACE("Time delta: %ld\n", delta); while (delta >= MMSYSTIME_MININTERVAL) { delta -= MMSYSTIME_MININTERVAL; - iData->mmSysTimeMS += MMSYSTIME_MININTERVAL; + WINMM_SysTimeMS += MMSYSTIME_MININTERVAL; /* since timeSetEvent() and timeKillEvent() can be called * from 16 bit code, there are cases where win16 lock is @@ -109,48 +117,52 @@ static void CALLBACK TIME_MMSysTimeCallback(LPWINE_MM_IDATA iData) * situation). * To cope with that, we just copy the WINE_TIMERENTRY struct * that need to trigger the callback, and call it without the - * mm timer crit sect locked. The bad side of this - * implementation is that, in some cases, the callback may be - * invoked *after* a timer has been destroyed... - * EPP 99/07/13 + * mm timer crit sect locked. + * the hKillTimeEvent is used to mark the section where we + * handle the callbacks so we can do synchronous kills. + * EPP 99/07/13, updated 04/01/10 */ idx = 0; EnterCriticalSection(&iData->cs); - for (lpTimer = iData->lpTimerList; lpTimer != NULL; ) { - lpNextTimer = lpTimer->lpNext; - if (lpTimer->uCurTime < MMSYSTIME_MININTERVAL) { + for (ptimer = &TIME_TimersList; *ptimer != NULL; ) { + timer = *ptimer; + next_ptimer = &timer->lpNext; + if (timer->uCurTime < MMSYSTIME_MININTERVAL) { /* since lpTimer->wDelay is >= MININTERVAL, wCurTime value * shall be correct (>= 0) */ - lpTimer->uCurTime += lpTimer->wDelay - MMSYSTIME_MININTERVAL; - if (lpTimer->lpFunc) { - if (idx == iData->nSizeLpTimers) { - if (iData->lpTimers) - iData->lpTimers = (LPWINE_TIMERENTRY) - HeapReAlloc(GetProcessHeap(), 0, - iData->lpTimers, - ++iData->nSizeLpTimers * sizeof(WINE_TIMERENTRY)); + timer->uCurTime += timer->wDelay - MMSYSTIME_MININTERVAL; + if (timer->lpFunc) { + if (idx == nSizeLpTimers) { + if (lpTimers) + lpTimers = (LPWINE_TIMERENTRY) + HeapReAlloc(GetProcessHeap(), 0, lpTimers, + ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); else - iData->lpTimers = (LPWINE_TIMERENTRY) + lpTimers = (LPWINE_TIMERENTRY) HeapAlloc(GetProcessHeap(), 0, - ++iData->nSizeLpTimers * sizeof(WINE_TIMERENTRY)); + ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); } - iData->lpTimers[idx++] = *lpTimer; + lpTimers[idx++] = *timer; } /* TIME_ONESHOT is defined as 0 */ - if (!(lpTimer->wFlags & TIME_PERIODIC)) - timeKillEvent(lpTimer->wTimerID); + if (!(timer->wFlags & TIME_PERIODIC)) + { + /* unlink timer from timers list */ + *ptimer = *next_ptimer; + HeapFree(GetProcessHeap(), 0, timer); + } } else { - lpTimer->uCurTime -= MMSYSTIME_MININTERVAL; + timer->uCurTime -= MMSYSTIME_MININTERVAL; } - lpTimer = lpNextTimer; + ptimer = next_ptimer; } + if (TIME_hKillEvent) ResetEvent(TIME_hKillEvent); LeaveCriticalSection(&iData->cs); - while (idx > 0) { - TIME_TriggerCallBack(&iData->lpTimers[--idx]); - } + while (idx > 0) TIME_TriggerCallBack(&lpTimers[--idx]); + if (TIME_hKillEvent) SetEvent(TIME_hKillEvent); } } @@ -160,7 +172,7 @@ static void CALLBACK TIME_MMSysTimeCallback(LPWINE_MM_IDATA iData) static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg) { LPWINE_MM_IDATA iData = (LPWINE_MM_IDATA)arg; - volatile HANDLE *pActive = (volatile HANDLE *)&iData->hMMTimer; + volatile HANDLE *pActive = (volatile HANDLE *)&TIME_hMMTimer; DWORD last_time, cur_time; usleep(MMSYSTIME_STDINTERVAL * 1000); @@ -184,10 +196,10 @@ void TIME_MMTimeStart(void) * mm timers are active, but this would require to keep mmSysTimeMS up-to-date * without being incremented within the service thread callback. */ - if (!WINMM_IData->hMMTimer) { - WINMM_IData->mmSysTimeMS = GetTickCount(); - WINMM_IData->lpTimerList = NULL; - WINMM_IData->hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, WINMM_IData, 0, NULL); + if (!TIME_hMMTimer) { + WINMM_SysTimeMS = GetTickCount(); + TIME_TimersList = NULL; + TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, WINMM_IData, 0, NULL); } } @@ -196,9 +208,10 @@ void TIME_MMTimeStart(void) */ void TIME_MMTimeStop(void) { - if (WINMM_IData->hMMTimer) { - HANDLE hMMTimer = WINMM_IData->hMMTimer; - WINMM_IData->hMMTimer = 0; + /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */ + if (TIME_hMMTimer) { + HANDLE hMMTimer = TIME_hMMTimer; + TIME_hMMTimer = 0; WaitForSingleObject(hMMTimer, INFINITE); CloseHandle(hMMTimer); } @@ -214,7 +227,7 @@ MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize) if (wSize >= sizeof(*lpTime)) { TIME_MMTimeStart(); lpTime->wType = TIME_MS; - lpTime->u.ms = WINMM_IData->mmSysTimeMS; + lpTime->u.ms = WINMM_SysTimeMS; TRACE("=> %lu\n", lpTime->u.ms); } @@ -252,12 +265,15 @@ WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, EnterCriticalSection(&WINMM_IData->cs); - for (lpTimer = WINMM_IData->lpTimerList; lpTimer != NULL; lpTimer = lpTimer->lpNext) { + if ((wFlags & TIME_KILL_SYNCHRONOUS) && !TIME_hKillEvent) + TIME_hKillEvent = CreateEventW(NULL, TRUE, TRUE, NULL); + + for (lpTimer = TIME_TimersList; lpTimer != NULL; lpTimer = lpTimer->lpNext) { wNewID = max(wNewID, lpTimer->wTimerID); } - lpNewTimer->lpNext = WINMM_IData->lpTimerList; - WINMM_IData->lpTimerList = lpNewTimer; + lpNewTimer->lpNext = TIME_TimersList; + TIME_TimersList = lpNewTimer; lpNewTimer->wTimerID = wNewID + 1; LeaveCriticalSection(&WINMM_IData->cs); @@ -285,31 +301,30 @@ MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, */ MMRESULT WINAPI timeKillEvent(UINT wID) { - LPWINE_TIMERENTRY* lpTimer; - MMRESULT ret = MMSYSERR_INVALPARAM; + LPWINE_TIMERENTRY lpSelf = NULL, *lpTimer; TRACE("(%u)\n", wID); EnterCriticalSection(&WINMM_IData->cs); /* remove WINE_TIMERENTRY from list */ - for (lpTimer = &WINMM_IData->lpTimerList; *lpTimer; lpTimer = &(*lpTimer)->lpNext) { + for (lpTimer = &TIME_TimersList; *lpTimer; lpTimer = &(*lpTimer)->lpNext) { if (wID == (*lpTimer)->wTimerID) { + lpSelf = *lpTimer; + /* unlink timer of id 'wID' */ + *lpTimer = (*lpTimer)->lpNext; break; } } LeaveCriticalSection(&WINMM_IData->cs); - if (*lpTimer) { - LPWINE_TIMERENTRY lpTemp = *lpTimer; - - /* unlink timer of id 'wID' */ - *lpTimer = (*lpTimer)->lpNext; - HeapFree(GetProcessHeap(), 0, lpTemp); - ret = TIMERR_NOERROR; - } else { - WARN("wID=%u is not a valid timer ID\n", wID); + if (!lpSelf) + { + WARN("wID=%u is not a valid timer ID\n", wID); + return MMSYSERR_INVALPARAM; } - - return ret; + if (lpSelf->wFlags & TIME_KILL_SYNCHRONOUS) + WaitForSingleObject(TIME_hKillEvent, INFINITE); + HeapFree(GetProcessHeap(), 0, lpSelf); + return TIMERR_NOERROR; } /************************************************************************** @@ -361,5 +376,5 @@ DWORD WINAPI timeGetTime(void) if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); TIME_MMTimeStart(); if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); - return WINMM_IData->mmSysTimeMS; + return WINMM_SysTimeMS; } diff --git a/dlls/winmm/winemm.h b/dlls/winmm/winemm.h index 12f1642b0b9..5ed142365c1 100644 --- a/dlls/winmm/winemm.h +++ b/dlls/winmm/winemm.h @@ -201,12 +201,6 @@ typedef struct tagWINE_MM_IDATA { HANDLE hWinMM32Instance; HANDLE hWinMM16Instance; CRITICAL_SECTION cs; - /* mm timer part */ - HANDLE hMMTimer; - DWORD mmSysTimeMS; - LPWINE_TIMERENTRY lpTimerList; - int nSizeLpTimers; - LPWINE_TIMERENTRY lpTimers; /* mci part */ LPWINE_MCIDRIVER lpMciDrvs; /* low level drivers (unused yet) */ @@ -242,7 +236,7 @@ DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwParam2); DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg); LPWINE_MLD MMDRV_Get(HANDLE hndl, UINT type, BOOL bCanBeID); LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, BOOL bSrcCanBeID, UINT dstTyped); -DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, BOOL bFrom32); +DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, BOOL bFrom32); UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, DWORD dwParam2); BOOL MMDRV_Is32(unsigned int); void MMDRV_InstallMap(unsigned int, MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, @@ -290,6 +284,7 @@ void TIME_MMTimeStop(void); /* Global variables */ extern LPWINE_MM_IDATA WINMM_IData; +extern DWORD WINMM_SysTimeMS; /* pointers to 16 bit functions (if sibling MMSYSTEM.DLL is loaded * NULL otherwise