No longer calling mm timers callbacks with mm timer crit sect locked.

This commit is contained in:
Eric Pouech 1999-07-15 14:34:23 +00:00 committed by Alexandre Julliard
parent fe9bdf9543
commit 5e61c20bc9
1 changed files with 86 additions and 61 deletions

View File

@ -26,39 +26,37 @@ DEFAULT_DEBUG_CHANNEL(mmtime)
#define MMSYSTIME_MININTERVAL /* (1) */ (10) #define MMSYSTIME_MININTERVAL /* (1) */ (10)
#define MMSYSTIME_MAXINTERVAL (65535) #define MMSYSTIME_MAXINTERVAL (65535)
static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer, DWORD dwCurrent) static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer, DWORD dwCurrent)
{ {
if (lpTimer->lpFunc != (FARPROC16) NULL) { TRACE("before CallBack (%lu)!\n", dwCurrent);
TRACE("before CallBack (%lu)!\n", dwCurrent); TRACE("lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
TRACE("lpFunc=%p wTimerID=%04X dwUser=%08lX !\n", lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
/* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called /* - 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 * during interrupt time, is allowed to execute very limited number of API calls (like
* PostMessage), and must reside in DLL (therefore uses stack of active application). So I * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
* guess current implementation via SetTimer has to be improved upon. * guess current implementation via SetTimer has to be improved upon.
*/ */
switch (lpTimer->wFlags & 0x30) { switch (lpTimer->wFlags & 0x30) {
case TIME_CALLBACK_FUNCTION: case TIME_CALLBACK_FUNCTION:
if (lpTimer->isWin32) if (lpTimer->wFlags & WINE_TIMER_IS32)
((LPTIMECALLBACK)lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0); ((LPTIMECALLBACK)lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0);
else else
Callbacks->CallTimeFuncProc(lpTimer->lpFunc, Callbacks->CallTimeFuncProc(lpTimer->lpFunc,
lpTimer->wTimerID, 0, lpTimer->wTimerID, 0,
lpTimer->dwUser, 0, 0); lpTimer->dwUser, 0, 0);
break; break;
case TIME_CALLBACK_EVENT_SET: case TIME_CALLBACK_EVENT_SET:
SetEvent((HANDLE)lpTimer->lpFunc); SetEvent((HANDLE)lpTimer->lpFunc);
break; break;
case TIME_CALLBACK_EVENT_PULSE: case TIME_CALLBACK_EVENT_PULSE:
PulseEvent((HANDLE)lpTimer->lpFunc); PulseEvent((HANDLE)lpTimer->lpFunc);
break; break;
default: default:
FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", lpTimer->wFlags, lpTimer->lpFunc); FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", lpTimer->wFlags, lpTimer->lpFunc);
break; break;
}
TRACE("after CallBack !\n");
} }
TRACE("after CallBack !\n");
} }
/************************************************************************** /**************************************************************************
@ -66,29 +64,45 @@ static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer, DWORD dwCurrent)
*/ */
static void CALLBACK TIME_MMSysTimeCallback(ULONG_PTR ptr_) static void CALLBACK TIME_MMSysTimeCallback(ULONG_PTR ptr_)
{ {
LPTIMERENTRY lpTimer, lpNextTimer; LPWINE_TIMERENTRY lpTimer, lpNextTimer;
LPWINE_MM_IDATA iData = (LPWINE_MM_IDATA)ptr_; LPWINE_MM_IDATA iData = (LPWINE_MM_IDATA)ptr_;
int idx;
iData->mmSysTimeMS += MMSYSTIME_MININTERVAL; iData->mmSysTimeMS += MMSYSTIME_MININTERVAL;
/* this is a hack... /* since timeSetEvent() and timeKillEvent() can be called
* since timeSetEvent() and timeKillEvent() can be called
* from 16 bit code, there are cases where win16 lock is * from 16 bit code, there are cases where win16 lock is
* locked upon entering timeSetEvent(), and then the process * locked upon entering timeSetEvent(), and then the mm timer
* heap is locked. OTOH, in this callback the process heap * critical section is locked. This function cannot call the
* is first locked, and the win16 lock can be locked while * timer callback with the crit sect locked (because callback
* calling a client callback. to avoid deadlocks, the process * may need to acquire Win16 lock, thus providing a deadlock
* heap and win 16 lock must always be locked in the same * situation).
* order... * 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
*/ */
SYSLEVEL_EnterWin16Lock(); idx = 0;
EnterCriticalSection(&iData->cs);
EnterCriticalSection(&iData->cs);
for (lpTimer = iData->lpTimerList; lpTimer != NULL; ) { for (lpTimer = iData->lpTimerList; lpTimer != NULL; ) {
lpNextTimer = lpTimer->lpNext; lpNextTimer = lpTimer->lpNext;
if (lpTimer->wCurTime < MMSYSTIME_MININTERVAL) { if (lpTimer->wCurTime < MMSYSTIME_MININTERVAL) {
lpTimer->wCurTime = lpTimer->wDelay; /* since lpTimer->wDelay is >= MININTERVAL, wCurTime value
TIME_TriggerCallBack(lpTimer, iData->mmSysTimeMS); * shall be correct (>= 0)
*/
lpTimer->wCurTime += lpTimer->wDelay - MMSYSTIME_MININTERVAL;
if (lpTimer->lpFunc) {
if (idx == iData->nSizeLpTimers) {
iData->lpTimers = (LPWINE_TIMERENTRY)
HeapReAlloc(GetProcessHeap(), 0,
iData->lpTimers,
++iData->nSizeLpTimers * sizeof(WINE_TIMERENTRY));
}
iData->lpTimers[idx++] = *lpTimer;
}
if (lpTimer->wFlags & TIME_ONESHOT) if (lpTimer->wFlags & TIME_ONESHOT)
timeKillEvent(lpTimer->wTimerID); timeKillEvent(lpTimer->wTimerID);
} else { } else {
@ -96,9 +110,11 @@ static void CALLBACK TIME_MMSysTimeCallback(ULONG_PTR ptr_)
} }
lpTimer = lpNextTimer; lpTimer = lpNextTimer;
} }
LeaveCriticalSection(&iData->cs); LeaveCriticalSection(&iData->cs);
SYSLEVEL_LeaveWin16Lock();
while (idx > 0) {
TIME_TriggerCallBack(iData->lpTimers + --idx, iData->mmSysTimeMS);
}
} }
/************************************************************************** /**************************************************************************
@ -177,20 +193,22 @@ MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize)
* timeSetEventInternal [internal] * timeSetEventInternal [internal]
*/ */
static WORD timeSetEventInternal(UINT wDelay, UINT wResol, static WORD timeSetEventInternal(UINT wDelay, UINT wResol,
FARPROC16 lpFunc, DWORD dwUser, FARPROC16 lpFunc, DWORD dwUser, UINT wFlags)
UINT wFlags, UINT16 isWin32)
{ {
WORD wNewID = 0; WORD wNewID = 0;
LPTIMERENTRY lpNewTimer; LPWINE_TIMERENTRY lpNewTimer;
LPTIMERENTRY lpTimer; LPWINE_TIMERENTRY lpTimer;
LPWINE_MM_IDATA iData; LPWINE_MM_IDATA iData;
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)HeapAlloc(GetProcessHeap(), 0, sizeof(TIMERENTRY)); lpNewTimer = (LPWINE_TIMERENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY));
if (lpNewTimer == NULL) if (lpNewTimer == NULL)
return 0; return 0;
if (wDelay < MMSYSTIME_MININTERVAL || wDelay > MMSYSTIME_MAXINTERVAL)
return 0;
iData = MULTIMEDIA_MMTimeStart(); iData = MULTIMEDIA_MMTimeStart();
if (!iData) if (!iData)
@ -200,7 +218,6 @@ static WORD timeSetEventInternal(UINT wDelay, UINT wResol,
lpNewTimer->wDelay = wDelay; lpNewTimer->wDelay = wDelay;
lpNewTimer->wResol = wResol; lpNewTimer->wResol = wResol;
lpNewTimer->lpFunc = lpFunc; lpNewTimer->lpFunc = lpFunc;
lpNewTimer->isWin32 = isWin32;
lpNewTimer->dwUser = dwUser; lpNewTimer->dwUser = dwUser;
lpNewTimer->wFlags = wFlags; lpNewTimer->wFlags = wFlags;
@ -227,7 +244,11 @@ static WORD timeSetEventInternal(UINT wDelay, UINT wResol,
MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
DWORD dwUser, UINT wFlags) DWORD dwUser, UINT wFlags)
{ {
return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc, dwUser, wFlags, 1); if (wFlags & WINE_TIMER_IS32)
WARN("Unknown windows flag... wine internally used.. ooch\n");
return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc,
dwUser, wFlags|WINE_TIMER_IS32);
} }
/************************************************************************** /**************************************************************************
@ -236,7 +257,11 @@ MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc, MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc,
DWORD dwUser, UINT16 wFlags) DWORD dwUser, UINT16 wFlags)
{ {
return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc, dwUser, wFlags, 0); if (wFlags & WINE_TIMER_IS32)
WARN("Unknown windows flag... wine internally used.. ooch\n");
return timeSetEventInternal(wDelay, wResol, (FARPROC16)lpFunc,
dwUser, wFlags & ~WINE_TIMER_IS32);
} }
/************************************************************************** /**************************************************************************
@ -244,24 +269,24 @@ MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16
*/ */
MMRESULT WINAPI timeKillEvent(UINT wID) MMRESULT WINAPI timeKillEvent(UINT wID)
{ {
LPTIMERENTRY* lpTimer; LPWINE_TIMERENTRY* lpTimer;
LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData(); LPWINE_MM_IDATA iData = MULTIMEDIA_GetIData();
MMRESULT ret = MMSYSERR_INVALPARAM; MMRESULT ret = MMSYSERR_INVALPARAM;
EnterCriticalSection(&iData->cs); EnterCriticalSection(&iData->cs);
/* remove WINE_TIMERENTRY from list */
for (lpTimer = &iData->lpTimerList; *lpTimer; lpTimer = &((*lpTimer)->lpNext)) { for (lpTimer = &iData->lpTimerList; *lpTimer; lpTimer = &((*lpTimer)->lpNext)) {
if (wID == (*lpTimer)->wTimerID) { if (wID == (*lpTimer)->wTimerID) {
LPTIMERENTRY xlptimer = (*lpTimer)->lpNext; *lpTimer = (*lpTimer)->lpNext;
HeapFree(GetProcessHeap(), 0, *lpTimer);
*lpTimer = xlptimer;
ret = TIMERR_NOERROR;
break; break;
} }
} }
LeaveCriticalSection(&iData->cs); LeaveCriticalSection(&iData->cs);
if (*lpTimer) {
HeapFree(GetProcessHeap(), 0, *lpTimer);
ret = TIMERR_NOERROR;
}
return ret; return ret;
} }