|
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\cbase\ub_dtim.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "ub_std.h" |
|
19 |
|
20 /** |
|
21 Creates a new timed event queue with the specified active object priority. |
|
22 |
|
23 @param aPriority The priority of this active object. |
|
24 |
|
25 @return On successful return, a pointer to the queue of timed events. |
|
26 |
|
27 @publishedAll |
|
28 @released |
|
29 */ |
|
30 EXPORT_C CDeltaTimer* CDeltaTimer::NewL(TInt aPriority) |
|
31 { |
|
32 TTimeIntervalMicroSeconds32 tickPeriod; |
|
33 UserHal::TickPeriod(tickPeriod); |
|
34 |
|
35 CDeltaTimer* timer = new(ELeave) CDeltaTimer(aPriority, tickPeriod.Int()); |
|
36 |
|
37 TInt err = timer->iTimer.CreateLocal(); |
|
38 |
|
39 if (err) |
|
40 { |
|
41 delete timer; |
|
42 User::Leave(err); |
|
43 } |
|
44 |
|
45 CActiveScheduler::Add(timer); |
|
46 |
|
47 return timer; |
|
48 } |
|
49 |
|
50 /** |
|
51 Creates a new timed event queue with the specified active object priority, and |
|
52 the specified timer granularity. |
|
53 |
|
54 @param aPriority The priority of this active object. |
|
55 @param aGranularity Ignored. The resolution of the timer is the tick period. |
|
56 |
|
57 @return On successful return, a pointer to the queue of timed events. |
|
58 |
|
59 @publishedAll |
|
60 @deprecated |
|
61 */ |
|
62 EXPORT_C CDeltaTimer* CDeltaTimer::NewL(TInt aPriority, TTimeIntervalMicroSeconds32 /*aGranularity*/) |
|
63 { |
|
64 return CDeltaTimer::NewL(aPriority); |
|
65 } |
|
66 |
|
67 /** |
|
68 Constructor taking an active object priority value. |
|
69 |
|
70 The constructor sets this active object's priority value through a call to |
|
71 the base class constructor in its c'tor list. |
|
72 |
|
73 @param aPriority The priority of this active object. |
|
74 @param aTickPeriod The period of a tick on the system. |
|
75 |
|
76 @internalComponent |
|
77 @released |
|
78 */ |
|
79 CDeltaTimer::CDeltaTimer(TInt aPriority, TInt aTickPeriod) |
|
80 : CActive(aPriority), iTickPeriod(aTickPeriod) |
|
81 { |
|
82 } |
|
83 |
|
84 /** |
|
85 Adds a new timed event entry into the timed event queue. |
|
86 |
|
87 @param aTimeInMicroSeconds The interval from the present time when the timed |
|
88 event entry is to expire. |
|
89 @param aEntry The timed event entry encapsulating the call back that |
|
90 is to be called when this timed event entry expires. |
|
91 |
|
92 @publishedAll |
|
93 @released |
|
94 */ |
|
95 EXPORT_C void CDeltaTimer::Queue(TTimeIntervalMicroSeconds32 aTimeInMicroSeconds, TDeltaTimerEntry& aEntry) |
|
96 { |
|
97 QueueLong(TTimeIntervalMicroSeconds(MAKE_TINT64(0, aTimeInMicroSeconds.Int())), aEntry); |
|
98 } |
|
99 |
|
100 /** |
|
101 Adds a new timed event entry into the timed event queue. |
|
102 |
|
103 @param aTimeInMicroSeconds The interval from the present time when the timed |
|
104 event entry is to expire. |
|
105 @param aEntry The timed event entry encapsulating the call back that |
|
106 is to be called when this timed event entry expires. |
|
107 |
|
108 @return KErrNone if sucessful, KErrOverflow if the interval is too great or negative. |
|
109 |
|
110 @publishedAll |
|
111 @released |
|
112 */ |
|
113 EXPORT_C TInt CDeltaTimer::QueueLong(TTimeIntervalMicroSeconds aTimeInMicroSeconds, TDeltaTimerEntry& aEntry) |
|
114 { |
|
115 const TInt64 timeInTicks = (aTimeInMicroSeconds.Int64() + iTickPeriod - 1) / iTickPeriod; |
|
116 |
|
117 TInt timeInTicks32 = I64LOW(timeInTicks); |
|
118 |
|
119 // We are using deltas on tick values, hence using maximum signed number of ticks |
|
120 if (I64HIGH(timeInTicks) || (timeInTicks32 < 0)) |
|
121 { |
|
122 return KErrOverflow; |
|
123 } |
|
124 |
|
125 // Make sure we queue for at least one tick |
|
126 if (timeInTicks32 == 0) |
|
127 { |
|
128 timeInTicks32 = 1; |
|
129 } |
|
130 |
|
131 // Calculate tick count for new entry |
|
132 aEntry.iLink.iTickCount = Exec::TickCount() + timeInTicks32; |
|
133 |
|
134 // Add this entry at the right spot |
|
135 iQueue.Add(aEntry.iLink); |
|
136 |
|
137 // Queue the timer, re-queuing if we've added to the head of the queue |
|
138 Activate(&aEntry.iLink == iQueue.First()); |
|
139 |
|
140 return KErrNone; |
|
141 } |
|
142 |
|
143 /** |
|
144 Issues a new RTimer request, if there is no outstanding request and the queue |
|
145 is not empty. |
|
146 |
|
147 @internalComponent |
|
148 @released |
|
149 */ |
|
150 void CDeltaTimer::Activate(TBool aRequeueTimer) |
|
151 // |
|
152 // Queue a request on the timer. |
|
153 // |
|
154 { |
|
155 if (IsActive()) |
|
156 { |
|
157 if (aRequeueTimer) |
|
158 { |
|
159 Cancel(); |
|
160 } |
|
161 else |
|
162 { |
|
163 return; |
|
164 } |
|
165 } |
|
166 |
|
167 if (!iQueue.IsEmpty() && !iQueueBusy) |
|
168 { |
|
169 SetActive(); |
|
170 |
|
171 const TInt ticksToWait = iQueue.First()->iTickCount - Exec::TickCount(); |
|
172 |
|
173 if (ticksToWait > 0) |
|
174 { |
|
175 iTimer.AfterTicks(iStatus, ticksToWait); |
|
176 } |
|
177 else |
|
178 { |
|
179 TRequestStatus* status = &iStatus; |
|
180 User::RequestComplete(status, KErrNone); |
|
181 } |
|
182 } |
|
183 } |
|
184 |
|
185 /** |
|
186 Deals with an RTimer completion event. |
|
187 |
|
188 The function inspects the timed event entry at the head of the queue, and |
|
189 reduces its timer value by the appropriate amount. If this timed event is |
|
190 now found to have expired, the call back function is called, and the timed |
|
191 event entry removed from the queue. |
|
192 |
|
193 If the timed event entry has not expired, it remains at the head of the queue. |
|
194 |
|
195 The function issues a new RTimer request, using the timer granularity value |
|
196 as the time interval. |
|
197 |
|
198 @see RTimer |
|
199 @see CActive |
|
200 |
|
201 @internalComponent |
|
202 @released |
|
203 */ |
|
204 void CDeltaTimer::RunL() |
|
205 // |
|
206 // Call all zero delta callbacks |
|
207 { |
|
208 // Queue busy |
|
209 iQueueBusy = ETrue; |
|
210 |
|
211 // Whilst the list of expired timers is being processed, time will pass and |
|
212 // the tick count may have increased such that there are now more expired |
|
213 // timers. Loop until we have either emptied the queue or can wait for a |
|
214 // timer exipration in the future. |
|
215 while (!iQueue.IsEmpty()) |
|
216 { |
|
217 // Calculate how long till first timer expires |
|
218 const TUint tickCount = Exec::TickCount(); |
|
219 |
|
220 // If the first timer is yet to expire, wait some more |
|
221 if (((TInt)(iQueue.First()->iTickCount - tickCount)) > 0) |
|
222 { |
|
223 break; |
|
224 } |
|
225 |
|
226 // Remove entry before callback to prevent re-entrancy issues |
|
227 TTickCountQueLink* entry = iQueue.RemoveFirst(); |
|
228 |
|
229 // Iterate through the timers we know have expired based on the |
|
230 // last calculation of delta |
|
231 while (entry) |
|
232 { |
|
233 // Make callback. This could go reentrant on Queue[Long]() or Remove(). |
|
234 reinterpret_cast<TDeltaTimerEntry*>( |
|
235 PtrSub( |
|
236 entry, |
|
237 _FOFF(TDeltaTimerEntry, iLink) |
|
238 )) |
|
239 ->iCallBack.CallBack(); |
|
240 |
|
241 // Remove the next expired entry, if any |
|
242 entry = iQueue.RemoveFirst(tickCount); |
|
243 } |
|
244 } |
|
245 |
|
246 // Queue idle |
|
247 iQueueBusy = EFalse; |
|
248 |
|
249 // Requeue timer |
|
250 Activate(); |
|
251 } |
|
252 |
|
253 /** |
|
254 Implements cancellation of an oustanding RTimer request. |
|
255 |
|
256 @internalComponent |
|
257 @released |
|
258 */ |
|
259 void CDeltaTimer::DoCancel() |
|
260 { |
|
261 iTimer.Cancel(); |
|
262 } |
|
263 |
|
264 /** |
|
265 Removes the specified timed event entry from the timer queue. |
|
266 |
|
267 @param aEntry The timed event entry. |
|
268 |
|
269 @publishedAll |
|
270 @released |
|
271 */ |
|
272 EXPORT_C void CDeltaTimer::Remove(TDeltaTimerEntry& aEntry) |
|
273 { |
|
274 // Remove the specified entry from the list |
|
275 aEntry.iLink.Deque(); |
|
276 } |
|
277 |
|
278 /** |
|
279 Destructor. |
|
280 |
|
281 Frees all resources before destruction of the object. Specifically, it cancels |
|
282 any outstanding timer requests generated by the RTimer object and then deletes |
|
283 all timed event entries from the timed event queue. |
|
284 |
|
285 @see RTimer |
|
286 |
|
287 @publishedAll |
|
288 @released |
|
289 */ |
|
290 CDeltaTimer::~CDeltaTimer() |
|
291 { |
|
292 Cancel(); |
|
293 |
|
294 while (!iQueue.IsEmpty()) |
|
295 { |
|
296 iQueue.First()->Deque(); |
|
297 } |
|
298 |
|
299 iTimer.Close(); |
|
300 } |