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

Last change on this file since 4355 was 4355, checked in by phaller, 25 years ago

Fix for timers

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