Some applications call GlobalMemoryStatus() very often. Cache the
[wine/dcerpc.git] / windows / timer.c
blobb724780caa68427b6bb7373d254eb8c80cd52276
1 /*
2 * Timer functions
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include "windef.h"
8 #include "wingdi.h"
9 #include "wine/winuser16.h"
10 #include "winuser.h"
11 #include "queue.h"
12 #include "task.h"
13 #include "winproc.h"
14 #include "services.h"
15 #include "message.h"
16 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(timer)
21 typedef struct tagTIMER
23 HWND hwnd;
24 HQUEUE16 hq;
25 UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
26 UINT id;
27 UINT timeout;
28 HANDLE hService;
29 BOOL expired;
30 HWINDOWPROC proc;
31 } TIMER;
33 #define NB_TIMERS 34
34 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
36 #define SYS_TIMER_RATE 54925
38 static TIMER TimersArray[NB_TIMERS];
40 static CRITICAL_SECTION csTimer;
43 /***********************************************************************
44 * TIMER_Init
46 * Initialize critical section for the timer.
48 BOOL TIMER_Init( void )
50 InitializeCriticalSection( &csTimer );
51 MakeCriticalSectionGlobal( &csTimer );
53 return TRUE;
57 /***********************************************************************
58 * TIMER_ClearTimer
60 * Clear and remove a timer.
62 static void TIMER_ClearTimer( TIMER * pTimer )
64 if ( pTimer->hService != INVALID_HANDLE_VALUE )
66 SERVICE_Delete( pTimer->hService );
67 pTimer->hService = INVALID_HANDLE_VALUE;
70 if ( pTimer->expired )
72 QUEUE_DecTimerCount( pTimer->hq );
73 pTimer->expired = FALSE;
76 pTimer->hwnd = 0;
77 pTimer->msg = 0;
78 pTimer->id = 0;
79 pTimer->timeout = 0;
80 WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
84 /***********************************************************************
85 * TIMER_RemoveWindowTimers
87 * Remove all timers for a given window.
89 void TIMER_RemoveWindowTimers( HWND hwnd )
91 int i;
92 TIMER *pTimer;
94 EnterCriticalSection( &csTimer );
96 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
97 if ((pTimer->hwnd == hwnd) && pTimer->timeout)
98 TIMER_ClearTimer( pTimer );
100 LeaveCriticalSection( &csTimer );
104 /***********************************************************************
105 * TIMER_RemoveQueueTimers
107 * Remove all timers for a given queue.
109 void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
111 int i;
112 TIMER *pTimer;
114 EnterCriticalSection( &csTimer );
116 for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
117 if ((pTimer->hq == hqueue) && pTimer->timeout)
118 TIMER_ClearTimer( pTimer );
120 LeaveCriticalSection( &csTimer );
124 /***********************************************************************
125 * TIMER_CheckTimer
127 static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
129 TIMER *pTimer = (TIMER *)timer_ptr;
130 HQUEUE16 wakeQueue = 0;
132 EnterCriticalSection( &csTimer );
134 /* Paranoid check to prevent a race condition ... */
135 if ( !pTimer->timeout )
137 LeaveCriticalSection( &csTimer );
138 return;
141 if ( !pTimer->expired )
143 TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
144 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
146 pTimer->expired = TRUE;
147 wakeQueue = pTimer->hq;
150 LeaveCriticalSection( &csTimer );
152 /* Note: This has to be done outside the csTimer critical section,
153 otherwise we'll get deadlocks. */
155 if ( wakeQueue )
156 QUEUE_IncTimerCount( wakeQueue );
160 /***********************************************************************
161 * TIMER_GetTimerMsg
163 * Build a message for an expired timer.
165 BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
166 HQUEUE16 hQueue, BOOL remove )
168 TIMER *pTimer;
169 int i;
171 EnterCriticalSection( &csTimer );
173 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
174 if ( pTimer->timeout != 0 && pTimer->expired
175 && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
176 break;
178 if ( i == NB_TIMERS )
180 LeaveCriticalSection( &csTimer );
181 return FALSE; /* No timer */
184 TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
185 pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
187 if (remove)
188 pTimer->expired = FALSE;
190 /* Build the message */
191 msg->hwnd = pTimer->hwnd;
192 msg->message = pTimer->msg;
193 msg->wParam = pTimer->id;
194 msg->lParam = (LONG)pTimer->proc;
195 msg->time = GetTickCount();
197 LeaveCriticalSection( &csTimer );
199 return TRUE;
203 /***********************************************************************
204 * TIMER_SetTimer
206 static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
207 WNDPROC16 proc, WINDOWPROCTYPE type, BOOL sys )
209 int i;
210 TIMER * pTimer;
212 if (!timeout)
213 { /* timeout==0 is a legal argument UB 990821*/
214 WARN("Timeout== 0 not implemented, using timeout=1\n");
215 timeout=1;
217 EnterCriticalSection( &csTimer );
219 /* Check if there's already a timer with the same hwnd and id */
221 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
222 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
223 (pTimer->timeout != 0))
225 TIMER_ClearTimer( pTimer );
226 break;
229 if ( i == NB_TIMERS )
231 /* Find a free timer */
233 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
234 if (!pTimer->timeout) break;
236 if ( (i >= NB_TIMERS) ||
237 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) )
239 LeaveCriticalSection( &csTimer );
240 return 0;
244 if (!hwnd) id = i + 1;
246 /* Add the timer */
248 pTimer->hwnd = hwnd;
249 pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
250 : GetFastQueue16( );
251 pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
252 pTimer->id = id;
253 pTimer->timeout = timeout;
254 pTimer->proc = (HWINDOWPROC)0;
255 if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
257 pTimer->expired = FALSE;
258 pTimer->hService = SERVICE_AddTimer( MAX( timeout * 1000L, SYS_TIMER_RATE ),
259 TIMER_CheckTimer, (ULONG_PTR)pTimer );
261 TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
262 pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
263 (DWORD)pTimer->proc );
265 LeaveCriticalSection( &csTimer );
267 if (!id) return TRUE;
268 else return id;
272 /***********************************************************************
273 * TIMER_KillTimer
275 static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
277 int i;
278 TIMER * pTimer;
280 EnterCriticalSection( &csTimer );
282 /* Find the timer */
284 for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
285 if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
286 (pTimer->timeout != 0)) break;
288 if ( (i >= NB_TIMERS) ||
289 (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) ||
290 (!sys && (pTimer->msg != WM_TIMER)) ||
291 (sys && (pTimer->msg != WM_SYSTIMER)) )
293 LeaveCriticalSection( &csTimer );
294 return FALSE;
297 /* Delete the timer */
299 TIMER_ClearTimer( pTimer );
301 LeaveCriticalSection( &csTimer );
303 return TRUE;
307 /***********************************************************************
308 * SetTimer16 (USER.10)
310 UINT16 WINAPI SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
311 TIMERPROC16 proc )
313 TRACE("%04x %d %d %08lx\n",
314 hwnd, id, timeout, (LONG)proc );
315 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
316 WIN_PROC_16, FALSE );
320 /***********************************************************************
321 * SetTimer32 (USER32.511)
323 UINT WINAPI SetTimer( HWND hwnd, UINT id, UINT timeout,
324 TIMERPROC proc )
326 TRACE("%04x %d %d %08lx\n",
327 hwnd, id, timeout, (LONG)proc );
328 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
329 WIN_PROC_32A, FALSE );
333 /***********************************************************************
334 * SetSystemTimer16 (USER.11)
336 UINT16 WINAPI SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
337 TIMERPROC16 proc )
339 TRACE("%04x %d %d %08lx\n",
340 hwnd, id, timeout, (LONG)proc );
341 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
342 WIN_PROC_16, TRUE );
346 /***********************************************************************
347 * SetSystemTimer32 (USER32.509)
349 UINT WINAPI SetSystemTimer( HWND hwnd, UINT id, UINT timeout,
350 TIMERPROC proc )
352 TRACE("%04x %d %d %08lx\n",
353 hwnd, id, timeout, (LONG)proc );
354 return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
355 WIN_PROC_32A, TRUE );
359 /***********************************************************************
360 * KillTimer16 (USER.12)
362 BOOL16 WINAPI KillTimer16( HWND16 hwnd, UINT16 id )
364 TRACE("%04x %d\n", hwnd, id );
365 return TIMER_KillTimer( hwnd, id, FALSE );
369 /***********************************************************************
370 * KillTimer32 (USER32.354)
372 BOOL WINAPI KillTimer( HWND hwnd, UINT id )
374 TRACE("%04x %d\n", hwnd, id );
375 return TIMER_KillTimer( hwnd, id, FALSE );
379 /***********************************************************************
380 * KillSystemTimer16 (USER.182)
382 BOOL16 WINAPI KillSystemTimer16( HWND16 hwnd, UINT16 id )
384 TRACE("%04x %d\n", hwnd, id );
385 return TIMER_KillTimer( hwnd, id, TRUE );
389 /***********************************************************************
390 * KillSystemTimer32 (USER32.353)
392 BOOL WINAPI KillSystemTimer( HWND hwnd, UINT id )
394 TRACE("%04x %d\n", hwnd, id );
395 return TIMER_KillTimer( hwnd, id, TRUE );