source: trunk/src/winmm/os2timer.cpp@ 9916

Last change on this file since 9916 was 9916, checked in by sandervl, 22 years ago

Improved accuracy of waveIn/OutGetPosition. (use FPU to prevent rounding errors)

File size: 13.4 KB
Line 
1/* $Id: os2timer.cpp,v 1.21 2003-03-06 15:42:33 sandervl Exp $ */
2
3/*
4 * OS/2 Timer class
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1999 Patrick Haller (phaller@gmx.net)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13
14/****************************************************************************
15 * Includes *
16 ****************************************************************************/
17
18#define INCL_DOSPROCESS
19#define INCL_DOSDATETIME
20#define INCL_DOSSEMAPHORES
21#include <os2wrap.h> //Odin32 OS/2 api wrappers
22#include <process.h>
23#include <win32type.h>
24#include <win32api.h>
25#include <wprocess.h>
26#include <dbglog.h>
27#include <vmutex.h>
28
29#include "time.h"
30#include "os2timer.h"
31
32#define DBG_LOCALLOG DBG_os2timer
33#include "dbglocal.h"
34
35
36/****************************************************************************
37 * Structures *
38 ****************************************************************************/
39static VMutex timeMutex;
40
41/****************************************************************************
42 * Local Prototypes *
43 ****************************************************************************/
44
45static DWORD WIN32API TimerHlpHandler(LPVOID timer);
46
47
48
49/****************************************************************************
50 * Class: OS2TimerResolution *
51 ****************************************************************************/
52
53
54/*****************************************************************************
55 * Name : OS2TimerResolution::OS2TimerResolution
56 * Purpose : create a new entry in the resolution stack
57 * Parameters: -
58 * Variables :
59 * Result :
60 * Remark :
61 * Status : UNTESTED STUB
62 *
63 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
64 *****************************************************************************/
65
66OS2TimerResolution::OS2TimerResolution(int dwPeriod)
67 : next(NULL)
68{
69 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::OS2TimerResolution(%08xh,%08xh)\n",
70 this,
71 dwPeriod));
72
73 timeMutex.enter();
74 // add to linked list
75 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
76
77 if(timeRes != NULL)
78 {
79 while(timeRes->next != NULL)
80 {
81 timeRes = timeRes->next;
82 }
83 timeRes->next = this;
84 }
85 else
86 OS2TimerResolution::sTimerResolutions = this;
87
88 timeMutex.leave();
89
90 this->dwPeriod = dwPeriod;
91}
92
93
94/*****************************************************************************
95 * Name : OS2TimerResolution::~OS2TimerResolution
96 * Purpose : remove entry from the linked list
97 * Parameters:
98 * Variables :
99 * Result :
100 * Remark :
101 * Status : UNTESTED STUB
102 *
103 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
104 *****************************************************************************/
105
106OS2TimerResolution::~OS2TimerResolution()
107{
108 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::~OS2TimerResolution(%08xh)\n",
109 this));
110
111
112 timeMutex.enter();
113
114 // remove from linked list
115 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
116
117 // leaveResolutionScope() if still entered???
118
119 if(timeRes != this)
120 {
121 while(timeRes->next != this)
122 {
123 timeRes = timeRes->next;
124 }
125 timeRes->next = this->next;
126 }
127 else
128 OS2TimerResolution::sTimerResolutions = timeRes->next;
129
130 timeMutex.leave();
131}
132
133
134/*****************************************************************************
135 * Name : OS2TimerResolution::enterResolutionScope
136 * Purpose : set the currently requested timer resolution for this entry
137 * Parameters:
138 * Variables :
139 * Result :
140 * Remark :
141 * Status : UNTESTED STUB
142 *
143 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
144 *****************************************************************************/
145
146BOOL OS2TimerResolution::enterResolutionScope(int dwPeriod)
147{
148 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::enterResolutionScope(%08xh)\n",
149 dwPeriod));
150
151 OS2TimerResolution* timeRes = new OS2TimerResolution(dwPeriod);
152 if (timeRes != NULL)
153 return TRUE;
154 else
155 return FALSE;
156}
157
158
159/*****************************************************************************
160 * Name : OS2TimerResolution::leaveResolutionScope
161 * Purpose : remove specified entry from the list if periods match
162 * Parameters: int dwPeriod
163 * Variables :
164 * Result : TRUE or FALSE
165 * Remark :
166 * Status : UNTESTED STUB
167 *
168 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
169 *****************************************************************************/
170
171BOOL OS2TimerResolution::leaveResolutionScope(int dwPeriod)
172{
173 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::leaveResolutionScope(%08xh)\n",
174 dwPeriod));
175
176 timeMutex.enter();
177 OS2TimerResolution* timeRes = OS2TimerResolution::sTimerResolutions;
178
179 if (timeRes != NULL)
180 {
181 for(; // walk to the end of the list
182 timeRes->next != NULL;
183 timeRes = timeRes->next)
184 ;
185
186 if (timeRes->dwPeriod == dwPeriod) // do the requested period match?
187 {
188 delete timeRes; // so delete that object
189 timeMutex.leave();
190 return TRUE; // OK, can remove the entry
191 }
192 }
193 timeMutex.leave();
194
195 return FALSE; // nope, mismatch !
196}
197
198
199/*****************************************************************************
200 * Name : OS2TimerResolution::queryCurrentResolution
201 * Purpose : determine the minimum resolution currently requested
202 * Parameters:
203 * Variables :
204 * Result :
205 * Remark :
206 * Status : UNTESTED STUB
207 *
208 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
209 *****************************************************************************/
210
211int OS2TimerResolution::queryCurrentResolution()
212{
213 timeMutex.enter();
214 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
215 int iMin = -1;
216
217 if (timeRes != NULL) // do we have an entry yet?
218 for (; // walk the linked list
219 timeRes->next != NULL;
220 timeRes = timeRes->next)
221 {
222 if (timeRes->dwPeriod < iMin) // determine minimum time period
223 iMin = timeRes->dwPeriod;
224 }
225 timeMutex.leave();
226
227 dprintf(("WINMM:OS2Timer: OS2TimerResolution::queryCurrentResolution == %08xh\n",
228 iMin));
229
230 return iMin;
231}
232
233
234
235
236
237/******************************************************************************/
238/******************************************************************************/
239OS2Timer::OS2Timer() : TimerSem(0), TimerHandle(0), hTimerThread(0),
240 clientCallback(NULL), TimerStatus(Stopped), fFatal(FALSE),
241 next(NULL), timerID(0)
242{
243 dprintf(("WINMM:OS2Timer: OS2Timer::OS2Timer(%08xh)\n",
244 this));
245
246 timeMutex.enter();
247 OS2Timer *timer = OS2Timer::timers;
248
249 if(timer != NULL)
250 {
251 while(timer->next != NULL)
252 {
253 timer = timer->next;
254 }
255 timer->next = this;
256 }
257 else
258 timers = this;
259 timeMutex.leave();
260
261 // create timer semaphore
262 int rc = DosCreateEventSem(NULL, &TimerSem, DC_SEM_SHARED, 0);
263 if(rc != 0)
264 {
265 dprintf(("WINMM: OS2Timer: DosCreateEventSem failed rc=#%08xh\n", rc));
266 return; // terminate thread
267 }
268
269
270 //hTimerThread = _beginthread(TimerHlpHandler, NULL, 0x4000, (void *)this);
271 hTimerThread = CreateThread(NULL,
272 0x4000,
273 TimerHlpHandler,
274 (LPVOID)this,
275 0, // thread creation flags
276 &TimerThreadID);
277
278 if (hTimerThread == NULL)
279 {
280 dprintf(("WINMM: OS2Timer: CreateThread failed rc=#%08xh\n",
281 GetLastError()));
282 DosCloseEventSem(TimerSem);
283 }
284}
285/******************************************************************************/
286/******************************************************************************/
287OS2Timer::~OS2Timer()
288{
289 dprintf(("WINMM:OS2Timer: OS2Timer::~OS2Timer(%08xh)\n",
290 this));
291
292 KillTimer();
293
294 timeMutex.enter();
295 OS2Timer *timer = OS2Timer::timers;
296
297 if(timer != this)
298 {
299 while(timer->next != this)
300 {
301 timer = timer->next;
302 }
303 timer->next = this->next;
304 }
305 else
306 timers = timer->next;
307
308 timeMutex.leave();
309}
310/******************************************************************************/
311/******************************************************************************/
312BOOL OS2Timer::StartTimer(int period,
313 int resolution,
314 LPTIMECALLBACK lptc,
315 int dwUser,
316 int fuEvent)
317{
318 dprintf(("WINMM:OS2Timer: OS2Timer::StartTimer(%08xh, %08xh, %08xh, %08xh, %08xh, %08xh)\n",
319 this,
320 period,
321 resolution,
322 lptc,
323 dwUser,
324 fuEvent));
325
326 APIRET rc;
327
328 // has the thread been created properly?
329 if(hTimerThread == NULLHANDLE)
330 return(FALSE);
331
332 if(TimerStatus == Stopped)
333 {
334 clientCallback = lptc; // callback data (id / addr)
335 userData = dwUser; // user-supplied data
336 dwFlags = fuEvent; // type of timer / callback
337
338 if(fuEvent & TIME_PERIODIC)
339 rc = DosStartTimer(period, (HSEM)TimerSem, &TimerHandle);
340 else
341 rc = DosAsyncTimer(period, (HSEM)TimerSem, &TimerHandle);
342
343 if(rc)
344 {
345
346#ifdef DEBUG
347 if(fuEvent & TIME_PERIODIC)
348 WriteLog("DosStartTimer failed %d\n", rc);
349 else
350 WriteLog("DosAsyncTimer failed %d\n", rc);
351#endif
352
353 return(FALSE);
354 }
355
356 TimerStatus = Running;
357 }
358 else
359 return(FALSE); //already running (must use timeKillEvent first)
360
361 return(TRUE);
362}
363/******************************************************************************/
364/******************************************************************************/
365void OS2Timer::StopTimer()
366{
367 dprintf(("WINMM:OS2Timer: OS2Timer::StopTimer(%08xh)\n",
368 this));
369
370 if(TimerStatus == Running)
371 {
372 DosStopTimer(TimerHandle);
373 TimerStatus = Stopped;
374 }
375}
376/******************************************************************************/
377/******************************************************************************/
378void OS2Timer::KillTimer()
379{
380 dprintf(("WINMM:OS2Timer: OS2Timer::KillTimer(%08xh)\n",
381 this));
382
383 fFatal = TRUE;
384
385 StopTimer();
386
387 if(DosPostEventSem(TimerSem))
388 {
389 //something went wrong, kill the thread
390 TerminateThread(hTimerThread, -1);
391 }
392 TimerStatus = InActive;
393}
394/******************************************************************************/
395//******************************************************************************
396void OS2Timer::TimerHandler()
397{
398 ULONG Count = 0;
399 APIRET rc = 0; /* Return code */
400 USHORT selTIB;
401
402 dprintf(("WINMM: TimerHandler thread created (%08xh)\n",
403 this));
404
405 rc = DosSetPriority (PRTYS_THREAD, /* Change a single thread */
406 PRTYC_TIMECRITICAL, /* Time critical class */
407 0L, /* Increase by 15 */
408 0L); /* Assume current thread */
409
410 while(!fFatal)
411 {
412 dprintf(("WINMM: OS2Timer::TimerHandler waiting on timer (%04xh, %08xh\n",
413 dwFlags,
414 clientCallback));
415
416 DosWaitEventSem(TimerSem, SEM_INDEFINITE_WAIT);
417 DosResetEventSem(TimerSem, &Count);
418 if(!fFatal)
419 {
420 // @@@PH: we're calling the client with PRTYC_TIMECRITICAL !!!
421 // It'd be much nicer to call with original priority!
422
423 // check timer running condition
424 if (TimerStatus == Running)
425 {
426 dprintf(("WINMM: OS2Timer::TimerHandler firing (%04xh, %08xh\n",
427 dwFlags,
428 clientCallback));
429
430 // process the event
431 switch (dwFlags & 0x0030)
432 {
433 case TIME_CALLBACK_FUNCTION:
434 if (clientCallback != NULL)
435 {
436 selTIB = SetWin32TIB();
437 clientCallback((UINT)timerID, 0, userData, 0, 0);
438 SetFS(selTIB);
439 }
440 break;
441
442 case TIME_CALLBACK_EVENT_SET:
443 SetEvent( (HANDLE)clientCallback );
444 break;
445
446 case TIME_CALLBACK_EVENT_PULSE:
447 PulseEvent( (HANDLE)clientCallback );
448 break;
449
450 default:
451 dprintf(("WINMM: OS2Timer %08xh: unknown type for mmtime callback(%08xh)\n",
452 this,
453 dwFlags));
454 }
455 }
456 }
457 }
458
459 // last message
460 dprintf(("WINMM: OS2Timer: Timer thread terminating (%08xh)\n",
461 this));
462
463 DosCloseEventSem(TimerSem);
464
465 // mark this thread as terminated
466 ExitThread(0);
467}
468//******************************************************************************
469//******************************************************************************
470static DWORD WIN32API TimerHlpHandler(LPVOID timer)
471{
472 ((OS2Timer *)timer)->TimerHandler();
473
474 return 0;
475}
476
477
478//******************************************************************************
479//******************************************************************************
480OS2TimerResolution *OS2TimerResolution::sTimerResolutions = NULL;
481OS2Timer *OS2Timer::timers = NULL;
482int OS2Timer::timerPeriod = 0;
483
Note: See TracBrowser for help on using the repository browser.