• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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