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

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

Fix: MM-timers should now use correct calling convention

File size: 11.1 KB
Line 
1/* $Id: os2timer.cpp,v 1.11 1999-08-31 16:41:48 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{
80 // add to linked list
81 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
82
83 if(timeRes != NULL)
84 {
85 while(timeRes->next != NULL)
86 {
87 timeRes = timeRes->next;
88 }
89 timeRes->next = this;
90 }
91 else
92 OS2TimerResolution::sTimerResolutions = this;
93
94 this->dwPeriod = dwPeriod;
95}
96
97
98/*****************************************************************************
99 * Name : OS2TimerResolution::~OS2TimerResolution
100 * Purpose : remove entry from the linked list
101 * Parameters:
102 * Variables :
103 * Result :
104 * Remark :
105 * Status : UNTESTED STUB
106 *
107 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
108 *****************************************************************************/
109
110OS2TimerResolution::~OS2TimerResolution()
111{
112 // remove from linked list
113 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
114
115 // leaveResolutionScope() if still entered???
116
117 if(timeRes != this)
118 {
119 while(timeRes->next != this)
120 {
121 timeRes = timeRes->next;
122 }
123 timeRes->next = this->next;
124 }
125 else
126 OS2TimerResolution::sTimerResolutions = timeRes->next;
127}
128
129
130/*****************************************************************************
131 * Name : OS2TimerResolution::enterResolutionScope
132 * Purpose : set the currently requested timer resolution for this entry
133 * Parameters:
134 * Variables :
135 * Result :
136 * Remark :
137 * Status : UNTESTED STUB
138 *
139 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
140 *****************************************************************************/
141
142BOOL OS2TimerResolution::enterResolutionScope(int dwPeriod)
143{
144 OS2TimerResolution* timeRes = new OS2TimerResolution(dwPeriod);
145 if (timeRes != NULL)
146 return TRUE;
147 else
148 return FALSE;
149}
150
151
152/*****************************************************************************
153 * Name : OS2TimerResolution::leaveResolutionScope
154 * Purpose : remove specified entry from the list if periods match
155 * Parameters: int dwPeriod
156 * Variables :
157 * Result : TRUE or FALSE
158 * Remark :
159 * Status : UNTESTED STUB
160 *
161 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
162 *****************************************************************************/
163
164BOOL OS2TimerResolution::leaveResolutionScope(int dwPeriod)
165{
166 OS2TimerResolution* timeRes = OS2TimerResolution::sTimerResolutions;
167
168 if (timeRes != NULL)
169 {
170 for(; // walk to the end of the list
171 timeRes->next != NULL;
172 timeRes = timeRes->next)
173 ;
174
175 if (timeRes->dwPeriod == dwPeriod) // do the requested period match?
176 {
177 delete timeRes; // so delete that object
178 return TRUE; // OK, can remove the entry
179 }
180 }
181 return FALSE; // nope, mismatch !
182}
183
184
185/*****************************************************************************
186 * Name : OS2TimerResolution::queryCurrentResolution
187 * Purpose : determine the minimum resolution currently requested
188 * Parameters:
189 * Variables :
190 * Result :
191 * Remark :
192 * Status : UNTESTED STUB
193 *
194 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
195 *****************************************************************************/
196
197int OS2TimerResolution::queryCurrentResolution()
198{
199 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
200 int iMin = -1;
201
202 if (timeRes != NULL) // do we have an entry yet?
203 for (; // walk the linked list
204 timeRes->next != NULL;
205 timeRes = timeRes->next)
206 {
207 if (timeRes->dwPeriod < iMin) // determine minimum time period
208 iMin = timeRes->dwPeriod;
209 }
210
211 return iMin;
212}
213
214
215
216
217
218/******************************************************************************/
219/******************************************************************************/
220OS2Timer::OS2Timer() : TimerSem(0), TimerHandle(0), TimerThreadID(0),
221 clientCallback(NULL), TimerStatus(Stopped), fFatal(FALSE)
222{
223 OS2Timer *timer = OS2Timer::timers;
224
225 if(timer != NULL)
226 {
227 while(timer->next != NULL)
228 {
229 timer = timer->next;
230 }
231 timer->next = this;
232 }
233 else
234 timers = this;
235
236 //TimerThreadID = _beginthread(TimerHlpHandler, NULL, 0x4000, (void *)this);
237 hTimerThread = CreateThread(NULL,
238 0x1000,
239 (LPTHREAD_START_ROUTINE)TimerHlpHandler,
240 (LPVOID)this,
241 0, // thread creation flags
242 &TimerThreadID);
243
244
245 //@@@PH: CreateThread() should be used instead
246 //@@@PH: logic sux ... waits for creation of semaphores
247 DosSleep(100);
248}
249/******************************************************************************/
250/******************************************************************************/
251OS2Timer::~OS2Timer()
252{
253 OS2Timer *timer = OS2Timer::timers;
254
255 KillTimer();
256
257 if(timer != this)
258 {
259 while(timer->next != this)
260 {
261 timer = timer->next;
262 }
263 timer->next = this->next;
264 }
265 else
266 timers = timer->next;
267}
268/******************************************************************************/
269/******************************************************************************/
270BOOL OS2Timer::StartTimer(int period,
271 int resolution,
272 LPTIMECALLBACK lptc,
273 int dwUser,
274 int fuEvent)
275{
276 APIRET rc;
277
278 if(TimerThreadID == -1)
279 {
280 return(FALSE);
281 }
282
283 if(TimerStatus == Stopped)
284 {
285 clientCallback = lptc;
286 userData = dwUser;
287
288 if(fuEvent == TIME_PERIODIC)
289 rc = DosStartTimer(period, (HSEM)TimerSem, &TimerHandle);
290 else
291 rc = DosAsyncTimer(period, (HSEM)TimerSem, &TimerHandle);
292
293 if(rc)
294 {
295
296#ifdef DEBUG
297 if(fuEvent == TIME_PERIODIC)
298 WriteLog("DosStartTimer failed %d\n", rc);
299 else
300 WriteLog("DosAsyncTimer failed %d\n", rc);
301#endif
302
303 return(FALSE);
304 }
305
306 TimerStatus = Running;
307 }
308 else
309 return(FALSE); //already running (must use timeKillEvent first)
310
311 return(TRUE);
312}
313/******************************************************************************/
314/******************************************************************************/
315void OS2Timer::StopTimer()
316{
317 if(TimerStatus == Running)
318 {
319 DosStopTimer(TimerHandle);
320 TimerStatus = Stopped;
321 }
322}
323/******************************************************************************/
324/******************************************************************************/
325void OS2Timer::KillTimer()
326{
327 fFatal = TRUE;
328 DosStopTimer(TimerHandle);
329 if(DosPostEventSem(TimerSem))
330 { //something went wrong
331 DosKillThread(TimerThreadID);
332 DosCloseEventSem(TimerSem);
333 }
334 TimerStatus = InActive;
335}
336/******************************************************************************/
337//******************************************************************************
338void OS2Timer::TimerHandler()
339{
340 ULONG Count = 0;
341 APIRET rc = 0; /* Return code */
342 USHORT selTIB;
343
344 dprintf(("WINMM: TimerHandler thread created\n"));
345
346 rc = DosSetPriority (PRTYS_THREAD, /* Change a single thread */
347 PRTYC_TIMECRITICAL, /* Time critical class */
348 0L, /* Increase by 15 */
349 0L); /* Assume current thread */
350
351 rc = DosCreateEventSem(NULL, &TimerSem, DC_SEM_SHARED, 0);
352 if(rc != 0)
353 {
354 dprintf(("WINMM: OS2Timer: DosCreateEventSem failed rc=#%08xh\n", rc));
355 return; // terminate thread
356 }
357
358 TimerStatus = Stopped;
359
360 while(!fFatal)
361 {
362 DosWaitEventSem(TimerSem, SEM_INDEFINITE_WAIT);
363 DosResetEventSem(TimerSem, &Count);
364 if(!fFatal)
365 {
366 // @@@PH: we're calling the client with PRTYC_TIMECRITICAL !!!
367 // It'd be much nicer to call with original priority!
368
369 selTIB = SetWin32TIB();
370 clientCallback((UINT)this, 0, userData, 0, 0);
371 SetFS(selTIB);
372 }
373 }
374 DosCloseEventSem(TimerSem);
375}
376//******************************************************************************
377//******************************************************************************
378//static void _Optlink TimerHlpHandler(void *timer)
379static DWORD _System TimerHlpHandler(LPVOID timer)
380{
381 ((OS2Timer *)timer)->TimerHandler();
382
383 //_endthread(); isn't really required
384 return 0;
385}
386
387
388//******************************************************************************
389//******************************************************************************
390OS2TimerResolution *OS2TimerResolution::sTimerResolutions = NULL;
391OS2Timer *OS2Timer::timers = NULL;
392int OS2Timer::timerPeriod = 0;
393
Note: See TracBrowser for help on using the repository browser.