Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/src/dep/timer.c
+++ new/src/dep/timer.c
1 1 /*-
2 2 * Copyright (c) 2011-2012 George V. Neville-Neil,
3 3 * Steven Kreuzer,
4 4 * Martin Burnicki,
5 5 * Jan Breuer,
6 6 * Gael Mace,
7 7 * Alexandre Van Kempen,
8 8 * Inaqui Delgado,
9 9 * Rick Ratzel,
10 10 * National Instruments.
11 11 * Copyright (c) 2009-2010 George V. Neville-Neil,
12 12 * Steven Kreuzer,
13 13 * Martin Burnicki,
14 14 * Jan Breuer,
15 15 * Gael Mace,
16 16 * Alexandre Van Kempen
17 17 *
18 18 * Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
19 19 *
20 20 * All Rights Reserved
21 21 *
22 22 * Redistribution and use in source and binary forms, with or without
23 23 * modification, are permitted provided that the following conditions are
24 24 * met:
25 25 * 1. Redistributions of source code must retain the above copyright notice,
26 26 * this list of conditions and the following disclaimer.
27 27 * 2. Redistributions in binary form must reproduce the above copyright
28 28 * notice, this list of conditions and the following disclaimer in the
29 29 * documentation and/or other materials provided with the distribution.
30 30 *
31 31 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
32 32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 34 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
35 35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38 38 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39 39 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
40 40 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
41 41 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 42 */
43 43
44 44 /**
45 45 * @file timer.c
46 46 * @date Wed Jun 23 09:41:26 2010
47 47 *
48 48 * @brief The timers which run the state machine.
49 49 *
50 50 * Timers in the PTP daemon are run off of the signal system.
51 51 */
52 52
53 53 #include "../ptpd.h"
54 54
55 55 #define US_TIMER_INTERVAL (62500)
56 56 volatile unsigned int elapsed;
57 57
58 58 /*
59 59 * original code calls sigalarm every fixed 1ms. This highly pollutes the debug_log, and causes more interrupted instructions
60 60 * This was later modified to have a fixed granularity of 1s.
61 61 *
62 62 * Currently this has a configured granularity, and timerStart() guarantees that clocks expire ASAP when the granularity is too small.
63 63 * Timers must now be explicitelly canceled with timerStop (instead of timerStart(0.0))
64 64 */
65 65
66 66 void
67 67 catch_alarm(int sig)
68 68 {
69 69 elapsed++;
70 70 /* be sure to NOT call DBG in asynchronous handlers! */
71 71 }
72 72
73 73 void
|
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
74 74 initTimer(void)
75 75 {
76 76 struct itimerval itimer;
77 77
78 78 DBG("initTimer\n");
79 79
80 80 signal(SIGALRM, SIG_IGN);
81 81
82 82 elapsed = 0;
83 83 itimer.it_value.tv_sec = itimer.it_interval.tv_sec = 0;
84 - itimer.it_value.tv_usec = itimer.it_interval.tv_usec = US_TIMER_INTERVAL;
84 + itimer.it_value.tv_usec = itimer.it_interval.tv_usec =
85 + US_TIMER_INTERVAL;
85 86
87 +#ifdef __sun
88 + sigset(SIGALRM, catch_alarm);
89 +#else
86 90 signal(SIGALRM, catch_alarm);
91 +#endif
87 92 setitimer(ITIMER_REAL, &itimer, 0);
88 93 }
89 94
90 95 void
91 96 timerUpdate(IntervalTimer * itimer)
92 97 {
93 98
94 99 int i, delta;
95 100
96 101 /*
97 102 * latch how many ticks we got since we were last called
98 103 * remember that catch_alarm() is totally asynchronous to this timerUpdate()
99 104 */
100 105 delta = elapsed;
101 106 elapsed = 0;
102 107
103 108 if (delta <= 0)
104 109 return;
105 110
106 111 /*
107 112 * if time actually passed, then decrease every timer left
108 113 * the one(s) that went to zero or negative are:
109 114 * a) rearmed at the original time (ignoring the time that may have passed ahead)
110 115 * b) have their expiration latched until timerExpired() is called
111 116 */
112 117 for (i = 0; i < TIMER_ARRAY_SIZE; ++i) {
113 118 if ((itimer[i].interval) > 0 && ((itimer[i].left) -= delta)
114 119 <= 0) {
115 120 itimer[i].left = itimer[i].interval;
116 121 itimer[i].expire = TRUE;
117 122 DBG2("TimerUpdate: Timer %u has now expired. (Re-armed again with interval %d, left %d)\n", i, itimer[i].interval, itimer[i].left );
118 123 }
119 124 }
120 125
121 126 }
122 127
123 128 void
124 129 timerStop(UInteger16 index, IntervalTimer * itimer)
125 130 {
126 131 if (index >= TIMER_ARRAY_SIZE)
127 132 return;
128 133
129 134 itimer[index].interval = 0;
130 135 DBG2("timerStop: Stopping timer %d. (New interval: %d; New left: %d)\n", index, itimer[index].left , itimer[index].interval);
131 136 }
132 137
133 138 void
134 139 timerStart(UInteger16 index, float interval, IntervalTimer * itimer)
135 140 {
136 141 if (index >= TIMER_ARRAY_SIZE)
137 142 return;
138 143
139 144 itimer[index].expire = FALSE;
140 145
141 146
142 147 /*
143 148 * US_TIMER_INTERVAL defines the minimum interval between sigalarms.
144 149 * timerStart has a float parameter for the interval, which is casted to integer.
145 150 * very small amounts are forced to expire ASAP by setting the interval to 1
146 151 */
147 152 itimer[index].left = (int)((interval * 1E6) / US_TIMER_INTERVAL);
148 153 if(itimer[index].left == 0){
149 154 /*
150 155 * the interval is too small, raise it to 1 to make sure it expires ASAP
151 156 * Timer cancelation is done explicitelly with stopTimer()
152 157 */
153 158 itimer[index].left = 1;
154 159
155 160 static int operator_warned_interval_too_small = 0;
156 161 if(!operator_warned_interval_too_small){
157 162 operator_warned_interval_too_small = 1;
158 163 /*
159 164 * using random uniform timers it is pratically guarantted that we hit the possible minimum timer.
160 165 * This is because of the current timer model based on periodic sigalarm, irrespective if the next
161 166 * event is close or far away in time.
162 167 *
163 168 * A solution would be to recode this whole module with a calendar queue, while keeping the same API:
164 169 * E.g.: http://www.isi.edu/nsnam/ns/doc/node35.html
165 170 *
166 171 * Having events that expire immediatly (ie, delayreq invocations using random timers) can lead to
167 172 * messages appearing in unexpected ordering, so the protocol implementation must check more conditions
168 173 * and not assume a certain ususal ordering
169 174 */
170 175 DBG("Timer would be issued immediatly. Please raise dep/timer.c:US_TIMER_INTERVAL to hold %.2fs\n",
171 176 interval
172 177 );
173 178
174 179 }
175 180 }
176 181 itimer[index].interval = itimer[index].left;
177 182
178 183 DBG2("timerStart: Set timer %d to %f. New interval: %d; new left: %d\n", index, interval, itimer[index].left , itimer[index].interval);
179 184 }
180 185
181 186
182 187
183 188 /*
184 189 * This function arms the timer with a uniform range, as requested by page 105 of the standard (for sending delayReqs.)
185 190 * actual time will be U(0, interval * 2.0);
186 191 *
187 192 * PTPv1 algorithm was:
188 193 * ptpClock->R = getRand(&ptpClock->random_seed) % (PTP_DELAY_REQ_INTERVAL - 2) + 2;
189 194 * R is the number of Syncs to be received, before sending a new request
190 195 *
191 196 */
192 197 void timerStart_random(UInteger16 index, float interval, IntervalTimer * itimer)
193 198 {
194 199 float new_value;
195 200
196 201 new_value = getRand() * interval * 2.0;
197 202 DBG2(" timerStart_random: requested %.2f, got %.2f\n", interval, new_value);
198 203
199 204 timerStart(index, new_value, itimer);
200 205 }
201 206
202 207
203 208
204 209 Boolean
205 210 timerExpired(UInteger16 index, IntervalTimer * itimer)
206 211 {
207 212 timerUpdate(itimer);
208 213
209 214 if (index >= TIMER_ARRAY_SIZE)
210 215 return FALSE;
211 216
212 217 if (!itimer[index].expire)
213 218 return FALSE;
214 219
215 220 itimer[index].expire = FALSE;
216 221
217 222
218 223 DBG2("timerExpired: Timer %d expired, taking actions. current interval: %d; current left: %d\n", index, itimer[index].left , itimer[index].interval);
219 224
220 225 return TRUE;
221 226 }
222 227
223 228 Boolean
224 229 timerStopped(UInteger16 index, IntervalTimer * itimer)
225 230 {
226 231 timerUpdate(itimer);
227 232
228 233 if (index >= TIMER_ARRAY_SIZE)
229 234 return FALSE;
230 235
231 236 if (itimer[index].interval == 0) {
232 237 return TRUE;
233 238 DBG2("timerStopped: Timer %d is stopped\n", index);
234 239 }
235 240
236 241 return FALSE;
237 242
238 243 }
239 244
240 245 Boolean
241 246 timerRunning(UInteger16 index, IntervalTimer * itimer)
242 247 {
243 248 timerUpdate(itimer);
244 249
245 250 if (index >= TIMER_ARRAY_SIZE)
246 251 return FALSE;
247 252
248 253 if ((itimer[index].interval != 0) &&
249 254 (itimer[index].expire == FALSE)) {
250 255 return TRUE;
251 256 DBG2("timerRunning: Timer %d is running\n", index);
252 257 }
253 258
254 259 return FALSE;
255 260
256 261 }
257 262
|
↓ open down ↓ |
161 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX