1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 #ifndef OSCL_TIMER_H_INCLUDED
19 #define OSCL_TIMER_H_INCLUDED
20
21 #ifndef OSCL_BASE_H_INCLUDED
22 #include "oscl_base.h"
23 #endif
24
25 #ifndef OSCLCONFIG_UTIL_H_INCLUDED
26 #include "osclconfig_util.h"
27 #endif
28
29 #ifndef OSCL_VECTOR_H_INCLUDED
30 #include "oscl_vector.h"
31 #endif
32
33 #ifndef OSCL_TICKCOUNT_H_INCLUDED
34 #include "oscl_tickcount.h"
35 #endif
36
37 #ifndef OSCL_RAND_H_INCLUDED
38 #include "oscl_rand.h"
39 #endif
40
41 #ifndef OSCL_SCHEDULER_AO_H_INCLUDED
42 #include "oscl_scheduler_ao.h"
43 #endif
44
45
46 /**
47 * The observer class to receive timeout callbacks
48 */
49 class OsclTimerObserver
50 {
51 public:
52 /**
53 * This function will be called when the timer associated
54 * with this observer is executed
55 *
56 * @param timerID The ID given at timer request.
57 * @param timeoutInfo
58 * Any extra info given at timer request.
59 */
60 virtual void TimeoutOccurred(int32 timerID, int32 timeoutInfo) = 0;
61
~OsclTimerObserver()62 virtual ~OsclTimerObserver() {}
63 };
64
65 /**
66 * A timer class for scheduling one or more timeout events.
67 * The timeout event will trigger a callback to an observer
68 * class.
69 */
70 template<class Alloc>
71 class OsclTimer ;
72
73 class CallbackTimerObserver
74 {
75 public:
76 virtual void TimerBaseElapsed() = 0;
~CallbackTimerObserver()77 virtual ~CallbackTimerObserver() {}
78 };
79
80 template<class Alloc>
81 class CallbackTimer: public OsclTimerObject
82 {
83 public:
84 CallbackTimer(CallbackTimerObserver& aContainer, const char *name, int32 aPriority = OsclActiveObject::EPriorityNominal)
OsclTimerObject(aPriority,name)85 : OsclTimerObject(aPriority, name)
86 {
87 iContainer = &aContainer;
88 AddToScheduler();
89 }
~CallbackTimer()90 ~CallbackTimer()
91 {
92 RemoveFromScheduler();
93 }
Run()94 void Run()
95 {
96 if (Status() == OSCL_REQUEST_ERR_NONE)
97 iContainer->TimerBaseElapsed();
98 }
99 private:
100 CallbackTimerObserver *iContainer;
101 };
102
103
104 template<class Alloc>
105 class OsclTimer : public CallbackTimerObserver
106 {
107 public:
108
109 typedef CallbackTimer<Alloc> callback_timer_type;
110
111 /**
112 * Constructor
113 *
114 * @param frequency The frequency of the timer in cycles/second. A value of
115 * 1 means the timer will cycle in 1 second intervals.
116 */
117 OsclTimer(const char *name, uint32 frequency = 1, int32 priority = OsclActiveObject::EPriorityNominal);
118 virtual ~OsclTimer();
119
120 /**
121 * Set the global observer. Each timer can request a local
122 * observer, which if set overrides the global observer.
123 *
124 * @param obs observer object.
125 */
SetObserver(OsclTimerObserver * obs)126 void SetObserver(OsclTimerObserver *obs)
127 {
128 iObserver = obs;
129 }
130 /**
131 * Set the frequency of the timer in cycles/second.
132 *
133 * @param frequency A value of 1 means the timer will cycle in one second
134 * intervals, 1000 means millisecond intervals, etc.
135 */
136 void SetFrequency(uint32 frequency);
137
138 /**
139 * Set the exact frequency of the timer in microsecond.
140 *
141 * @param frequency A value of 1 means the timer will cycle in one microsecond
142 * intervals, 1000 means millisecond intervals, etc.
143 */
144 void SetExactFrequency(uint32 frequency);
145
146 /**
147 * Request a timer
148 *
149 * @param timerID used to identify the timer for cancellation. This value
150 * will be returned as part of the timeout event.
151 * @param timeoutInfo
152 * for user info. Returned to the observer on a timeout event
153 * @param cycles the number of cycles to wait before a timeout event. If
154 * the timer frequency is 1 and the cycles are set to 2, then
155 * the timeout event will occur in 2 seconds.
156 * @param obs a local observer object to be called on a timeout event.
157 * This observer overides the global observer if set.
158 */
159 void Request(int32 timerID, int32 timeoutInfo, int32 cycles, OsclTimerObserver *obs = 0, bool recurring = 0);
160 /**
161 * Cancel a timer
162 *
163 * @param timerID used to identify the timer to cancel.
164 * @param timeoutInfo
165 * if not set to -1, this value will be used as additional
166 * matching criteria to cancel a timer.
167 */
168 void Cancel(int32 timerID, int32 timeoutInfo = -1);
169 /**
170 * Cancel all pending timers.
171 */
172 void Clear();
173
174 private:
175 //Note: the timer needs to be a new'd object so that
176 //the CBase construction zeros the memory.
177 callback_timer_type *iTimer;
178
179 typedef struct _TimerEntry
180 {
181 int32 iCounter ;
182 int32 iTimerID ;
183 int32 iParam ;
184 OsclTimerObserver *iObserver;
185 bool iRecurring;
186 int32 iOrigCounter;
187 } TimerEntry;
188
189 typedef TimerEntry entry_type;
190 typedef Oscl_Vector<entry_type*, Alloc> entries_type;
191 typedef typename entries_type::iterator entries_type_iterator;
192
193 OsclTimerObserver *iObserver;
194 entries_type iEntries;
195 entries_type iEntriesWaitingToAdd;
196 entries_type iEntriesWaitingToCancel;
197 Oscl_TAlloc<entry_type, Alloc> iEntryAllocator;
198
199 bool iInCallback;
200
201 uint32 iCyclePeriod;
202 uint32 iTickCountPeriod;
203 uint32 iExpectedTimeout;
204
205 protected:
206 void TimerBaseElapsed();
207 friend class CallbackTimer<Alloc>;
208 };
209
210 template<class Alloc>
OsclTimer(const char * name,uint32 frequency,int32 priority)211 OsclTimer<Alloc>::OsclTimer(const char *name, uint32 frequency, int32 priority) :
212 iObserver(0)
213 , iInCallback(false)
214 , iTickCountPeriod(0)
215 , iExpectedTimeout(0)
216 {
217 //use the allocator with placement 'new'
218 Alloc alloc;
219 iTimer = OSCL_PLACEMENT_NEW(alloc.ALLOCATE(sizeof(CallbackTimer<Alloc>)), CallbackTimer<Alloc>(*this, name, priority));
220 SetFrequency(frequency);
221 }
222
223 template<class Alloc>
~OsclTimer()224 OsclTimer<Alloc>::~OsclTimer()
225 {
226 // Make sure we're cancelled
227 if (iTimer)
228 iTimer->Cancel();
229 if (iTimer)
230 {
231 iTimer->OSCL_TEMPLATED_DESTRUCTOR_CALL(callback_timer_type, CallbackTimer);
232 Alloc alloc;
233 alloc.deallocate(iTimer);
234 }
235 iTimer = NULL;
236
237 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
238 {
239 iEntryAllocator.deallocate(*it);
240 }
241 }
242
243 template<class Alloc>
SetFrequency(uint32 frequency)244 void OsclTimer<Alloc>::SetFrequency(uint32 frequency)
245 {
246 // timer takes microseconds
247 iCyclePeriod = 1000000 / frequency;
248 // get tick count period
249 iTickCountPeriod = OsclTickCount::TickCountPeriod();
250 }
251
252 template<class Alloc>
SetExactFrequency(uint32 frequency)253 void OsclTimer<Alloc>::SetExactFrequency(uint32 frequency)
254 {
255 // timer takes microseconds
256 iCyclePeriod = frequency;
257 // get tick count period
258 iTickCountPeriod = OsclTickCount::TickCountPeriod();
259 }
260
261 // Request a timer
262 template<class Alloc>
Request(int32 timerID,int32 param,int32 cycles,OsclTimerObserver * obs,bool recurring)263 void OsclTimer<Alloc>::Request(int32 timerID, int32 param, int32 cycles, OsclTimerObserver *obs, bool recurring)
264 {
265
266 // add to list of timers
267 entry_type *entry = iEntryAllocator.ALLOCATE(1);
268 entry->iTimerID = timerID;
269 entry->iParam = param;
270 entry->iCounter = cycles;
271 entry->iObserver = obs;
272 entry->iRecurring = recurring;
273 entry->iOrigCounter = entry->iCounter;
274
275 // if the request is called inside of a callback, then we must add it later
276 if (iInCallback)
277 {
278 iEntriesWaitingToAdd.push_back(entry);
279 return;
280 }
281
282 iEntries.push_back(entry);
283
284 if (iTimer)
285 {
286 iTimer->RunIfNotReady(iCyclePeriod);
287 }
288
289 if (iExpectedTimeout == 0)
290 {
291 iExpectedTimeout = (OsclTickCount::TickCount() * iTickCountPeriod) + iCyclePeriod;
292 }
293 }
294
295 // Cancel a timer
296 template<class Alloc>
Cancel(int32 timerID,int32 param)297 void OsclTimer<Alloc>::Cancel(int32 timerID, int32 param)
298 {
299
300 if (iInCallback)
301 {
302 // add to list of timers
303 entry_type *entry = iEntryAllocator.ALLOCATE(1);
304 entry->iTimerID = timerID;
305 entry->iParam = param;
306
307 iEntriesWaitingToCancel.push_back(entry);
308 return;
309 }
310
311 // remove from list of timers
312 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
313 {
314 if ((*it)->iTimerID == timerID)
315 {
316 // make sure the param matches unless it is not specified (-1)
317 if ((*it)->iParam == param || param == -1)
318 {
319 iEntryAllocator.deallocate(*it);
320 iEntries.erase(it);
321 return;
322 }
323 }
324 }
325 }
326
327 // Clear all waiting timers
328 template<class Alloc>
Clear()329 void OsclTimer<Alloc>::Clear()
330 {
331 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
332 {
333 iEntryAllocator.deallocate(*it);
334 }
335 iEntries.clear();
336 }
337
338 template<class Alloc>
TimerBaseElapsed()339 void OsclTimer<Alloc>::TimerBaseElapsed()
340 {
341 uint8 expiredFound = 0;
342
343 {
344 // call all whose timers have expired
345 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
346 {
347 entry_type *entry = (*it);
348 if (--(entry->iCounter) <= 0)
349 {
350 if (!entry->iRecurring) expiredFound = 1;
351 if (entry->iRecurring) entry->iCounter = entry->iOrigCounter;
352
353 // use local observer if it exists, otherwise use global observer
354 OsclTimerObserver *obs = (entry->iObserver ? entry->iObserver : iObserver);
355 if (obs)
356 {
357 iInCallback = true;
358 obs->TimeoutOccurred(entry->iTimerID, entry->iParam);
359 iInCallback = false;
360 }
361 }
362 }
363 }
364
365 // remove from list all whose timers have expired
366 while (expiredFound)
367 {
368 expiredFound = 0;
369 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
370 {
371 entry_type *entry = (*it);
372 if (entry->iCounter <= 0)
373 {
374 expiredFound = 1;
375 iEntryAllocator.deallocate(entry);
376 iEntries.erase(it);
377 break;
378 }
379 }
380 }
381
382 {
383 // if any timers were cancelled in the callback, process them now
384 for (entries_type_iterator it = iEntriesWaitingToCancel.begin(); it != iEntriesWaitingToCancel.end(); it++)
385 {
386 entry_type *entry = (*it);
387 Cancel(entry->iTimerID, entry->iParam);
388 iEntryAllocator.deallocate(entry);
389 }
390 iEntriesWaitingToCancel.clear();
391 }
392
393 {
394 // if any timers were requested in the callback, process them now
395 for (entries_type_iterator it = iEntriesWaitingToAdd.begin(); it != iEntriesWaitingToAdd.end(); it++)
396 {
397 entry_type *entry = (*it);
398 Request(entry->iTimerID, entry->iParam, entry->iCounter, entry->iObserver);
399 iEntryAllocator.deallocate(entry);
400 }
401 iEntriesWaitingToAdd.clear();
402 }
403
404 if (!iEntries.empty())
405 {
406 // adjust for the jitter
407 uint32 time = OsclTickCount::TickCount() * iTickCountPeriod;
408 int32 jitter = time - iExpectedTimeout;
409 int32 waitperiod = iCyclePeriod - jitter;
410
411 // currently there is some problem on the phone if we send
412 // in real-time rather than with a slower (growing delay) H.223 mux output
413 // if jitter is too large in either direction, start over
414 if ((uint)OSCL_ABS(jitter) > iCyclePeriod)
415 {
416 iExpectedTimeout = time;
417 }
418 else
419 {
420 iExpectedTimeout += iCyclePeriod;
421 }
422
423 waitperiod = OSCL_MAX(waitperiod, 0);
424
425 if (iTimer)
426 {
427 iTimer->RunIfNotReady(waitperiod);
428 }
429 }
430 else
431 {
432 iExpectedTimeout = 0;
433 }
434 }
435
436
437
438 #endif
439