mm timer

Eric Pouech pouech-eric at wanadoo.fr
Sat Jan 10 10:34:23 CST 2004


A+
-------------- next part --------------
Name:          mmtime
ChangeLog:     
	- implemented TIME_KILL_SYCHRONOUS timer flags
	- timeKillTimer is now thread safe
	- replaced some iData attributes by global variables
License:       X11
GenDate:       2004/01/10 16:30:57 UTC
ModifiedFiles: dlls/winmm/winemm.h dlls/winmm/mmsystem.c dlls/winmm/time.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/winemm.h,v
retrieving revision 1.53
diff -u -u -r1.53 winemm.h
--- dlls/winmm/winemm.h	6 Jan 2004 22:08:33 -0000	1.53
+++ dlls/winmm/winemm.h	10 Jan 2004 13:13:49 -0000
@@ -201,12 +201,6 @@
     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_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 @@
 
 /* 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
Index: dlls/winmm/mmsystem.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/mmsystem.c,v
retrieving revision 1.105
diff -u -u -r1.105 mmsystem.c
--- dlls/winmm/mmsystem.c	31 Dec 2003 23:49:45 -0000	1.105
+++ dlls/winmm/mmsystem.c	10 Jan 2004 13:05:08 -0000
@@ -2529,7 +2529,7 @@
     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);
     }
Index: dlls/winmm/time.c
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/time.c,v
retrieving revision 1.25
diff -u -u -r1.25 time.c
--- dlls/winmm/time.c	31 Dec 2003 23:49:45 -0000	1.25
+++ dlls/winmm/time.c	10 Jan 2004 16:29:08 -0000
@@ -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 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 @@
 	 * 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 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 @@
      * 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_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 @@
     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 @@
 
     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 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 @@
     if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
     TIME_MMTimeStart();
     if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
-    return WINMM_IData->mmSysTimeMS;
+    return WINMM_SysTimeMS;
 }


More information about the wine-patches mailing list