Piotr Caban : winmm: Avoid allocations in timeSetEvent.

Alexandre Julliard julliard at winehq.org
Wed Sep 30 14:35:31 CDT 2020


Module: wine
Branch: master
Commit: b07504224e05bd104e9ad4f1fef7980c64ab2148
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=b07504224e05bd104e9ad4f1fef7980c64ab2148

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Wed Sep 30 14:37:52 2020 +0200

winmm: Avoid allocations in timeSetEvent.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winmm/time.c | 122 ++++++++++++++++++++++++------------------------------
 1 file changed, 55 insertions(+), 67 deletions(-)

diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c
index 814d97def0..2d5f3db389 100644
--- a/dlls/winmm/time.c
+++ b/dlls/winmm/time.c
@@ -30,13 +30,11 @@
 
 #include "winemm.h"
 
-#include "wine/list.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(mmtime);
 
 typedef struct tagWINE_TIMERENTRY {
-    struct list                 entry;
     UINT                        wDelay;
     UINT                        wResol;
     LPTIMECALLBACK              lpFunc; /* can be lots of things */
@@ -46,7 +44,8 @@ typedef struct tagWINE_TIMERENTRY {
     DWORD                       dwTriggerTime;
 } WINE_TIMERENTRY, *LPWINE_TIMERENTRY;
 
-static struct list timer_list = LIST_INIT(timer_list);
+static WINE_TIMERENTRY timers[16];
+static UINT timers_created;
 
 static CRITICAL_SECTION TIME_cbcrst;
 static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -60,17 +59,6 @@ static CRITICAL_SECTION TIME_cbcrst = { &critsect_debug, -1, 0, 0, 0, 0 };
 static    HANDLE                TIME_hMMTimer;
 static    CONDITION_VARIABLE    TIME_cv;
 
-/* link timer at the appropriate spot in the list */
-static inline void link_timer( WINE_TIMERENTRY *timer )
-{
-    WINE_TIMERENTRY *next;
-
-    LIST_FOR_EACH_ENTRY( next, &timer_list, WINE_TIMERENTRY, entry )
-        if ((int)(next->dwTriggerTime - timer->dwTriggerTime) >= 0) break;
-
-    list_add_before( &next->entry, &timer->entry );
-}
-
 /*
  * Some observations on the behavior of winmm on Windows.
  *
@@ -119,8 +107,8 @@ static inline void link_timer( WINE_TIMERENTRY *timer )
  */
 static int TIME_MMSysTimeCallback(void)
 {
-    WINE_TIMERENTRY *timer, *to_free;
-    int delta_time;
+    WINE_TIMERENTRY *timer, copy;
+    int i, delta_time;
 
     /* since timeSetEvent() and timeKillEvent() can be called
      * from 16 bit code, there are cases where win16 lock is
@@ -136,25 +124,30 @@ static int TIME_MMSysTimeCallback(void)
 
     for (;;)
     {
-        struct list *ptr = list_head( &timer_list );
-        if (!ptr)
+        for (i = 0; i < ARRAY_SIZE(timers); i++)
+            if (timers[i].wTimerID) break;
+        if (i == ARRAY_SIZE(timers)) return -1;
+        timer = timers + i;
+        for (i++; i < ARRAY_SIZE(timers); i++)
         {
-            delta_time = -1;
-            break;
+            if (!timers[i].wTimerID) continue;
+            if (timers[i].dwTriggerTime < timer->dwTriggerTime)
+                timer = timers + i;
         }
 
-        timer = LIST_ENTRY( ptr, WINE_TIMERENTRY, entry );
         delta_time = timer->dwTriggerTime - timeGetTime();
         if (delta_time > 0) break;
 
-        list_remove( &timer->entry );
         if (timer->wFlags & TIME_PERIODIC)
         {
             timer->dwTriggerTime += timer->wDelay;
-            link_timer( timer );  /* restart it */
-            to_free = NULL;
         }
-        else to_free = timer;
+        else
+        {
+            copy = *timer;
+            timer->wTimerID = 0;
+            timer = ©
+        }
 
         switch(timer->wFlags & (TIME_CALLBACK_EVENT_SET|TIME_CALLBACK_EVENT_PULSE))
         {
@@ -181,7 +174,6 @@ static int TIME_MMSysTimeCallback(void)
             }
             break;
         }
-        HeapFree( GetProcessHeap(), 0, to_free );
     }
     return delta_time;
 }
