diff --git a/multimedia/time.c b/multimedia/time.c index 3d85130395d..4f3646d58a9 100644 --- a/multimedia/time.c +++ b/multimedia/time.c @@ -7,23 +7,17 @@ */ #include -#include #include #include #include "winbase.h" #include "wine/winbase16.h" /* GetTaskDS */ #include "callback.h" #include "mmsystem.h" -#include "xmalloc.h" #include "services.h" -#include "options.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(mmtime) -static MMTIME16 mmSysTimeMS; -static MMTIME16 mmSysTimeSMPTE; - typedef struct tagTIMERENTRY { UINT wDelay; UINT wResol; @@ -34,11 +28,13 @@ typedef struct tagTIMERENTRY { UINT wTimerID; UINT wCurTime; UINT isWin32; - struct tagTIMERENTRY* Next; + struct tagTIMERENTRY* lpNext; } TIMERENTRY, *LPTIMERENTRY; -static LPTIMERENTRY lpTimerList = NULL; -static HANDLE hMMTimer; +static DWORD mmSysTimeMS; +static LPTIMERENTRY lpTimerList = NULL; +static HANDLE hMMTimer = 0; +CRITICAL_SECTION mmTimeCritSect; /* * FIXME @@ -51,14 +47,11 @@ static HANDLE hMMTimer; static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer, DWORD dwCurrent) { - lpTimer->wCurTime = lpTimer->wDelay; - if (lpTimer->lpFunc != (FARPROC16) NULL) { - TRACE("before CallBack16 (%lu)!\n", dwCurrent); + TRACE("before CallBack (%lu)!\n", dwCurrent); TRACE("lpFunc=%p wTimerID=%04X dwUser=%08lX !\n", lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser); - TRACE("hInstance=%04X !\n", lpTimer->hInstance); - + TRACE("hInstance=%04X !\n", lpTimer->hInstance); /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called * during interrupt time, is allowed to execute very limited number of API calls (like @@ -67,46 +60,52 @@ static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer, DWORD dwCurrent) */ switch (lpTimer->wFlags & 0x30) { case TIME_CALLBACK_FUNCTION: - if (lpTimer->isWin32) - lpTimer->lpFunc(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0); - else - Callbacks->CallTimeFuncProc(lpTimer->lpFunc, - lpTimer->wTimerID, 0, - lpTimer->dwUser, 0, 0); - break; + if (lpTimer->isWin32) + ((LPTIMECALLBACK)lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0); + else + Callbacks->CallTimeFuncProc(lpTimer->lpFunc, + lpTimer->wTimerID, 0, + lpTimer->dwUser, 0, 0); + break; case TIME_CALLBACK_EVENT_SET: - SetEvent((HANDLE)lpTimer->lpFunc); - break; + SetEvent((HANDLE)lpTimer->lpFunc); + break; case TIME_CALLBACK_EVENT_PULSE: - PulseEvent((HANDLE)lpTimer->lpFunc); - break; + PulseEvent((HANDLE)lpTimer->lpFunc); + break; default: - FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", lpTimer->wFlags, lpTimer->lpFunc); - break; + FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", lpTimer->wFlags, lpTimer->lpFunc); + break; } - TRACE("after CallBack16 !\n"); + TRACE("after CallBack !\n"); } - if (lpTimer->wFlags & TIME_ONESHOT) - timeKillEvent(lpTimer->wTimerID); } /************************************************************************** * TIME_MMSysTimeCallback */ -static VOID CALLBACK TIME_MMSysTimeCallback( ULONG_PTR dummy ) +static void CALLBACK TIME_MMSysTimeCallback( ULONG_PTR dummy ) { - LPTIMERENTRY lpTimer; - - mmSysTimeMS.u.ms += MMSYSTIME_MININTERVAL; - mmSysTimeSMPTE.u.smpte.frame++; - - for (lpTimer = lpTimerList; lpTimer != NULL; lpTimer = lpTimer->Next) { + LPTIMERENTRY lpTimer, lpNextTimer; + + mmSysTimeMS += MMSYSTIME_MININTERVAL; + + EnterCriticalSection(&mmTimeCritSect); + + for (lpTimer = lpTimerList; lpTimer != NULL; ) { + lpNextTimer = lpTimer->lpNext; if (lpTimer->wCurTime < MMSYSTIME_MININTERVAL) { - TIME_TriggerCallBack(lpTimer, mmSysTimeMS.u.ms); + lpTimer->wCurTime = lpTimer->wDelay; + TIME_TriggerCallBack(lpTimer, mmSysTimeMS); + if (lpTimer->wFlags & TIME_ONESHOT) + timeKillEvent(lpTimer->wTimerID); } else { lpTimer->wCurTime -= MMSYSTIME_MININTERVAL; } + lpTimer = lpNextTimer; } + + LeaveCriticalSection(&mmTimeCritSect); } /************************************************************************** @@ -114,20 +113,29 @@ static VOID CALLBACK TIME_MMSysTimeCallback( ULONG_PTR dummy ) */ BOOL MULTIMEDIA_MMTimeInit(void) { - mmSysTimeMS.wType = TIME_MS; - mmSysTimeMS.u.ms = GetTickCount(); - mmSysTimeSMPTE.wType = TIME_SMPTE; - mmSysTimeSMPTE.u.smpte.hour = 0; - mmSysTimeSMPTE.u.smpte.min = 0; - mmSysTimeSMPTE.u.smpte.sec = 0; - mmSysTimeSMPTE.u.smpte.frame = 0; - mmSysTimeSMPTE.u.smpte.fps = 0; - mmSysTimeSMPTE.u.smpte.dummy = 0; - hMMTimer = SERVICE_AddTimer( MMSYSTIME_MININTERVAL*1000L, TIME_MMSysTimeCallback, 0 ); + InitializeCriticalSection(&mmTimeCritSect); + MakeCriticalSectionGlobal(&mmTimeCritSect); return TRUE; } +/************************************************************************** + * MULTIMEDIA_MMTimeStart [internal] + */ +static BOOL MULTIMEDIA_MMTimeStart(void) +{ + /* one could think it's possible to stop the service thread activity when no more + * mm timers are active, but this would require to handle delta (in time) between + * GetTickCount() and timeGetTime() which are not -currently- synchronized. + */ + if (!hMMTimer) { + mmSysTimeMS = GetTickCount(); + hMMTimer = SERVICE_AddTimer( MMSYSTIME_MININTERVAL*1000L, TIME_MMSysTimeCallback, 0 ); + } + + return TRUE; +} + /************************************************************************** * timeGetSystemTime [WINMM.140] */ @@ -135,10 +143,13 @@ MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize) { TRACE("(%p, %u);\n", lpTime, wSize); - lpTime->wType = TIME_MS; - lpTime->u.ms = mmSysTimeMS.u.ms; + if (wSize >= sizeof(*lpTime)) { + MULTIMEDIA_MMTimeStart(); + lpTime->wType = TIME_MS; + lpTime->u.ms = mmSysTimeMS; - TRACE("=> %lu\n", mmSysTimeMS.u.ms); + TRACE("=> %lu\n", mmSysTimeMS); + } return 0; } @@ -150,10 +161,13 @@ MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize) { TRACE("(%p, %u);\n", lpTime, wSize); - lpTime->wType = TIME_MS; - lpTime->u.ms = mmSysTimeMS.u.ms; + if (wSize >= sizeof(*lpTime)) { + MULTIMEDIA_MMTimeStart(); + lpTime->wType = TIME_MS; + lpTime->u.ms = mmSysTimeMS; - TRACE("=> %lu\n", mmSysTimeMS.u.ms); + TRACE("=> %lu\n", mmSysTimeMS); + } return 0; } @@ -167,55 +181,58 @@ static WORD timeSetEventInternal(UINT wDelay, UINT wResol, { WORD wNewID = 0; LPTIMERENTRY lpNewTimer; - LPTIMERENTRY lpTimer = lpTimerList; + LPTIMERENTRY lpTimer; - TRACE("(%u, %u, %p, %08lX, %04X);\n", - wDelay, wResol, lpFunc, dwUser, wFlags); + TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser, wFlags); - lpNewTimer = (LPTIMERENTRY)xmalloc(sizeof(TIMERENTRY)); + lpNewTimer = (LPTIMERENTRY)malloc(sizeof(TIMERENTRY)); if (lpNewTimer == NULL) return 0; - while (lpTimer != NULL) { - wNewID = MAX(wNewID, lpTimer->wTimerID); - lpTimer = lpTimer->Next; - } - - lpNewTimer->Next = lpTimerList; - lpTimerList = lpNewTimer; - lpNewTimer->wTimerID = wNewID + 1; + + MULTIMEDIA_MMTimeStart(); + lpNewTimer->wCurTime = wDelay; lpNewTimer->wDelay = wDelay; lpNewTimer->wResol = wResol; lpNewTimer->lpFunc = lpFunc; lpNewTimer->isWin32 = isWin32; lpNewTimer->hInstance = GetTaskDS16(); - TRACE("hInstance=%04X !\n", lpNewTimer->hInstance); - TRACE("lpFunc=0x%08lx !\n", (DWORD)lpFunc ); lpNewTimer->dwUser = dwUser; lpNewTimer->wFlags = wFlags; - return lpNewTimer->wTimerID; + + TRACE("hInstance=%04X,lpFunc=0x%08lx !\n", lpNewTimer->hInstance, (DWORD)lpFunc); + + EnterCriticalSection(&mmTimeCritSect); + + for (lpTimer = lpTimerList; lpTimer != NULL; lpTimer = lpTimer->lpNext) { + wNewID = MAX(wNewID, lpTimer->wTimerID); + } + + lpNewTimer->lpNext = lpTimerList; + lpTimerList = lpNewTimer; + lpNewTimer->wTimerID = wNewID + 1; + + LeaveCriticalSection(&mmTimeCritSect); + + return wNewID + 1; } /************************************************************************** * timeSetEvent [MMSYSTEM.602] */ -MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, - LPTIMECALLBACK lpFunc, DWORD dwUser, - UINT wFlags) +MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, + DWORD dwUser, UINT wFlags) { - return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc, - dwUser, wFlags, 1); + return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc, dwUser, wFlags, 1); } /************************************************************************** * timeSetEvent [MMSYSTEM.602] */ -MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, - LPTIMECALLBACK16 lpFunc, DWORD dwUser, - UINT16 wFlags) +MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc, + DWORD dwUser, UINT16 wFlags) { - return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc, - dwUser, wFlags, 0); + return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc, dwUser, wFlags, 0); } /************************************************************************** @@ -224,17 +241,24 @@ MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, MMRESULT WINAPI timeKillEvent(UINT wID) { LPTIMERENTRY* lpTimer; - - for (lpTimer = &lpTimerList; *lpTimer; lpTimer = &((*lpTimer)->Next)) { + MMRESULT ret = MMSYSERR_INVALPARAM; + + EnterCriticalSection(&mmTimeCritSect); + + for (lpTimer = &lpTimerList; *lpTimer; lpTimer = &((*lpTimer)->lpNext)) { if (wID == (*lpTimer)->wTimerID) { - LPTIMERENTRY xlptimer = (*lpTimer)->Next; + LPTIMERENTRY xlptimer = (*lpTimer)->lpNext; free(*lpTimer); *lpTimer = xlptimer; - return TRUE; + ret = TIMERR_NOERROR; + break; } } - return 0; + + LeaveCriticalSection(&mmTimeCritSect); + + return ret; } /************************************************************************** @@ -280,8 +304,9 @@ MMRESULT WINAPI timeBeginPeriod(UINT wPeriod) return TIMERR_NOCANDO; return 0; } + /************************************************************************** - * timeBeginPeriod [MMSYSTEM.605] + * timeBeginPeriod16 [MMSYSTEM.605] */ MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod) { @@ -305,11 +330,12 @@ MMRESULT WINAPI timeEndPeriod(UINT wPeriod) } /************************************************************************** - * timeEndPeriod [MMSYSTEM.606] + * timeEndPeriod16 [MMSYSTEM.606] */ MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod) { TRACE("(%u) !\n", wPeriod); + if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) return TIMERR_NOCANDO; return 0; @@ -320,5 +346,6 @@ MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod) */ DWORD WINAPI timeGetTime(void) { - return mmSysTimeMS.u.ms; + MULTIMEDIA_MMTimeStart(); + return mmSysTimeMS; }