Skip to content
Snippets Groups Projects
Commit a9238080 authored by Ulrich Weigand's avatar Ulrich Weigand Committed by Alexandre Julliard
Browse files

Use separate service for each windows timer.

parent 1597d735
No related branches found
No related tags found
No related merge requests found
......@@ -17,13 +17,13 @@ DEFAULT_DEBUG_CHANNEL(timer)
typedef struct tagTIMER
{
HWND hwnd;
HQUEUE16 hq;
UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
HQUEUE16 hq;
UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
UINT id;
UINT timeout;
struct tagTIMER *next;
DWORD expires; /* Next expiration, or 0 if already expired */
HWINDOWPROC proc;
HANDLE hService;
BOOL expired;
HWINDOWPROC proc;
} TIMER;
#define NB_TIMERS 34
......@@ -31,14 +31,8 @@ typedef struct tagTIMER
static TIMER TimersArray[NB_TIMERS];
static TIMER * pNextTimer = NULL; /* Next timer to expire */
static CRITICAL_SECTION csTimer;
/* Duration from 'time' until expiration of the timer */
#define EXPIRE_TIME(pTimer,time) \
(((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
/***********************************************************************
* TIMER_Init
......@@ -55,61 +49,24 @@ BOOL TIMER_Init( void )
/***********************************************************************
* TIMER_InsertTimer
* TIMER_ClearTimer
*
* Insert the timer at its place in the chain.
* Clear and remove a timer.
*/
static void TIMER_InsertTimer( TIMER * pTimer )
static void TIMER_ClearTimer( TIMER * pTimer )
{
EnterCriticalSection( &csTimer );
if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
if ( pTimer->hService != INVALID_HANDLE_VALUE )
{
pTimer->next = pNextTimer;
pNextTimer = pTimer;
SERVICE_Delete( pTimer->hService );
pTimer->hService = INVALID_HANDLE_VALUE;
}
else
if ( pTimer->expired )
{
TIMER * ptr = pNextTimer;
while (ptr->next && (pTimer->expires >= ptr->next->expires))
ptr = ptr->next;
pTimer->next = ptr->next;
ptr->next = pTimer;
QUEUE_DecTimerCount( pTimer->hq );
pTimer->expired = FALSE;
}
LeaveCriticalSection( &csTimer );
}
/***********************************************************************
* TIMER_RemoveTimer
*
* Remove the timer from the chain.
*/
static void TIMER_RemoveTimer( TIMER * pTimer )
{
TIMER **ppTimer = &pNextTimer;
EnterCriticalSection( &csTimer );
while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
if (*ppTimer) *ppTimer = pTimer->next;
pTimer->next = NULL;
LeaveCriticalSection( &csTimer );
if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
}
/***********************************************************************
* TIMER_ClearTimer
*
* Clear and remove a timer.
*/
static void TIMER_ClearTimer( TIMER * pTimer )
{
TIMER_RemoveTimer( pTimer );
pTimer->hwnd = 0;
pTimer->msg = 0;
pTimer->id = 0;
......@@ -159,77 +116,38 @@ void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
/***********************************************************************
* TIMER_RestartTimers
*
* Restart an expired timer.
*/
static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
{
TIMER_RemoveTimer( pTimer );
pTimer->expires = curTime + pTimer->timeout;
TIMER_InsertTimer( pTimer );
}
/***********************************************************************
* TIMER_CheckTimers
*
* Mark expired timers and wake the appropriate queues.
* TIMER_CheckTimer
*/
static void CALLBACK TIMER_CheckTimers( ULONG_PTR forceTimer )
static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
{
static HANDLE ServiceHandle = INVALID_HANDLE_VALUE;
static LONG ServiceTimeout = 0;
TIMER *pTimer;
DWORD curTime = GetTickCount();
TIMER *pTimer = (TIMER *)timer_ptr;
HQUEUE16 wakeQueue = 0;
EnterCriticalSection( &csTimer );
TRACE(timer, "Called at %ld (%s)\n", curTime, forceTimer? "manual" : "auto" );
pTimer = pNextTimer;
while (pTimer && !pTimer->expires) /* Skip already expired timers */
pTimer = pTimer->next;
while (pTimer && (pTimer->expires <= curTime))
/* Paranoid check to prevent a race condition ... */
if ( !pTimer->timeout )
{
pTimer->expires = 0;
QUEUE_IncTimerCount( pTimer->hq );
pTimer = pTimer->next;
LeaveCriticalSection( &csTimer );
return;
}
/* Install service callback with appropriate timeout, so that
we get called again once the next timer has expired */
if (pTimer)
if ( !pTimer->expired )
{
LONG timeout = pTimer->expires - curTime;
if ( forceTimer || timeout != ServiceTimeout )
{
if ( ServiceHandle != INVALID_HANDLE_VALUE )
SERVICE_Delete( ServiceHandle );
TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n",
pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
ServiceHandle = SERVICE_AddTimer( timeout * 1000L,
TIMER_CheckTimers, FALSE );
ServiceTimeout = timeout;
TRACE(timer, "Installed service callback with timeout %ld\n", timeout );
}
pTimer->expired = TRUE;
wakeQueue = pTimer->hq;
}
else
{
if ( ServiceHandle != INVALID_HANDLE_VALUE )
{
SERVICE_Delete( ServiceHandle );
ServiceHandle = INVALID_HANDLE_VALUE;
ServiceTimeout = 0;
TRACE(timer, "Deleted service callback\n" );
}
}
LeaveCriticalSection( &csTimer );
/* Note: This has to be done outside the csTimer critical section,
otherwise we'll get deadlocks. */
if ( wakeQueue )
QUEUE_IncTimerCount( wakeQueue );
}
......@@ -242,38 +160,33 @@ BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
HQUEUE16 hQueue, BOOL remove )
{
TIMER *pTimer;
DWORD curTime = GetTickCount();
int i;
EnterCriticalSection( &csTimer );
pTimer = pNextTimer;
if (hwnd) /* Find first timer for this window */
while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
else /* Find first timer for this queue */
while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if ( pTimer->timeout != 0 && pTimer->expired
&& (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
break;
if (!pTimer || (pTimer->expires > curTime))
if ( i == NB_TIMERS )
{
LeaveCriticalSection( &csTimer );
return FALSE; /* No timer */
}
TRACE(timer, "Timer expired: %04x, %04x, %04x, %08lx\n",
TRACE(timer, "Timer got message: %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 );
}
pTimer->expired = FALSE;
/* Build the message */
msg->hwnd = pTimer->hwnd;
msg->message = pTimer->msg;
msg->wParam = pTimer->id;
msg->lParam = (LONG)pTimer->proc;
msg->time = curTime;
msg->time = GetTickCount();
LeaveCriticalSection( &csTimer );
......@@ -300,32 +213,25 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
(pTimer->timeout != 0))
{
/* Got one: set new values and return */
TIMER_RemoveTimer( pTimer );
pTimer->timeout = timeout;
WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
pTimer->proc = (HWINDOWPROC)0;
if (proc) WINPROC_SetProc( &pTimer->proc, proc,
type, WIN_PROC_TIMER );
pTimer->expires = GetTickCount() + timeout;
TIMER_InsertTimer( pTimer );
TIMER_CheckTimers( TRUE );
LeaveCriticalSection( &csTimer );
return id;
TIMER_ClearTimer( pTimer );
break;
}
/* Find a free timer */
if ( i == NB_TIMERS )
{
/* Find a free timer */
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if (!pTimer->timeout) break;
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if (!pTimer->timeout) break;
if ( (i >= NB_TIMERS) ||
(!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
{
LeaveCriticalSection( &csTimer );
return 0;
if ( (i >= NB_TIMERS) ||
(!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
{
LeaveCriticalSection( &csTimer );
return 0;
}
}
if (!hwnd) id = i + 1;
/* Add the timer */
......@@ -336,15 +242,17 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
pTimer->id = id;
pTimer->timeout = timeout;
pTimer->expires = GetTickCount() + timeout;
pTimer->proc = (HWINDOWPROC)0;
if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
pTimer->expired = FALSE;
pTimer->hService = SERVICE_AddTimer( timeout * 1000L,
TIMER_CheckTimer, (ULONG_PTR)pTimer );
TRACE(timer, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
(DWORD)pTimer->proc );
TIMER_InsertTimer( pTimer );
TIMER_CheckTimers( TRUE );
LeaveCriticalSection( &csTimer );
if (!id) return TRUE;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment