ReactOS 0.4.15-dev-7918-g2a2556c
time.c File Reference
#include "winemm.h"
Include dependency graph for time.c:

Go to the source code of this file.

Classes

struct  tagWINE_TIMERENTRY
 

Macros

#define MMSYSTIME_MININTERVAL   (1)
 
#define MMSYSTIME_MAXINTERVAL   (65535)
 

Typedefs

typedef struct tagWINE_TIMERENTRY WINE_TIMERENTRY
 
typedef struct tagWINE_TIMERENTRYLPWINE_TIMERENTRY
 

Functions

 WINE_DEFAULT_DEBUG_CHANNEL (mmtime)
 
static void TIME_TriggerCallBack (LPWINE_TIMERENTRY lpTimer)
 
static DWORD CALLBACK TIME_MMSysTimeCallback ()
 
static DWORD CALLBACK TIME_MMSysTimeThread (LPVOID arg)
 
void TIME_MMTimeStart (void)
 
void TIME_MMTimeStop (void)
 
MMRESULT WINAPI timeGetSystemTime (LPMMTIME lpTime, UINT wSize)
 
WORD TIME_SetEventInternal (UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, DWORD dwUser, UINT wFlags)
 
MMRESULT WINAPI timeSetEvent (UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, DWORD_PTR dwUser, UINT wFlags)
 
MMRESULT WINAPI timeKillEvent (UINT wID)
 
MMRESULT WINAPI timeGetDevCaps (LPTIMECAPS lpCaps, UINT wSize)
 
MMRESULT WINAPI timeBeginPeriod (UINT wPeriod)
 
MMRESULT WINAPI timeEndPeriod (UINT wPeriod)
 
DWORD WINAPI timeGetTime (void)
 

Variables

static HANDLE TIME_hMMTimer
 
static LPWINE_TIMERENTRY TIME_TimersList
 
static HANDLE TIME_hKillEvent
 
static HANDLE TIME_hWakeEvent
 
static BOOL TIME_TimeToDie = TRUE
 
static LARGE_INTEGER TIME_qpcFreq
 

Macro Definition Documentation

◆ MMSYSTIME_MAXINTERVAL

#define MMSYSTIME_MAXINTERVAL   (65535)

Definition at line 79 of file time.c.

◆ MMSYSTIME_MININTERVAL

#define MMSYSTIME_MININTERVAL   (1)

Definition at line 78 of file time.c.

Typedef Documentation

◆ LPWINE_TIMERENTRY

◆ WINE_TIMERENTRY

Function Documentation

◆ TIME_MMSysTimeCallback()

static DWORD CALLBACK TIME_MMSysTimeCallback ( )
static

Definition at line 113 of file time.c.