@@ -281,36 +273,37 @@ DWORD WINAPI timeGetTime(void)
 MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
                             DWORD_PTR dwUser, UINT wFlags)
 {
-    WORD 		wNewID = 0;
-    LPWINE_TIMERENTRY	lpNewTimer;
-    LPWINE_TIMERENTRY	lpTimer;
+    WORD new_id = 0;
+    int i;
 
     TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser, wFlags);
 
     if (wDelay < MMSYSTIME_MININTERVAL || wDelay > MMSYSTIME_MAXINTERVAL)
 	return 0;
 
-    lpNewTimer = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY));
-    if (lpNewTimer == NULL)
-	return 0;
-
-    lpNewTimer->wDelay = wDelay;
-    lpNewTimer->dwTriggerTime = timeGetTime() + wDelay;
+    EnterCriticalSection(&WINMM_cs);
 
-    /* FIXME - wResol is not respected, although it is not clear
-               that we could change our precision meaningfully  */
-    lpNewTimer->wResol = wResol;
-    lpNewTimer->lpFunc = lpFunc;
-    lpNewTimer->dwUser = dwUser;
-    lpNewTimer->wFlags = wFlags;
+    for (i = 0; i < ARRAY_SIZE(timers); i++)
+        if (!timers[i].wTimerID) break;
+    if (i == ARRAY_SIZE(timers))
+    {
+        LeaveCriticalSection(&WINMM_cs);
+        return 0;
+    }
 
-    EnterCriticalSection(&WINMM_cs);
+    new_id = ARRAY_SIZE(timers)*(++timers_created) + i;
+    if (!new_id) new_id = ARRAY_SIZE(timers)*(++timers_created) + i;
 
-    LIST_FOR_EACH_ENTRY( lpTimer, &timer_list, WINE_TIMERENTRY, entry )
-        wNewID = max(wNewID, lpTimer->wTimerID);
+    timers[i].wDelay = wDelay;
+    timers[i].dwTriggerTime = timeGetTime() + wDelay;
 
-    link_timer( lpNewTimer );
-    lpNewTimer->wTimerID = wNewID + 1;
+    /* FIXME - wResol is not respected, although it is not clear
+       that we could change our precision meaningfully  */
+    timers[i].wResol = wResol;
+    timers[i].lpFunc = lpFunc;
+    timers[i].dwUser = dwUser;
+    timers[i].wFlags = wFlags;
+    timers[i].wTimerID = new_id;
 
     TIME_MMTimeStart();
 
@@ -319,9 +312,9 @@ MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
     /* Wake the service thread in case there is work to be done */
     WakeConditionVariable(&TIME_cv);
 
-    TRACE("=> %u\n", wNewID + 1);
+    TRACE("=> %u\n", new_id);
 
-    return wNewID + 1;
+    return new_id;
 }
 
 /**************************************************************************
@@ -329,35 +322,30 @@ MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
  */
 MMRESULT WINAPI timeKillEvent(UINT wID)
 {
-    WINE_TIMERENTRY *lpSelf = NULL, *lpTimer;
-    DWORD wFlags;
+    WINE_TIMERENTRY *timer;
+    WORD flags;
 
     TRACE("(%u)\n", wID);
     EnterCriticalSection(&WINMM_cs);
-    /* remove WINE_TIMERENTRY from list */
-    LIST_FOR_EACH_ENTRY( lpTimer, &timer_list, WINE_TIMERENTRY, entry )
+
+    timer = &timers[wID % ARRAY_SIZE(timers)];
+    if (timer->wTimerID != wID)
     {
-	if (wID == lpTimer->wTimerID) {
-            lpSelf = lpTimer;
-            list_remove( &lpTimer->entry );
-	    break;
-	}
+        LeaveCriticalSection(&WINMM_cs);
+        WARN("wID=%u is not a valid timer ID\n", wID);
+        return TIMERR_NOCANDO;
     }
-    if (list_empty(&timer_list))
-        WakeConditionVariable(&TIME_cv);
+
+    timer->wTimerID = 0;
+    flags = timer->wFlags;
     LeaveCriticalSection(&WINMM_cs);
 
-    if (!lpSelf)
+    if (flags & TIME_KILL_SYNCHRONOUS)
     {
-        WARN("wID=%u is not a valid timer ID\n", wID);
-        return MMSYSERR_INVALPARAM;
-    }
-    wFlags = lpSelf->wFlags;
-    if (wFlags & TIME_KILL_SYNCHRONOUS)
         EnterCriticalSection(&TIME_cbcrst);
-    HeapFree(GetProcessHeap(), 0, lpSelf);
-    if (wFlags & TIME_KILL_SYNCHRONOUS)
         LeaveCriticalSection(&TIME_cbcrst);
+    }
+    WakeConditionVariable(&TIME_cv);
     return TIMERR_NOERROR;
 }
 




More information about the wine-cvs mailing list