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

Last change on this file since 6933 was 6933, checked in by sandervl, 24 years ago

prevent multiple delete actions for the same timer

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