114{
115static int nSizeLpTimers;
116static LPWINE_TIMERENTRY lpTimers;
117
118 LPWINE_TIMERENTRY timer, *ptimer, *next_ptimer;
119 int idx;
121 DWORD delta_time;
122 DWORD ret_time = INFINITE;
123 DWORD adjust_time;
124
125
126 /* optimize for the most frequent case - no events */
127 if (! TIME_TimersList)
128 return(ret_time);
129
130 /* since timeSetEvent() and timeKillEvent() can be called
131 * from 16 bit code, there are cases where win16 lock is
132 * locked upon entering timeSetEvent(), and then the mm timer
133 * critical section is locked. This function cannot call the
134 * timer callback with the crit sect locked (because callback
135 * may need to acquire Win16 lock, thus providing a deadlock
136 * situation).
137 * To cope with that, we just copy the WINE_TIMERENTRY struct
138 * that need to trigger the callback, and call it without the
139 * mm timer crit sect locked.
140 * the hKillTimeEvent is used to mark the section where we
141 * handle the callbacks so we can do synchronous kills.
142 * EPP 99/07/13, updated 04/01/10
143 */
144 idx = 0;
146
148 for (ptimer = &TIME_TimersList; *ptimer != NULL; ) {
149 timer = *ptimer;
150 next_ptimer = &timer->lpNext;
151 if (cur_time >= timer->dwTriggerTime)
152 {
153 if (timer->lpFunc) {
154 if (idx == nSizeLpTimers) {
155 if (lpTimers)
156 lpTimers = (LPWINE_TIMERENTRY)
157 HeapReAlloc(GetProcessHeap(), 0, lpTimers,
158 ++nSizeLpTimers * sizeof(WINE_TIMERENTRY));
159 else
160 lpTimers = (LPWINE_TIMERENTRY)
162 ++nSizeLpTimers * sizeof(WINE_TIMERENTRY));
163 }
164 lpTimers[idx++] = *timer;
165
166 }
167
168 /* Update the time after we make the copy to preserve
169 the original trigger time */
170 timer->dwTriggerTime += timer->wDelay;
171
172 /* TIME_ONESHOT is defined as 0 */
173 if (!(timer->wFlags & TIME_PERIODIC))
174 {
175 /* unlink timer from timers list */
176 *ptimer = *next_ptimer;
177 HeapFree(GetProcessHeap(), 0, timer);
178
179 /* We don't need to trigger oneshots again */
180 delta_time = INFINITE;
181 }
182 else
183 {
184 /* Compute when this event needs this function
185 to be called again */
186 if (timer->dwTriggerTime <= cur_time)
187 delta_time = 0;
188 else
189 delta_time = timer->dwTriggerTime - cur_time;
190 }
191 }
192 else
193 delta_time = timer->dwTriggerTime - cur_time;
194
195 /* Determine when we need to return to this function */
196 ret_time = min(ret_time, delta_time);
197
198 ptimer = next_ptimer;
199 }
202
203 while (idx > 0) TIME_TriggerCallBack(&lpTimers[--idx]);
205
206 /* Finally, adjust the recommended wait time downward
207 by the amount of time the processing routines
208 actually took */
209 adjust_time = GetTickCount() - cur_time;
210 if (adjust_time > ret_time)
211 ret_time = 0;
212 else
213 ret_time -= adjust_time;
214
215 /* We return the amount of time our caller should sleep
216 before needing to check in on us again */
217 return(ret_time);
218}
time_t cur_time
#define NULL
Definition: types.h:112
unsigned int idx
Definition: utils.c:41
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapReAlloc
Definition: compat.h:734
#define HeapFree(x, y, z)
Definition: compat.h:735
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
struct tagWINE_TIMERENTRY WINE_TIMERENTRY
static HANDLE TIME_hKillEvent
Definition: time.c:47
static LPWINE_TIMERENTRY TIME_TimersList
Definition: time.c:46
struct tagWINE_TIMERENTRY * LPWINE_TIMERENTRY
static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer)
Definition: time.c:82
#define INFINITE
Definition: serial.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
#define TIME_PERIODIC
Definition: mmsystem.h:422
#define min(a, b)
Definition: monoChain.cc:55
LPTIMECALLBACK lpFunc
Definition: time.c:37
UINT16 wFlags
Definition: time.c:39
struct tagWINE_TIMERENTRY * lpNext
Definition: time.c:42
DWORD dwTriggerTime
Definition: time.c:41
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:714
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
CRITICAL_SECTION WINMM_cs
Definition: winmm.c:53

Referenced by TIME_MMSysTimeThread().

◆ TIME_MMSysTimeThread()

static DWORD CALLBACK TIME_MMSysTimeThread ( LPVOID  arg)
static

Definition at line 223 of file time.c.

224{
225 DWORD sleep_time;
226 DWORD rc;
227
228 TRACE("Starting main winmm thread\n");
229
230 /* FIXME: As an optimization, we could have
231 this thread die when there are no more requests
232 pending, and then get recreated on the first
233 new event; it's not clear if that would be worth
234 it or not. */
235
236 while (! TIME_TimeToDie)
237 {
238 sleep_time = TIME_MMSysTimeCallback();
239
240 if (sleep_time == 0)
241 continue;
242
243 rc = WaitForSingleObject(TIME_hWakeEvent, sleep_time);
244 if (rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0)
245 {
246 FIXME("Unexpected error %ld(%ld) in timer thread\n", rc, GetLastError());
247 break;
248 }
249 }
250 TRACE("Exiting main winmm thread\n");
251 return 0;
252}
#define FIXME(fmt,...)
Definition: debug.h:111
#define WAIT_TIMEOUT
Definition: dderror.h:14
static BOOL TIME_TimeToDie
Definition: time.c:49
static DWORD CALLBACK TIME_MMSysTimeCallback()
Definition: time.c:113
static HANDLE TIME_hWakeEvent
Definition: time.c:48
#define TRACE(s)
Definition: solgame.cpp:4
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define WAIT_OBJECT_0
Definition: winbase.h:406

Referenced by TIME_MMTimeStart().

◆ TIME_MMTimeStart()

void TIME_MMTimeStart ( void  )

Definition at line 257 of file time.c.

258{
259 if (!TIME_hMMTimer) {
265 }
266}
#define FALSE
Definition: types.h:117
BOOL WINAPI SetThreadPriority(IN HANDLE hThread, IN int nPriority)
Definition: thread.c:700
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
static HANDLE TIME_hMMTimer
Definition: time.c:45
static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg)
Definition: time.c:223
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
#define THREAD_PRIORITY_TIME_CRITICAL
Definition: winbase.h:281

Referenced by TIME_SetEventInternal().

◆ TIME_MMTimeStop()

void TIME_MMTimeStop ( void  )

Definition at line 271 of file time.c.

272{
273 if (TIME_hMMTimer) {
274
277
278 /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */
280
283 TIME_hMMTimer = 0;
285 }
286}
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:739

Referenced by WINMM_DeleteIData().

◆ TIME_SetEventInternal()

WORD TIME_SetEventInternal ( UINT  wDelay,
UINT  wResol,
LPTIMECALLBACK  lpFunc,
DWORD  dwUser,
UINT  wFlags 
)

Definition at line 306 of file time.c.

308{
309 WORD wNewID = 0;
310 LPWINE_TIMERENTRY lpNewTimer;
311 LPWINE_TIMERENTRY lpTimer;
312
313 TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser, wFlags);
314
315 if (wDelay < MMSYSTIME_MININTERVAL || wDelay > MMSYSTIME_MAXINTERVAL)
316 return 0;
317
318 lpNewTimer = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY));
319 if (lpNewTimer == NULL)
320 return 0;
321
323
324 lpNewTimer->wDelay = wDelay;
325 lpNewTimer->dwTriggerTime = GetTickCount() + wDelay;
326
327 /* FIXME - wResol is not respected, although it is not clear
328 that we could change our precision meaningfully */
329 lpNewTimer->wResol = wResol;
330 lpNewTimer->lpFunc = lpFunc;
331 lpNewTimer->dwUser = dwUser;
332 lpNewTimer->wFlags = wFlags;
333
335
336 if ((wFlags & TIME_KILL_SYNCHRONOUS) && !TIME_hKillEvent)
338
339 for (lpTimer = TIME_TimersList; lpTimer != NULL; lpTimer = lpTimer->lpNext) {
340 wNewID = max(wNewID, lpTimer->wTimerID);
341 }
342
343 lpNewTimer->lpNext = TIME_TimersList;
344 TIME_TimersList = lpNewTimer;
345 lpNewTimer->wTimerID = wNewID + 1;
346
348
349 /* Wake the service thread in case there is work to be done */
351
352 TRACE("=> %u\n", wNewID + 1);
353
354 return wNewID + 1;
355}
#define MMSYSTIME_MAXINTERVAL
Definition: time.c:79
void TIME_MMTimeStart(void)
Definition: time.c:257
unsigned short WORD
Definition: ntddk_ex.h:93
DWORD dwUser
Definition: time.c:38
UINT16 wTimerID
Definition: time.c:40
#define max(a, b)
Definition: svc.c:63
_In_ DWORD _Out_ _In_ WORD wFlags
Definition: wincon.h:531

Referenced by timeSetEvent().

◆ TIME_TriggerCallBack()

static void TIME_TriggerCallBack ( LPWINE_TIMERENTRY  lpTimer)
static

Definition at line 82 of file time.c.

