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

Last change on this file since 2242 was 2242, checked in by phaller, 26 years ago

Fix: memory leak in Dart thread callback functions

File size: 12.2 KB
Line 
1/* $Id: os2timer.cpp,v 1.13 1999-12-29 08:33:56 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
31
32/****************************************************************************
33 * Structures *
34 ****************************************************************************/
35
36
37/***********************************
38 * PH: fixups for missing os2win.h *
39 ***********************************/
40
41extern "C"
42{
43 typedef DWORD (* CALLBACK LPTHREAD_START_ROUTINE)(LPVOID);
44
45 HANDLE WIN32API CreateThread(LPSECURITY_ATTRIBUTES lpsa,
46 DWORD cbStack,
47 LPTHREAD_START_ROUTINE lpStartAddr,
48 LPVOID lpvThreadParm,
49 DWORD fdwCreate,
50 LPDWORD lpIDThread);
51}
52
53/****************************************************************************
54 * Local Prototypes *
55 ****************************************************************************/
56
57static DWORD _System TimerHlpHandler(LPVOID timer);
58
59
60
61/****************************************************************************
62 * Class: OS2TimerResolution *
63 ****************************************************************************/
64
65
66/*****************************************************************************
67 * Name : OS2TimerResolution::OS2TimerResolution
68 * Purpose : create a new entry in the resolution stack
69 * Parameters: -
70 * Variables :
71 * Result :
72 * Remark :
73 * Status : UNTESTED STUB
74 *
75 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
76 *****************************************************************************/
77
78OS2TimerResolution::OS2TimerResolution(int dwPeriod)
79 : next(NULL)
80{
81 dprintf(("WINMM:OS2Timer: OS2TimerResolution::OS2TimerResolution(%08xh,%08xh)\n",
82 this,
83 dwPeriod));
84
85 // add to linked list
86 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
87
88 if(timeRes != NULL)
89 {
90 while(timeRes->next != NULL)
91 {
92 timeRes = timeRes->next;
93 }
94 timeRes->next = this;
95 }
96 else
97 OS2TimerResolution::sTimerResolutions = this;
98
99 this->dwPeriod = dwPeriod;
100}
101
102
103/*****************************************************************************
104 * Name : OS2TimerResolution::~OS2TimerResolution
105 * Purpose : remove entry from the linked list
106 * Parameters:
107 * Variables :
108 * Result :
109 * Remark :
110 * Status : UNTESTED STUB
111 *
112 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
113 *****************************************************************************/
114
115OS2TimerResolution::~OS2TimerResolution()
116{
117 dprintf(("WINMM:OS2Timer: OS2TimerResolution::~OS2TimerResolution(%08xh)\n",
118 this));
119
120
121 // remove from linked list
122 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
123
124 // leaveResolutionScope() if still entered???
125
126 if(timeRes != this)
127 {
128 while(timeRes->next != this)
129 {
130 timeRes = timeRes->next;
131 }
132 timeRes->next = this->next;
133 }
134 else
135 OS2TimerResolution::sTimerResolutions = timeRes->next;
136}
137
138
139/*****************************************************************************
140 * Name : OS2TimerResolution::enterResolutionScope
141 * Purpose : set the currently requested timer resolution for this entry
142 * Parameters:
143 * Variables :
144 * Result :
145 * Remark :
146 * Status : UNTESTED STUB
147 *
148 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
149 *****************************************************************************/
150
151BOOL OS2TimerResolution::enterResolutionScope(int dwPeriod)
152{
153 dprintf(("WINMM:OS2Timer: OS2TimerResolution::enterResolutionScope(%08xh)\n",
154 dwPeriod));
155
156 OS2TimerResolution* timeRes = new OS2TimerResolution(dwPeriod);
157 if (timeRes != NULL)
158 return TRUE;
159 else
160 return FALSE;
161}
162
163
164/*****************************************************************************
165 * Name : OS2TimerResolution::leaveResolutionScope
166 * Purpose : remove specified entry from the list if periods match
167 * Parameters: int dwPeriod
168 * Variables :
169 * Result : TRUE or FALSE
170 * Remark :
171 * Status : UNTESTED STUB
172 *
173 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
174 *****************************************************************************/
175
176BOOL OS2TimerResolution::leaveResolutionScope(int dwPeriod)
177{
178 dprintf(("WINMM:OS2Timer: OS2TimerResolution::leaveResolutionScope(%08xh)\n",
179 dwPeriod));
180
181 OS2TimerResolution* timeRes = OS2TimerResolution::sTimerResolutions;
182
183 if (timeRes != NULL)
184 {
185 for(; // walk to the end of the list
186 timeRes->next != NULL;
187 timeRes = timeRes->next)
188 ;
189
190 if (timeRes->dwPeriod == dwPeriod) // do the requested period match?
191 {
192 delete timeRes; // so delete that object
193 return TRUE; // OK, can remove the entry
194 }
195 }
196 return FALSE; // nope, mismatch !
197}
198
199
200/*****************************************************************************
201 * Name : OS2TimerResolution::queryCurrentResolution
202 * Purpose : determine the minimum resolution currently requested
203 * Parameters:
204 * Variables :
205 * Result :
206 * Remark :
207 * Status : UNTESTED STUB
208 *
209 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
210 *****************************************************************************/
211
212int OS2TimerResolution::queryCurrentResolution()
213{
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
226 dprintf(("WINMM:OS2Timer: OS2TimerResolution::queryCurrentResolution == %08xh\n",
227 iMin));
228
229 return iMin;
230}
231
232
233
234
235
236/******************************************************************************/
237/******************************************************************************/
238OS2Timer::OS2Timer() : TimerSem(0), TimerHandle(0), TimerThreadID(0),
239 clientCallback(NULL), TimerStatus(Stopped), fFatal(FALSE),
240 next(NULL)
241{
242 dprintf(("WINMM:OS2Timer: OS2Timer::OS2Timer(%08xh)\n",
243 this));
244
245 OS2Timer *timer = OS2Timer::timers;
246
247 if(timer != NULL)
248 {
249 while(timer->next != NULL)
250 {
251 timer = timer->next;
252 }
253 timer->next = this;
254 }
255 else
256 timers = this;
257
258 //TimerThreadID = _beginthread(TimerHlpHandler, NULL, 0x4000, (void *)this);
259 hTimerThread = CreateThread(NULL,
260 0x4000,
261 (LPTHREAD_START_ROUTINE)TimerHlpHandler,
262 (LPVOID)this,
263 0, // thread creation flags
264 &TimerThreadID);
265
266
267 //@@@PH: CreateThread() should be used instead
268 //@@@PH: logic sux ... waits for creation of semaphores
269 DosSleep(100);
270}
271/******************************************************************************/
272/******************************************************************************/
273OS2Timer::~OS2Timer()
274{
275 dprintf(("WINMM:OS2Timer: OS2Timer::~OS2Timer(%08xh)\n",
276 this));
277
278 OS2Timer *timer = OS2Timer::timers;
279
280 KillTimer();
281
282 if(timer != this)
283 {
284 while(timer->next != this)
285 {
286 timer = timer->next;
287 }
288 timer->next = this->next;
289 }
290 else
291 timers = timer->next;
292}
293/******************************************************************************/
294/******************************************************************************/
295BOOL OS2Timer::StartTimer(int period,
296 int resolution,
297 LPTIMECALLBACK lptc,
298 int dwUser,
299 int fuEvent)
300{
301 dprintf(("WINMM:OS2Timer: OS2Timer::StartTimer(%08xh, %08xh, %08xh, %08xh, %08xh, %08xh)\n",
302 this,
303 period,
304 resolution,
305 lptc,
306 dwUser,
307 fuEvent));
308
309 APIRET rc;
310
311 if(TimerThreadID == -1)
312 return(FALSE);
313
314 if(TimerStatus == Stopped)
315 {
316 clientCallback = lptc;
317 userData = dwUser;
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 DosStopTimer(TimerHandle);
366 if(DosPostEventSem(TimerSem))
367 { //something went wrong
368 DosKillThread(TimerThreadID);
369 DosCloseEventSem(TimerSem);
370 }
371 TimerStatus = InActive;
372}
373/******************************************************************************/
374//******************************************************************************
375void OS2Timer::TimerHandler()
376{
377 ULONG Count = 0;
378 APIRET rc = 0; /* Return code */
379 USHORT selTIB;
380
381 dprintf(("WINMM: TimerHandler thread created (%08xh)\n",
382 this));
383
384 rc = DosSetPriority (PRTYS_THREAD, /* Change a single thread */
385 PRTYC_TIMECRITICAL, /* Time critical class */
386 0L, /* Increase by 15 */
387 0L); /* Assume current thread */
388
389 rc = DosCreateEventSem(NULL, &TimerSem, DC_SEM_SHARED, 0);
390 if(rc != 0)
391 {
392 dprintf(("WINMM: OS2Timer: DosCreateEventSem failed rc=#%08xh\n", rc));
393 return; // terminate thread
394 }
395
396 TimerStatus = Stopped;
397
398 while(!fFatal)
399 {
400 DosWaitEventSem(TimerSem, SEM_INDEFINITE_WAIT);
401 DosResetEventSem(TimerSem, &Count);
402 if(!fFatal)
403 {
404 // @@@PH: we're calling the client with PRTYC_TIMECRITICAL !!!
405 // It'd be much nicer to call with original priority!
406
407 selTIB = SetWin32TIB();
408 clientCallback((UINT)this, 0, userData, 0, 0);
409 SetFS(selTIB);
410 }
411 }
412 DosCloseEventSem(TimerSem);
413}
414//******************************************************************************
415//******************************************************************************
416//static void _Optlink TimerHlpHandler(void *timer)
417static DWORD _System TimerHlpHandler(LPVOID timer)
418{
419 ((OS2Timer *)timer)->TimerHandler();
420
421 //_endthread(); isn't really required
422 return 0;
423}
424
425
426//******************************************************************************
427//******************************************************************************
428OS2TimerResolution *OS2TimerResolution::sTimerResolutions = NULL;
429OS2Timer *OS2Timer::timers = NULL;
430int OS2Timer::timerPeriod = 0;
431
Note: See TracBrowser for help on using the repository browser.