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

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

Fix: WINMM: OS2Timer stuff

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