83{
84 TRACE("%04lx:CallBack => lpFunc=%p wTimerID=%04X dwUser=%08lX dwTriggerTime %ld(delta %ld)\n",
85 GetCurrentThreadId(), lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser,
86 lpTimer->dwTriggerTime, GetTickCount() - lpTimer->dwTriggerTime);
87
88 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
89 * during interrupt time, is allowed to execute very limited number of API calls (like
90 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
91 * guess current implementation via SetTimer has to be improved upon.
92 */
93 switch (lpTimer->wFlags & 0x30) {
95 (lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0);
96 break;
98 SetEvent((HANDLE)lpTimer->lpFunc);
99 break;
101 PulseEvent((HANDLE)lpTimer->lpFunc);
102 break;
103 default:
104 FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n",
105 lpTimer->wFlags, lpTimer->lpFunc);
106 break;
107 }
108}
#define TIME_CALLBACK_EVENT_PULSE
Definition: mmsystem.h:425
#define TIME_CALLBACK_EVENT_SET
Definition: mmsystem.h:424
#define TIME_CALLBACK_FUNCTION
Definition: mmsystem.h:423
BOOL WINAPI DECLSPEC_HOTPATCH PulseEvent(IN HANDLE hEvent)
Definition: synch.c:695
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459

Referenced by TIME_MMSysTimeCallback().

◆ timeBeginPeriod()

MMRESULT WINAPI timeBeginPeriod ( UINT  wPeriod)

Definition at line 423 of file time.c.

424{
425 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
426 return TIMERR_NOCANDO;
427
428 /* High resolution timer requested, use QPC */
429 if (wPeriod <= 5 && TIME_qpcFreq.QuadPart == 0)
430 {
432 TIME_qpcFreq.QuadPart /= 1000;
433 }
434
435 if (wPeriod > MMSYSTIME_MININTERVAL)
436 {
437 WARN("Stub; we set our timer resolution at minimum\n");
438 }
439
440 return 0;
441}
#define WARN(fmt,...)
Definition: debug.h:112
BOOL WINAPI QueryPerformanceFrequency(OUT PLARGE_INTEGER lpFrequency)
Definition: perfcnt.c:45
static LARGE_INTEGER TIME_qpcFreq
Definition: time.c:50
#define MMSYSTIME_MININTERVAL
Definition: time.c:78
#define TIMERR_NOCANDO
Definition: mmsystem.h:419
LONGLONG QuadPart
Definition: typedefs.h:114

Referenced by DirectSoundDevice_Initialize(), and test_timer().

◆ timeEndPeriod()

MMRESULT WINAPI timeEndPeriod ( UINT  wPeriod)

Definition at line 446 of file time.c.

447{
448 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
449 return TIMERR_NOCANDO;
450
451 /* High resolution timer no longer requested, stop using QPC */
452 if (wPeriod <= 5 && TIME_qpcFreq.QuadPart != 0)
454
455 if (wPeriod > MMSYSTIME_MININTERVAL)
456 {
457 WARN("Stub; we set our timer resolution at minimum\n");
458 }
459 return 0;
460}

Referenced by DirectSoundDevice_Release(), DSOUND_timer(), and test_timer().

◆ timeGetDevCaps()

MMRESULT WINAPI timeGetDevCaps ( LPTIMECAPS  lpCaps,
UINT  wSize 
)

Definition at line 401 of file time.c.

402{
403 TRACE("(%p, %u)\n", lpCaps, wSize);
404
405 if (lpCaps == 0) {
406 WARN("invalid lpCaps\n");
407 return TIMERR_NOCANDO;
408 }
409
410 if (wSize < sizeof(TIMECAPS)) {
411 WARN("invalid wSize\n");
412 return TIMERR_NOCANDO;
413 }
414
417 return TIMERR_NOERROR;
418}
#define TIMERR_NOERROR
Definition: mmsystem.h:418
UINT wPeriodMin
Definition: mmsystem.h:1394
UINT wPeriodMax
Definition: mmsystem.h:1395

Referenced by DirectSoundDevice_Initialize(), and test_timeGetDevCaps().

◆ timeGetSystemTime()

MMRESULT WINAPI timeGetSystemTime ( LPMMTIME  lpTime,
UINT  wSize 
)

Definition at line 291 of file time.c.

292{
293
294 if (wSize >= sizeof(*lpTime)) {
295 lpTime->wType = TIME_MS;
296 lpTime->u.ms = GetTickCount();
297
298 }
299
300 return 0;
301}
#define TIME_MS
Definition: mmsystem.h:28
DWORD ms
Definition: mmsystem.h:967
union mmtime_tag::@3042 u
UINT wType
Definition: mmsystem.h:965

◆ timeGetTime()

DWORD WINAPI timeGetTime ( void  )

Definition at line 466 of file time.c.

