Use SERVICES callback to implement Windows timers.
Timer expiration handling removed from EVENT_WaitNetEvent loop.
diff --git a/include/message.h b/include/message.h
index ffe942e..b8dcc10 100644
--- a/include/message.h
+++ b/include/message.h
@@ -22,8 +22,6 @@
extern void TIMER_RemoveWindowTimers( HWND hwnd );
extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue );
extern void TIMER_SwitchQueue( HQUEUE16 hOldQueue, HQUEUE16 hNewQueue );
-extern LONG TIMER_GetNextExpiration(void);
-extern void TIMER_ExpireTimers(void);
extern BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
HQUEUE16 hQueue, BOOL remove );
diff --git a/windows/timer.c b/windows/timer.c
index 2163101..89dd416 100644
--- a/windows/timer.c
+++ b/windows/timer.c
@@ -8,6 +8,7 @@
#include "queue.h"
#include "task.h"
#include "winproc.h"
+#include "services.h"
#include "debug.h"
DEFAULT_DEBUG_CHANNEL(timer)
@@ -189,47 +190,22 @@
TIMER_InsertTimer( pTimer );
}
-
/***********************************************************************
- * TIMER_GetNextExpiration
- *
- * Return next timer expiration time, or -1 if none.
- */
-LONG TIMER_GetNextExpiration(void)
-{
- TIMER *pTimer;
- LONG retValue;
-
- EnterCriticalSection( &csTimer );
-
- pTimer = pNextTimer;
-
- while (pTimer && !pTimer->expires) /* Skip already expired timers */
- pTimer = pTimer->next;
-
- if (pTimer)
- {
- DWORD now = GetTickCount();
- retValue = (pTimer->expires <= now) ? 0 : (pTimer->expires - now);
- }
- else retValue = -1;
-
- LeaveCriticalSection( &csTimer );
- return retValue;
-}
-
-
-/***********************************************************************
- * TIMER_ExpireTimers
+ * TIMER_CheckTimers
*
* Mark expired timers and wake the appropriate queues.
*/
-void TIMER_ExpireTimers(void)
+static void CALLBACK TIMER_CheckTimers( ULONG_PTR forceTimer )
{
+ static HANDLE ServiceHandle = INVALID_HANDLE_VALUE;
+ static LONG ServiceTimeout = 0;
+
TIMER *pTimer;
DWORD curTime = GetTickCount();
EnterCriticalSection( &csTimer );
+
+ TRACE(timer, "Called at %ld (%s)\n", curTime, forceTimer? "manual" : "auto" );
pTimer = pNextTimer;
@@ -241,6 +217,37 @@
QUEUE_IncTimerCount( pTimer->hq );
pTimer = pTimer->next;
}
+
+ /* Install service callback with appropriate timeout, so that
+ we get called again once the next timer has expired */
+
+ if (pTimer)
+ {
+ LONG timeout = pTimer->expires - curTime;
+
+ if ( forceTimer || timeout != ServiceTimeout )
+ {
+ if ( ServiceHandle != INVALID_HANDLE_VALUE )
+ SERVICE_Delete( ServiceHandle );
+
+ ServiceHandle = SERVICE_AddTimer( timeout * 1000L,
+ TIMER_CheckTimers, FALSE );
+ ServiceTimeout = timeout;
+
+ TRACE(timer, "Installed service callback with timeout %ld\n", timeout );
+ }
+ }
+ else
+ {
+ if ( ServiceHandle != INVALID_HANDLE_VALUE )
+ {
+ SERVICE_Delete( ServiceHandle );
+ ServiceHandle = INVALID_HANDLE_VALUE;
+ ServiceTimeout = 0;
+
+ TRACE(timer, "Deleted service callback\n" );
+ }
+ }
LeaveCriticalSection( &csTimer );
}
@@ -272,11 +279,15 @@
return FALSE; /* No timer */
}
- if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
-
TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n",
pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
+ if (remove)
+ {
+ TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
+ TIMER_CheckTimers( TRUE );
+ }
+
/* Build the message */
msg->hwnd = pTimer->hwnd;
msg->message = pTimer->msg;
@@ -318,6 +329,7 @@
type, WIN_PROC_TIMER );
pTimer->expires = GetTickCount() + timeout;
TIMER_InsertTimer( pTimer );
+ TIMER_CheckTimers( TRUE );
LeaveCriticalSection( &csTimer );
return id;
}
@@ -351,6 +363,7 @@
pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
(DWORD)pTimer->proc );
TIMER_InsertTimer( pTimer );
+ TIMER_CheckTimers( TRUE );
LeaveCriticalSection( &csTimer );
diff --git a/windows/x11drv/event.c b/windows/x11drv/event.c
index 5c65024..91c0e7b 100644
--- a/windows/x11drv/event.c
+++ b/windows/x11drv/event.c
@@ -205,26 +205,15 @@
BOOL X11DRV_EVENT_WaitNetEvent( BOOL sleep, BOOL peek )
{
XEvent event;
- LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
int pending = TSXPending(display);
- /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
- * in this case, we fall through directly to the XNextEvent loop.
- */
-
- if (!pending)
+ if (!pending && sleep)
{
int num_pending;
- struct timeval timeout;
fd_set io_set[3];
memcpy( io_set, __event_io_set, sizeof(io_set) );
- if(maxWait != -1) {
- timeout.tv_usec = (maxWait % 1000) * 1000;
- timeout.tv_sec = maxWait / 1000;
- }
-
#ifdef CONFIG_IPC
sigsetjmp(env_wait_x, 1);
stop_wait_op= CONT;
@@ -238,37 +227,24 @@
/* The code up to the next "stop_wait_op = CONT" must be reentrant */
num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
&io_set[EVENT_IO_WRITE],
- &io_set[EVENT_IO_EXCEPT], (maxWait == -1) ? 0 : &timeout );
+ &io_set[EVENT_IO_EXCEPT], NULL );
if ( num_pending == -1 )
{
/* Error - signal, invalid arguments, out of memory */
stop_wait_op = CONT;
return FALSE;
}
- if ( num_pending == 0 )
- {
- /* Timeout */
- stop_wait_op = CONT;
- TIMER_ExpireTimers(); /* FIXME: should this be done even if sleep == 0? */
- return FALSE;
- }
- else stop_wait_op = CONT;
+ stop_wait_op = CONT;
#else /* CONFIG_IPC */
num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
&io_set[EVENT_IO_WRITE],
- &io_set[EVENT_IO_EXCEPT], (maxWait == -1) ? 0 : &timeout );
+ &io_set[EVENT_IO_EXCEPT], NULL );
if ( num_pending == -1 )
{
/* Error - signal, invalid arguments, out of memory */
return FALSE;
}
- if ( num_pending == 0 )
- {
- /* Timeout */
- TIMER_ExpireTimers(); /* FIXME: should this be done even if sleep == 0? */
- return FALSE;
- }
#endif /* CONFIG_IPC */
/* Flush the wake-up pipe, it's just dummy data for waking-up this