winmm: Use a pipe for timer

Maarten Lankhorst m.b.lankhorst at gmail.com
Sat May 5 10:37:38 CDT 2007


This avoids expensive server calls in a time critical timer.

Without priority patch it drops stddev in winmm timer tests to < 2 ms as
compared to ~7 ms before. With priority patch it drops to < .20 ms.

Backwards compatibility code is kept just in case.
-------------- next part --------------
>From f6fe324eda8af43f41f2b1b6a610fc99b5e412ab Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date: Fri, 4 May 2007 20:56:43 +0200
Subject: [PATCH] winmm: Use fds for timers

---
 dlls/winmm/time.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 83 insertions(+), 12 deletions(-)

diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c
index 27a4e46..1a8fca2 100644
--- a/dlls/winmm/time.c
+++ b/dlls/winmm/time.c
@@ -44,7 +44,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mmtime);
 
 static    HANDLE                TIME_hMMTimer;
 static    LPWINE_TIMERENTRY 	TIME_TimersList;
-static    HANDLE                TIME_hWakeEvent;
 static    CRITICAL_SECTION      TIME_cbcrst;
 static    BOOL                  TIME_TimeToDie = TRUE;
 
@@ -77,6 +76,78 @@ static    BOOL                  TIME_TimeToDie = TRUE;
 #define MMSYSTIME_MININTERVAL (1)
 #define MMSYSTIME_MAXINTERVAL (65535)
 
+#define WINE_USE_POLL
+
+#ifdef WINE_USE_POLL
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+static int TIME_hWakeEvent[2] = { -1, -1 };
+
+static void reset_fd(int *fd)
+{
+    char readme;
+    struct pollfd pfd;
+    pfd.fd = fd[0];
+    pfd.events = POLLIN;
+    while (poll(&pfd, 1, 0) > 0)
+        read(fd[0], &readme, sizeof(readme));
+}
+
+static void set_fd(int *fd)
+{
+    char foo = 'A';
+
+    write(fd[1], &foo, sizeof(foo));
+}
+
+static void create_fd(int *fd)
+{
+    if (pipe(fd) < 0)
+        fd[0] = fd[1] = -1;
+}
+
+static void close_fd(int *fd)
+{
+    close(fd[0]);
+    close(fd[1]);
+    fd[0] = fd[1] = -1;
+}
+
+static DWORD poll_fd(int *fd, DWORD timeout)
+{
+    struct pollfd pfd;
+    pfd.fd = fd[0];
+    pfd.events = POLLIN;
+
+    switch (poll(&pfd, 1, (int)timeout))
+    {
+        case 0: return WAIT_TIMEOUT;
+        case -1: return WAIT_FAILED;
+        default: reset_fd(fd); return WAIT_OBJECT_0;
+    }
+}
+
+#define SETEVENT    set_fd
+#define CREATEEVENT create_fd
+#define CLOSEEVENT  close_fd
+#define WAITEVENT   poll_fd
+
+#else
+
+static HANDLE TIME_hWakeEvent;
+
+#define SETEVENT SetEvent
+#define CREATEEVENT(x) do { x = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
+#define CLOSEEVENT CloseHandle
+#define WAITEVENT WaitForSingleObject
+
+#endif
 
 static	void	TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer)
 {
@@ -244,9 +315,9 @@ static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg)
         if (sleep_time == 0)
             continue;
 
-        rc = WaitForSingleObject(TIME_hWakeEvent, sleep_time);
+        rc = WAITEVENT(TIME_hWakeEvent, sleep_time);
         if (rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0)
-        {   
+        {
             FIXME("Unexpected error %d(%d) in timer thread\n", rc, GetLastError());
             break;
         }
@@ -261,10 +332,10 @@ static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg)
 void	TIME_MMTimeStart(void)
 {
     if (!TIME_hMMTimer) {
-	TIME_TimersList = NULL;
-        TIME_hWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+        TIME_TimersList = NULL;
+        CREATEEVENT(TIME_hWakeEvent);
         TIME_TimeToDie = FALSE;
-	TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, &WINMM_IData, 0, NULL);
+        TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, &WINMM_IData, 0, NULL);
         SetThreadPriority(TIME_hMMTimer, THREAD_PRIORITY_TIME_CRITICAL);
         InitializeCriticalSection(&TIME_cbcrst);
         TIME_cbcrst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINMM.TIME_cbcrst");
@@ -279,14 +350,14 @@ void	TIME_MMTimeStop(void)
     if (TIME_hMMTimer) {
 
         TIME_TimeToDie = TRUE;
-        SetEvent(TIME_hWakeEvent);
+        SETEVENT(TIME_hWakeEvent);
 
         /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */
-	WaitForSingleObject(TIME_hMMTimer, INFINITE);
+        WaitForSingleObject(TIME_hMMTimer, INFINITE);
 
-	CloseHandle(TIME_hMMTimer);
-	CloseHandle(TIME_hWakeEvent);
-	TIME_hMMTimer = 0;
+        CloseHandle(TIME_hMMTimer);
+        CLOSEEVENT(TIME_hWakeEvent);
+        TIME_hMMTimer = 0;
         TIME_cbcrst.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&TIME_cbcrst);
         TIME_TimersList = NULL;
@@ -352,7 +423,7 @@ WORD	TIME_SetEventInternal(UINT wDelay, UINT wResol,
     LeaveCriticalSection(&WINMM_IData.cs);
 
     /* Wake the service thread in case there is work to be done */
-    SetEvent(TIME_hWakeEvent);
+    SETEVENT(TIME_hWakeEvent);
 
     TRACE("=> %u\n", wNewID + 1);
 
-- 
1.4.4.2



More information about the wine-patches mailing list