467{
468 LARGE_INTEGER perfCount;
469#if defined(COMMENTOUTPRIORTODELETING)
470 DWORD count;
471
472 /* FIXME: releasing the win16 lock here is a temporary hack (I hope)
473 * that lets mciavi.drv run correctly
474 */
475 if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count);
476 if (pFnRestoreThunkLock) pFnRestoreThunkLock(count);
477#endif
478 /* Use QPC if a high-resolution timer was requested (<= 5ms) */
479 if (TIME_qpcFreq.QuadPart != 0)
480 {
481 QueryPerformanceCounter(&perfCount);
482 return (DWORD)(perfCount.QuadPart / TIME_qpcFreq.QuadPart);
483 }
484 /* Otherwise continue using GetTickCount */
485 return GetTickCount();
486}
BOOL WINAPI QueryPerformanceCounter(OUT PLARGE_INTEGER lpPerformanceCount)
Definition: perfcnt.c:23
GLuint GLuint GLsizei count
Definition: gl.h:1545

Referenced by NS_AddRemoteComputerAsNameServer(), NS_PruneSessionCache(), and testTimeProc().

◆ timeKillEvent()

MMRESULT WINAPI timeKillEvent ( UINT  wID)

Definition at line 370 of file time.c.

371{
372 LPWINE_TIMERENTRY lpSelf = NULL, *lpTimer;
373
374 TRACE("(%u)\n", wID);
376 /* remove WINE_TIMERENTRY from list */
377 for (lpTimer = &TIME_TimersList; *lpTimer; lpTimer = &(*lpTimer)->lpNext) {
378 if (wID == (*lpTimer)->wTimerID) {
379 lpSelf = *lpTimer;
380 /* unlink timer of id 'wID' */
381 *lpTimer = (*lpTimer)->lpNext;
382 break;
383 }
384 }
386
387 if (!lpSelf)
388 {
389 WARN("wID=%u is not a valid timer ID\n", wID);
390 return MMSYSERR_INVALPARAM;
391 }
392 if (lpSelf->wFlags & TIME_KILL_SYNCHRONOUS)
394 HeapFree(GetProcessHeap(), 0, lpSelf);
395 return TIMERR_NOERROR;
396}
#define MMSYSERR_INVALPARAM
Definition: mmsystem.h:107

Referenced by DirectSoundDevice_Release(), DSOUND_timer(), ScreenSaverProc(), test_priority(), and test_timer().

◆ timeSetEvent()

MMRESULT WINAPI timeSetEvent ( UINT  wDelay,
UINT  wResol,
LPTIMECALLBACK  lpFunc,
DWORD_PTR  dwUser,
UINT  wFlags 
)

Definition at line 360 of file time.c.

362{
363 return TIME_SetEventInternal(wDelay, wResol, lpFunc,
364 dwUser, wFlags);
365}
WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, DWORD dwUser, UINT wFlags)
Definition: time.c:306

Referenced by DirectSoundDevice_Initialize(), ScreenSaverProc(), test_priority(), and test_timer().

◆ WINE_DEFAULT_DEBUG_CHANNEL()

WINE_DEFAULT_DEBUG_CHANNEL ( mmtime  )

Variable Documentation

◆ TIME_hKillEvent

HANDLE TIME_hKillEvent
static

Definition at line 47 of file time.c.

Referenced by TIME_MMSysTimeCallback(), TIME_SetEventInternal(), and timeKillEvent().

◆ TIME_hMMTimer

HANDLE TIME_hMMTimer
static

Definition at line 45 of file time.c.

Referenced by TIME_MMTimeStart(), and TIME_MMTimeStop().

◆ TIME_hWakeEvent

HANDLE TIME_hWakeEvent
static

◆ TIME_qpcFreq

LARGE_INTEGER TIME_qpcFreq
static

Definition at line 50 of file time.c.

Referenced by timeBeginPeriod(), timeEndPeriod(), and timeGetTime().

◆ TIME_TimersList

LPWINE_TIMERENTRY TIME_TimersList
static

◆ TIME_TimeToDie

BOOL TIME_TimeToDie = TRUE
static

Definition at line 49 of file time.c.

Referenced by TIME_MMSysTimeThread(), TIME_MMTimeStart(), and TIME_MMTimeStop().