source: trunk/src/winmm/os2timer.cpp

Last change on this file was 21933, checked in by dmik, 14 years ago

winmm: Restore normal priority when calling timer funciton.

This should prevent the callback code from working at the high
priority used for waiting on timer signals.

File size: 14.3 KB
RevLine 
[10269]1/* $Id: os2timer.cpp,v 1.22 2003-10-13 09:18:37 sandervl Exp $ */
[95]2
[4]3/*
4 * OS/2 Timer class
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
[756]7 * Copyright 1999 Patrick Haller (phaller@gmx.net)
[4]8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
[588]12
13
14/****************************************************************************
15 * Includes *
16 ****************************************************************************/
17
[4]18#define INCL_DOSPROCESS
19#define INCL_DOSDATETIME
20#define INCL_DOSSEMAPHORES
[588]21#include <os2wrap.h> //Odin32 OS/2 api wrappers
[4]22#include <process.h>
[756]23#include <win32type.h>
[5358]24#include <win32api.h>
[668]25#include <wprocess.h>
[9902]26#include <dbglog.h>
27#include <vmutex.h>
[756]28
29#include "time.h"
[4]30#include "os2timer.h"
31
[2812]32#define DBG_LOCALLOG DBG_os2timer
33#include "dbglocal.h"
[588]34
[663]35
36/****************************************************************************
37 * Structures *
38 ****************************************************************************/
[9902]39static VMutex timeMutex;
[759]40
[756]41/****************************************************************************
42 * Local Prototypes *
43 ****************************************************************************/
[663]44
[5358]45static DWORD WIN32API TimerHlpHandler(LPVOID timer);
[663]46
47
48
49/****************************************************************************
[756]50 * Class: OS2TimerResolution *
[663]51 ****************************************************************************/
52
[4]53
[756]54/*****************************************************************************
55 * Name : OS2TimerResolution::OS2TimerResolution
56 * Purpose : create a new entry in the resolution stack
57 * Parameters: -
58 * Variables :
59 * Result :
60 * Remark :
61 * Status : UNTESTED STUB
62 *
63 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
64 *****************************************************************************/
[588]65
[756]66OS2TimerResolution::OS2TimerResolution(int dwPeriod)
[763]67 : next(NULL)
[756]68{
[9916]69 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::OS2TimerResolution(%08xh,%08xh)\n",
[2242]70 this,
71 dwPeriod));
72
[9902]73 timeMutex.enter();
[756]74 // add to linked list
75 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
[663]76
[756]77 if(timeRes != NULL)
78 {
79 while(timeRes->next != NULL)
80 {
81 timeRes = timeRes->next;
82 }
83 timeRes->next = this;
84 }
85 else
86 OS2TimerResolution::sTimerResolutions = this;
[663]87
[9902]88 timeMutex.leave();
89
[756]90 this->dwPeriod = dwPeriod;
91}
92
93
94/*****************************************************************************
95 * Name : OS2TimerResolution::~OS2TimerResolution
96 * Purpose : remove entry from the linked list
97 * Parameters:
98 * Variables :
99 * Result :
100 * Remark :
101 * Status : UNTESTED STUB
102 *
103 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
104 *****************************************************************************/
105
106OS2TimerResolution::~OS2TimerResolution()
107{
[9916]108 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::~OS2TimerResolution(%08xh)\n",
[2242]109 this));
110
111
[9902]112 timeMutex.enter();
113
[756]114 // remove from linked list
115 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
116
117 // leaveResolutionScope() if still entered???
118
119 if(timeRes != this)
120 {
121 while(timeRes->next != this)
122 {
123 timeRes = timeRes->next;
124 }
125 timeRes->next = this->next;
126 }
127 else
128 OS2TimerResolution::sTimerResolutions = timeRes->next;
[9902]129
130 timeMutex.leave();
[756]131}
132
133
134/*****************************************************************************
135 * Name : OS2TimerResolution::enterResolutionScope
136 * Purpose : set the currently requested timer resolution for this entry
137 * Parameters:
138 * Variables :
139 * Result :
140 * Remark :
141 * Status : UNTESTED STUB
142 *
143 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
144 *****************************************************************************/
145
146BOOL OS2TimerResolution::enterResolutionScope(int dwPeriod)
147{
[9916]148 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::enterResolutionScope(%08xh)\n",
[2242]149 dwPeriod));
150
[756]151 OS2TimerResolution* timeRes = new OS2TimerResolution(dwPeriod);
152 if (timeRes != NULL)
153 return TRUE;
154 else
155 return FALSE;
156}
157
158
159/*****************************************************************************
160 * Name : OS2TimerResolution::leaveResolutionScope
161 * Purpose : remove specified entry from the list if periods match
162 * Parameters: int dwPeriod
163 * Variables :
164 * Result : TRUE or FALSE
165 * Remark :
166 * Status : UNTESTED STUB
167 *
168 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
169 *****************************************************************************/
170
171BOOL OS2TimerResolution::leaveResolutionScope(int dwPeriod)
172{
[9916]173 dprintf2(("WINMM:OS2Timer: OS2TimerResolution::leaveResolutionScope(%08xh)\n",
[2242]174 dwPeriod));
175
[9902]176 timeMutex.enter();
[756]177 OS2TimerResolution* timeRes = OS2TimerResolution::sTimerResolutions;
178
179 if (timeRes != NULL)
180 {
181 for(; // walk to the end of the list
182 timeRes->next != NULL;
183 timeRes = timeRes->next)
184 ;
185
186 if (timeRes->dwPeriod == dwPeriod) // do the requested period match?
187 {
188 delete timeRes; // so delete that object
[9902]189 timeMutex.leave();
[756]190 return TRUE; // OK, can remove the entry
191 }
192 }
[9902]193 timeMutex.leave();
194
[756]195 return FALSE; // nope, mismatch !
196}
197
198
199/*****************************************************************************
200 * Name : OS2TimerResolution::queryCurrentResolution
[757]201 * Purpose : determine the minimum resolution currently requested
[756]202 * Parameters:
203 * Variables :
204 * Result :
205 * Remark :
206 * Status : UNTESTED STUB
207 *
208 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
209 *****************************************************************************/
210
211int OS2TimerResolution::queryCurrentResolution()
212{
[9902]213 timeMutex.enter();
[756]214 OS2TimerResolution *timeRes = OS2TimerResolution::sTimerResolutions;
[757]215 int iMin = -1;
[756]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 {
[757]222 if (timeRes->dwPeriod < iMin) // determine minimum time period
223 iMin = timeRes->dwPeriod;
[756]224 }
[9902]225 timeMutex.leave();
[756]226
[2242]227 dprintf(("WINMM:OS2Timer: OS2TimerResolution::queryCurrentResolution == %08xh\n",
228 iMin));
229
[757]230 return iMin;
[756]231}
232
233
234
235
236
[4]237/******************************************************************************/
238/******************************************************************************/
[3600]239OS2Timer::OS2Timer() : TimerSem(0), TimerHandle(0), hTimerThread(0),
[763]240 clientCallback(NULL), TimerStatus(Stopped), fFatal(FALSE),
[10269]241 next(NULL), timerID(0), refCount(0)
[4]242{
[2242]243 dprintf(("WINMM:OS2Timer: OS2Timer::OS2Timer(%08xh)\n",
244 this));
245
[9902]246 timeMutex.enter();
[759]247 OS2Timer *timer = OS2Timer::timers;
[4]248
[756]249 if(timer != NULL)
250 {
251 while(timer->next != NULL)
252 {
253 timer = timer->next;
[4]254 }
255 timer->next = this;
256 }
[756]257 else
258 timers = this;
[9902]259 timeMutex.leave();
[3600]260
[4355]261 // create timer semaphore
262 int rc = DosCreateEventSem(NULL, &TimerSem, DC_SEM_SHARED, 0);
263 if(rc != 0)
264 {
265 dprintf(("WINMM: OS2Timer: DosCreateEventSem failed rc=#%08xh\n", rc));
266 return; // terminate thread
267 }
[10269]268
269 //increase reference count for creation
270 addRef();
271
272 //increase reference count since the thread will access the object
273 addRef();
[759]274 hTimerThread = CreateThread(NULL,
[2242]275 0x4000,
[5358]276 TimerHlpHandler,
[759]277 (LPVOID)this,
278 0, // thread creation flags
279 &TimerThreadID);
[4355]280
281 if (hTimerThread == NULL)
282 {
283 dprintf(("WINMM: OS2Timer: CreateThread failed rc=#%08xh\n",
284 GetLastError()));
285 DosCloseEventSem(TimerSem);
286 }
[4]287}
288/******************************************************************************/
289/******************************************************************************/
290OS2Timer::~OS2Timer()
291{
[2242]292 dprintf(("WINMM:OS2Timer: OS2Timer::~OS2Timer(%08xh)\n",
293 this));
294
[9902]295 KillTimer();
296
297 timeMutex.enter();
[756]298 OS2Timer *timer = OS2Timer::timers;
[4]299
[756]300 if(timer != this)
301 {
302 while(timer->next != this)
303 {
304 timer = timer->next;
[4]305 }
306 timer->next = this->next;
307 }
[756]308 else
309 timers = timer->next;
[9902]310
311 timeMutex.leave();
[4]312}
313/******************************************************************************/
314/******************************************************************************/
[756]315BOOL OS2Timer::StartTimer(int period,
316 int resolution,
317 LPTIMECALLBACK lptc,
318 int dwUser,
319 int fuEvent)
[4]320{
[2242]321 dprintf(("WINMM:OS2Timer: OS2Timer::StartTimer(%08xh, %08xh, %08xh, %08xh, %08xh, %08xh)\n",
322 this,
323 period,
324 resolution,
325 lptc,
326 dwUser,
327 fuEvent));
328
[756]329 APIRET rc;
[3600]330
331 // has the thread been created properly?
332 if(hTimerThread == NULLHANDLE)
[4]333 return(FALSE);
[756]334
335 if(TimerStatus == Stopped)
336 {
[3600]337 clientCallback = lptc; // callback data (id / addr)
338 userData = dwUser; // user-supplied data
339 dwFlags = fuEvent; // type of timer / callback
[756]340
[3600]341 if(fuEvent & TIME_PERIODIC)
[756]342 rc = DosStartTimer(period, (HSEM)TimerSem, &TimerHandle);
343 else
344 rc = DosAsyncTimer(period, (HSEM)TimerSem, &TimerHandle);
345
346 if(rc)
347 {
348
[4]349#ifdef DEBUG
[3600]350 if(fuEvent & TIME_PERIODIC)
[756]351 WriteLog("DosStartTimer failed %d\n", rc);
352 else
353 WriteLog("DosAsyncTimer failed %d\n", rc);
[4]354#endif
[756]355
356 return(FALSE);
[4]357 }
[756]358
359 TimerStatus = Running;
[4]360 }
[756]361 else
362 return(FALSE); //already running (must use timeKillEvent first)
363
[4]364 return(TRUE);
365}
366/******************************************************************************/
367/******************************************************************************/
368void OS2Timer::StopTimer()
369{
[2242]370 dprintf(("WINMM:OS2Timer: OS2Timer::StopTimer(%08xh)\n",
371 this));
372
[756]373 if(TimerStatus == Running)
374 {
375 DosStopTimer(TimerHandle);
376 TimerStatus = Stopped;
[4]377 }
378}
379/******************************************************************************/
380/******************************************************************************/
381void OS2Timer::KillTimer()
382{
[2242]383 dprintf(("WINMM:OS2Timer: OS2Timer::KillTimer(%08xh)\n",
384 this));
385
[4]386 fFatal = TRUE;
[3600]387
388 StopTimer();
389
[21930]390 DosPostEventSem(TimerSem);
391
[4]392 TimerStatus = InActive;
393}
[10269]394//******************************************************************************
395//******************************************************************************
396#ifdef DEBUG
397LONG OS2Timer::addRef()
398{
399//// dprintf2(("addRef %x -> refcount %x", this, refCount+1));
400 return InterlockedIncrement(&refCount);
401};
402#endif
[4]403/******************************************************************************/
404//******************************************************************************
[10269]405LONG OS2Timer::release()
406{
407#ifdef DEBUG
408 if(refCount-1 < 0) {
409 DebugInt3();
410 }
411#endif
412 if(InterlockedDecrement(&refCount) == 0) {
413 dprintf2(("marked for deletion -> delete now"));
414 delete this;
415 return 0;
416 }
417 return refCount;
418}
419/******************************************************************************/
420//******************************************************************************
[4]421void OS2Timer::TimerHandler()
422{
[668]423 ULONG Count = 0;
424 APIRET rc = 0; /* Return code */
[4]425
[2242]426 dprintf(("WINMM: TimerHandler thread created (%08xh)\n",
427 this));
[4]428
[21933]429 // save the current thread priority
430 PTIB ptib = NULL;
431 DosGetInfoBlocks(&ptib, NULL);
432 ULONG prio = ptib->tib_ptib2->tib2_ulpri;
[4]433
[21933]434 // increase the thread priority to improve timer resolution
435 DosSetPriority (PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
436
[668]437 while(!fFatal)
438 {
[4355]439 dprintf(("WINMM: OS2Timer::TimerHandler waiting on timer (%04xh, %08xh\n",
440 dwFlags,
441 clientCallback));
[21933]442
[10269]443 rc = DosWaitEventSem(TimerSem, SEM_INDEFINITE_WAIT);
444 if(rc) {
445 dprintf(("DosWaitEventSem failed with %d", rc));
446 DebugInt3();
447 }
448 rc = DosResetEventSem(TimerSem, &Count);
449 if(rc) {
450 dprintf(("DosResetEventSem failed with %d", rc));
451 DebugInt3();
452 }
[668]453 if(!fFatal)
454 {
[3600]455 // check timer running condition
456 if (TimerStatus == Running)
457 {
[4355]458 dprintf(("WINMM: OS2Timer::TimerHandler firing (%04xh, %08xh\n",
459 dwFlags,
460 clientCallback));
461
[3600]462 // process the event
463 switch (dwFlags & 0x0030)
464 {
465 case TIME_CALLBACK_FUNCTION:
466 if (clientCallback != NULL)
467 {
[21933]468 // restore the original priority (we never know what the callback
469 // code does)
470 DosSetPriority (PRTYS_THREAD, (prio >> 8) & 0xFF, 0, 0);
471
[10269]472 clientCallback((UINT)timerID, 0, userData, 0, 0);
[21933]473
474 DosSetPriority (PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
[3600]475 }
476 break;
477
478 case TIME_CALLBACK_EVENT_SET:
479 SetEvent( (HANDLE)clientCallback );
480 break;
481
482 case TIME_CALLBACK_EVENT_PULSE:
483 PulseEvent( (HANDLE)clientCallback );
484 break;
485
486 default:
487 dprintf(("WINMM: OS2Timer %08xh: unknown type for mmtime callback(%08xh)\n",
488 this,
489 dwFlags));
490 }
491 }
[4]492 }
[668]493 }
[3600]494
495 // last message
496 dprintf(("WINMM: OS2Timer: Timer thread terminating (%08xh)\n",
497 this));
498
[668]499 DosCloseEventSem(TimerSem);
[10269]500
501 //release object
502 release();
[4]503}
504//******************************************************************************
505//******************************************************************************
[5358]506static DWORD WIN32API TimerHlpHandler(LPVOID timer)
[4]507{
508 ((OS2Timer *)timer)->TimerHandler();
509
[759]510 return 0;
[4]511}
512//******************************************************************************
513//******************************************************************************
[756]514OS2TimerResolution *OS2TimerResolution::sTimerResolutions = NULL;
515OS2Timer *OS2Timer::timers = NULL;
516int OS2Timer::timerPeriod = 0;
[588]517
Note: See TracBrowser for help on using the repository browser.