source: trunk/dll/tmrsvcs.c@ 1760

Last change on this file since 1760 was 1760, checked in by Steven Levine, 11 years ago

Comments

  • Property svn:keywords set to Author Date Id Revision
File size: 3.7 KB
Line 
1
2/***********************************************************************
3
4 $Id: tmrsvcs.c 1760 2014-03-21 23:10:53Z stevenhl $
5
6 Timer services
7
8 Copyright (c) 2008 Steven H. Levine
9
10 05 Jan 08 SHL Baseline
11 12 Jun 11 GKY Added IdleIfNeeded to the container/list fill and free loops to improve system
12 responsiveness when dealing with large numbers of items
13 21 Mar 14 SHL Comments
14
15***********************************************************************/
16
17#define INCL_DOS // QSV_MS_COUNT
18
19// #include "errutil.h" // DbgMsg // 05 Jan 08 SHL fixme debug
20#include "tmrsvcs.h"
21
22// static PSZ pszSrcFile = __FILE__; // 05 Jan 08 SHL fixme debug
23
24/**
25 * Prepare interval timer descriptor for use
26 * Call with interval 0 to to reset internal estimators
27 * @param pTD point to interval timer descriptor
28 * @param interval_msec is the timer interval in msec or 0 to retain existing value
29 */
30
31VOID InitITimer(ITIMER_DESC *pitd, UINT interval_msec)
32{
33 if (interval_msec) {
34 // Assume starting new loop at similar rate
35 pitd->interval_msec = interval_msec;
36 pitd->remaining = pitd->estimated;
37 }
38 else {
39 // Assume loop rate is changing to a significantly lower value
40 pitd->remaining = 0;
41 pitd->estimated = 1; // Force rate recalc
42 }
43 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &pitd->start_msec, sizeof(pitd->start_msec));
44}
45
46/**
47 * Check timer interval expired
48 * Attempts to optimize calls to fetch QSV_MS_COUNT
49 * Caller should reinit if processing rate changes
50 * @return TRUE if expired
51 */
52
53BOOL IsITimerExpired(ITIMER_DESC *pitd)
54{
55 INT err_msec;
56 ULONG cur_msec;
57 UINT elapsed_msec;
58 INT cnt;
59
60 if (--pitd->remaining < 0) {
61
62 DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &cur_msec, sizeof(cur_msec));
63 elapsed_msec = cur_msec - pitd->start_msec;
64 if (elapsed_msec == pitd->interval_msec) {
65 pitd->remaining = pitd->estimated;
66 pitd->start_msec = cur_msec;
67 pitd->misses = 0;
68 return TRUE; // Say interval expired
69 }
70
71 pitd->misses++;
72 err_msec = (cur_msec - pitd->start_msec) - pitd->interval_msec;
73 // Estimate counts per msec
74 if (err_msec > 0) {
75 // Late - need to reduce estimated count
76 if (elapsed_msec)
77 pitd->estimated = pitd->estimated * pitd->interval_msec / elapsed_msec;
78 else {
79 // Should not occur
80 if (pitd->estimated)
81 pitd->estimated--;
82 }
83 // Calc counts for next interval
84 pitd->remaining = pitd->estimated -
85 (pitd->estimated * err_msec / pitd->interval_msec);
86 pitd->start_msec += pitd->interval_msec;
87 return TRUE;
88 }
89
90 // Early - need to increase estimated count
91 cnt = pitd->estimated * (-err_msec) / pitd->interval_msec;
92 if (!cnt) {
93 if (pitd->estimated)
94 cnt = pitd->estimated * 2;
95 else
96 cnt = 1;
97 }
98 pitd->estimated += cnt;
99 pitd->remaining = cnt;
100 }
101 return FALSE; // Keep waiting
102}
103
104/**
105 * Sleep if timer expired to avoid hogging CPU
106 * @note Assumes ITIMER_DESC initialized by caller before first call
107 */
108
109VOID SleepIfNeeded(ITIMER_DESC *pitd, UINT sleepTime)
110{
111 if (IsITimerExpired(pitd)) {
112 DosSleep(sleepTime);
113 InitITimer(pitd, 0);
114 }
115}
116
117/**
118 * Switch to idle priority if timer expired
119 * @return 0 if switched otherwise return APIRET or non-zero value
120 * @note Assumes ITIMER_DESC initialized by caller before first call
121 */
122
123ULONG IdleIfNeeded(ITIMER_DESC *pitd, LONG delta)
124{
125 APIRET rc;
126
127 if (IsITimerExpired(pitd)) {
128 rc = DosSetPriority(PRTYS_THREAD,PRTYC_IDLETIME,delta,0L);
129 InitITimer(pitd, 0);
130 return rc;
131 }
132 return 1;
133}
134
135#pragma alloc_text(TMRSVCS,InitITimer,IsITimerExpired,SleepIfNeeded,IdleIfNeeded)
Note: See TracBrowser for help on using the repository browser.