Author: janderwald
Date: Tue Nov 3 12:47:06 2009
New Revision: 43931
URL:
http://svn.reactos.org/svn/reactos?rev=43931&view=rev
Log:
- Partially revert 43747
See issue #4936 for more details.
Modified:
trunk/reactos/dll/win32/winmm/time.c
Modified: trunk/reactos/dll/win32/winmm/time.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/winmm/time.c?rev…
==============================================================================
--- trunk/reactos/dll/win32/winmm/time.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/winmm/time.c [iso-8859-1] Tue Nov 3 12:47:06 2009
@@ -17,14 +17,13 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
-#include <errno.h>
#include <time.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
@@ -32,12 +31,6 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
#include "windef.h"
#include "winbase.h"
@@ -45,47 +38,26 @@
#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;
+ UINT wDelay;
+ UINT wResol;
LPTIMECALLBACK lpFunc; /* can be lots of things */
- DWORD_PTR dwUser;
- UINT16 wFlags;
- UINT16 wTimerID;
- DWORD dwTriggerTime;
+ DWORD dwUser;
+ UINT16 wFlags;
+ UINT16 wTimerID;
+ DWORD dwTriggerTime;
+ struct tagWINE_TIMERENTRY* lpNext;
} WINE_TIMERENTRY, *LPWINE_TIMERENTRY;
-static struct list timer_list = LIST_INIT(timer_list);
-
-static CRITICAL_SECTION TIME_cbcrst;
-static CRITICAL_SECTION_DEBUG critsect_debug =
-{
- 0, 0, &TIME_cbcrst,
- { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
- 0, 0, { (DWORD_PTR)(__FILE__ ": TIME_cbcrst") }
-};
-static CRITICAL_SECTION TIME_cbcrst = { &critsect_debug, -1, 0, 0, 0, 0 };
-
static HANDLE TIME_hMMTimer;
+static LPWINE_TIMERENTRY TIME_TimersList;
+static HANDLE TIME_hKillEvent;
+static HANDLE TIME_hWakeEvent;
static BOOL TIME_TimeToDie = TRUE;
-static int TIME_fdWake[2] = { -1, -1 };
-
-/* 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.
@@ -94,7 +66,7 @@
*
* Second, a brief survey of a variety of Win 2k and Win X
* machines showed that a 'standard' (aka default) timer
- * resolution was 1 ms (Win9x is documented as being 1). However, one
+ * resolution was 1 ms (Win9x is documented as being 1). However, one
* machine had a standard timer resolution of 10 ms.
*
* Further, if we set our default resolution to 1,
@@ -116,15 +88,54 @@
#define MMSYSTIME_MININTERVAL (1)
#define MMSYSTIME_MAXINTERVAL (65535)
-#ifdef HAVE_POLL
+
+static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer)
+{
+ TRACE("%04lx:CallBack => lpFunc=%p wTimerID=%04X dwUser=%08lX dwTriggerTime
%ld(delta %ld)\n",
+ GetCurrentThreadId(), lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser,
+ lpTimer->dwTriggerTime, GetTickCount() - lpTimer->dwTriggerTime);
+
+ /* - 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
+ * PostMessage), and must reside in DLL (therefore uses stack of active
application). So I
+ * guess current implementation via SetTimer has to be improved upon.
+ */
+ switch (lpTimer->wFlags & 0x30) {
+ case TIME_CALLBACK_FUNCTION:
+ (lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0);
+ break;
+ case TIME_CALLBACK_EVENT_SET:
+ SetEvent((HANDLE)lpTimer->lpFunc);
+ break;
+ case TIME_CALLBACK_EVENT_PULSE:
+ PulseEvent((HANDLE)lpTimer->lpFunc);
+ break;
+ default:
+ FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n",
+ lpTimer->wFlags, lpTimer->lpFunc);
+ break;
+ }
+}
/**************************************************************************
* TIME_MMSysTimeCallback
*/
-static int TIME_MMSysTimeCallback(void)
-{
- WINE_TIMERENTRY *timer, *to_free;
- int delta_time;
+static DWORD CALLBACK TIME_MMSysTimeCallback()
+{
+static int nSizeLpTimers;
+static LPWINE_TIMERENTRY lpTimers;
+
+ LPWINE_TIMERENTRY timer, *ptimer, *next_ptimer;
+ int idx;
+ DWORD cur_time;
+ DWORD delta_time;
+ DWORD ret_time = INFINITE;
+ DWORD adjust_time;
+
+
+ /* optimize for the most frequent case - no events */
+ if (! TIME_TimersList)
+ return(ret_time);
/* since timeSetEvent() and timeKillEvent() can be called
* from 16 bit code, there are cases where win16 lock is
@@ -136,60 +147,84 @@
* 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 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;
+ cur_time = GetTickCount();
EnterCriticalSection(&WINMM_cs);
- for (;;)
- {
- struct list *ptr = list_head( &timer_list );
- if (!ptr)
+ for (ptimer = &TIME_TimersList; *ptimer != NULL; ) {
+ timer = *ptimer;
+ next_ptimer = &timer->lpNext;
+ if (cur_time >= timer->dwTriggerTime)
{
- delta_time = -1;
- break;
+ if (timer->lpFunc) {
+ if (idx == nSizeLpTimers) {
+ if (lpTimers)
+ lpTimers = (LPWINE_TIMERENTRY)
+ HeapReAlloc(GetProcessHeap(), 0, lpTimers,
+ ++nSizeLpTimers * sizeof(WINE_TIMERENTRY));
+ else
+ lpTimers = (LPWINE_TIMERENTRY)
+ HeapAlloc(GetProcessHeap(), 0,
+ ++nSizeLpTimers * sizeof(WINE_TIMERENTRY));
+ }
+ lpTimers[idx++] = *timer;
+
+ }
+
+ /* Update the time after we make the copy to preserve
+ the original trigger time */
+ timer->dwTriggerTime += timer->wDelay;
+
+ /* TIME_ONESHOT is defined as 0 */
+ if (!(timer->wFlags & TIME_PERIODIC))
+ {
+ /* unlink timer from timers list */
+ *ptimer = *next_ptimer;
+ HeapFree(GetProcessHeap(), 0, timer);
+
+ /* We don't need to trigger oneshots again */
+ delta_time = INFINITE;
+ }
+ else
+ {
+ /* Compute when this event needs this function
+ to be called again */
+ if (timer->dwTriggerTime <= cur_time)
+ delta_time = 0;
+ else
+ delta_time = timer->dwTriggerTime - cur_time;
+ }
}
-
- timer = LIST_ENTRY( ptr, WINE_TIMERENTRY, entry );
- delta_time = timer->dwTriggerTime - GetTickCount();
- 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;
-
- switch(timer->wFlags &
(TIME_CALLBACK_EVENT_SET|TIME_CALLBACK_EVENT_PULSE))
- {
- case TIME_CALLBACK_EVENT_SET:
- SetEvent(timer->lpFunc);
- break;
- case TIME_CALLBACK_EVENT_PULSE:
- PulseEvent(timer->lpFunc);
- break;
- case TIME_CALLBACK_FUNCTION:
- {
- DWORD_PTR user = timer->dwUser;
- UINT16 id = timer->wTimerID;
- UINT16 flags = timer->wFlags;
- LPTIMECALLBACK func = timer->lpFunc;
-
- if (flags & TIME_KILL_SYNCHRONOUS)
EnterCriticalSection(&TIME_cbcrst);
- LeaveCriticalSection(&WINMM_cs);
-
- func(id, 0, user, 0, 0);
-
- EnterCriticalSection(&WINMM_cs);
- if (flags & TIME_KILL_SYNCHRONOUS)
LeaveCriticalSection(&TIME_cbcrst);
- }
- break;
- }
- HeapFree( GetProcessHeap(), 0, to_free );
- }
+ else
+ delta_time = timer->dwTriggerTime - cur_time;
+
+ /* Determine when we need to return to this function */
+ ret_time = min(ret_time, delta_time);
+
+ ptimer = next_ptimer;
+ }
+ if (TIME_hKillEvent) ResetEvent(TIME_hKillEvent);
LeaveCriticalSection(&WINMM_cs);
- return delta_time;
+
+ while (idx > 0) TIME_TriggerCallBack(&lpTimers[--idx]);
+ if (TIME_hKillEvent) SetEvent(TIME_hKillEvent);
+
+ /* Finally, adjust the recommended wait time downward
+ by the amount of time the processing routines
+ actually took */
+ adjust_time = GetTickCount() - cur_time;
+ if (adjust_time > ret_time)
+ ret_time = 0;
+ else
+ ret_time -= adjust_time;
+
+ /* We return the amount of time our caller should sleep
+ before needing to check in on us again */
+ return(ret_time);
}
/**************************************************************************
@@ -197,12 +232,8 @@
*/
static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg)
{
- int sleep_time, ret;
- char readme[16];
- struct pollfd pfd;
-
- pfd.fd = TIME_fdWake[0];
- pfd.events = POLLIN;
+ DWORD sleep_time;
+ DWORD rc;
TRACE("Starting main winmm thread\n");
@@ -212,23 +243,19 @@
new event; it's not clear if that would be worth
it or not. */
- while (! TIME_TimeToDie)
+ while (! TIME_TimeToDie)
{
- sleep_time = TIME_MMSysTimeCallback();
+ sleep_time = TIME_MMSysTimeCallback();
if (sleep_time == 0)
continue;
- if ((ret = poll(&pfd, 1, sleep_time)) < 0)
+ rc = WaitForSingleObject(TIME_hWakeEvent, sleep_time);
+ if (rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0)
{
- if (errno != EINTR && errno != EAGAIN)
- {
- ERR("Unexpected error in poll: %s(%d)\n", strerror(errno),
errno);
- break;
- }
- }
-
- while (ret > 0) ret = read(TIME_fdWake[0], readme, sizeof(readme));
+ FIXME("Unexpected error %ld(%ld) in timer thread\n", rc,
GetLastError());
+ break;
+ }
}
TRACE("Exiting main winmm thread\n");
return 0;
@@ -237,50 +264,34 @@
/**************************************************************************
* TIME_MMTimeStart
*/
-static void TIME_MMTimeStart(void)
+void TIME_MMTimeStart(void)
{
if (!TIME_hMMTimer) {
- if (pipe(TIME_fdWake) < 0)
- {
- TIME_fdWake[0] = TIME_fdWake[1] = -1;
- ERR("Cannot create pipe: %s\n", strerror(errno));
- } else {
- fcntl(TIME_fdWake[0], F_SETFL, O_NONBLOCK);
- fcntl(TIME_fdWake[1], F_SETFL, O_NONBLOCK);
- }
+ TIME_TimersList = NULL;
+ TIME_hWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
TIME_TimeToDie = FALSE;
- TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, NULL, 0, NULL);
+ TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, NULL, 0, NULL);
SetThreadPriority(TIME_hMMTimer, THREAD_PRIORITY_TIME_CRITICAL);
}
}
-#else /* HAVE_POLL */
-
-static void TIME_MMTimeStart(void)
-{
- FIXME( "not starting system thread\n" );
-}
-
-#endif /* HAVE_POLL */
-
/**************************************************************************
* TIME_MMTimeStop
*/
void TIME_MMTimeStop(void)
{
if (TIME_hMMTimer) {
- const char a='a';
TIME_TimeToDie = TRUE;
- write(TIME_fdWake[1], &a, sizeof(a));
-
- WaitForSingleObject(TIME_hMMTimer, INFINITE);
- close(TIME_fdWake[0]);
- close(TIME_fdWake[1]);
- TIME_fdWake[0] = TIME_fdWake[1] = -1;
- CloseHandle(TIME_hMMTimer);
- TIME_hMMTimer = 0;
- DeleteCriticalSection(&TIME_cbcrst);
+ SetEvent(TIME_hWakeEvent);
+
+ /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */
+ WaitForSingleObject(TIME_hMMTimer, INFINITE);
+
+ CloseHandle(TIME_hMMTimer);
+ CloseHandle(TIME_hWakeEvent);
+ TIME_hMMTimer = 0;
+ TIME_TimersList = NULL;
}
}
@@ -300,15 +311,14 @@
}
/**************************************************************************
- * timeSetEvent [WINMM.@]
- */
-MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
- DWORD_PTR dwUser, UINT wFlags)
+ * TIME_SetEventInternal [internal]
+ */
+WORD TIME_SetEventInternal(UINT wDelay, UINT wResol,
+ LPTIMECALLBACK lpFunc, DWORD dwUser, UINT wFlags)
{
WORD wNewID = 0;
LPWINE_TIMERENTRY lpNewTimer;
LPWINE_TIMERENTRY lpTimer;
- const char c = 'c';
TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser,
wFlags);
@@ -318,6 +328,8 @@
lpNewTimer = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY));
if (lpNewTimer == NULL)
return 0;
+
+ TIME_MMTimeStart();
lpNewTimer->wDelay = wDelay;
lpNewTimer->dwTriggerTime = GetTickCount() + wDelay;
@@ -331,18 +343,21 @@
EnterCriticalSection(&WINMM_cs);
- LIST_FOR_EACH_ENTRY( lpTimer, &timer_list, WINE_TIMERENTRY, entry )
- wNewID = max(wNewID, lpTimer->wTimerID);
-
- link_timer( lpNewTimer );
+ 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 = TIME_TimersList;
+ TIME_TimersList = lpNewTimer;
lpNewTimer->wTimerID = wNewID + 1;
- TIME_MMTimeStart();
-
LeaveCriticalSection(&WINMM_cs);
/* Wake the service thread in case there is work to be done */
- write(TIME_fdWake[1], &c, sizeof(c));
+ SetEvent(TIME_hWakeEvent);
TRACE("=> %u\n", wNewID + 1);
@@ -350,21 +365,30 @@
}
/**************************************************************************
+ * timeSetEvent [WINMM.@]
+ */
+MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc,
+ DWORD_PTR dwUser, UINT wFlags)
+{
+ return TIME_SetEventInternal(wDelay, wResol, lpFunc,
+ dwUser, wFlags);
+}
+
+/**************************************************************************
* timeKillEvent [WINMM.@]
*/
MMRESULT WINAPI timeKillEvent(UINT wID)
{
- WINE_TIMERENTRY *lpSelf = NULL, *lpTimer;
- DWORD wFlags;
+ LPWINE_TIMERENTRY lpSelf = NULL, *lpTimer;
TRACE("(%u)\n", wID);
EnterCriticalSection(&WINMM_cs);
/* remove WINE_TIMERENTRY from list */
- LIST_FOR_EACH_ENTRY( lpTimer, &timer_list, WINE_TIMERENTRY, entry )
- {
- if (wID == lpTimer->wTimerID) {
- lpSelf = lpTimer;
- list_remove( &lpTimer->entry );
+ for (lpTimer = &TIME_TimersList; *lpTimer; lpTimer = &(*lpTimer)->lpNext)
{
+ if (wID == (*lpTimer)->wTimerID) {
+ lpSelf = *lpTimer;
+ /* unlink timer of id 'wID' */
+ *lpTimer = (*lpTimer)->lpNext;
break;
}
}
@@ -375,12 +399,9 @@
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);
+ if (lpSelf->wFlags & TIME_KILL_SYNCHRONOUS)
+ WaitForSingleObject(TIME_hKillEvent, INFINITE);
HeapFree(GetProcessHeap(), 0, lpSelf);
- if (wFlags & TIME_KILL_SYNCHRONOUS)
- LeaveCriticalSection(&TIME_cbcrst);
return TIMERR_NOERROR;
}
@@ -438,6 +459,7 @@
}
/**************************************************************************
+ * timeGetTime [MMSYSTEM.607]
* timeGetTime [WINMM.@]
*/
DWORD WINAPI timeGetTime(void)
@@ -446,7 +468,7 @@
DWORD count;
/* FIXME: releasing the win16 lock here is a temporary hack (I hope)
- * that lets mciavi32.dll run correctly
+ * that lets mciavi.drv run correctly
*/
if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);