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
19
20 #include "oscl_scheduler_ao.h"
21 #include "oscl_error.h"
22 #include "oscl_scheduler.h"
23 #include "pvlogger.h"
24 #include "oscl_tickcount.h"
25
26 #define OSCL_DISABLE_WARNING_THIS_USED_IN_BASE_CLASS
27 #define OSCL_DISABLE_WARNING_TYPEDEF_USED_AS_SYNONYM
28 #include "osclconfig_compiler_warnings.h"
29
30 #include "oscl_scheduler_tuneables.h"
31
32 /////////////////////
33 // PVActiveBase
34 /////////////////////
35
PVActiveBase(const char name[],int32 pri)36 PVActiveBase::PVActiveBase(const char name[],
37 int32 pri)
38 {
39 iName.Set(name);
40 #if(PV_SCHED_ENABLE_AO_STATS)
41 iPVActiveStats = NULL;
42 #endif
43 iPVReadyQLink.iAOPriority = pri;
44 iBusy = false;
45 iStatus = OSCL_REQUEST_ERR_NONE;
46 }
47
~PVActiveBase()48 PVActiveBase::~PVActiveBase()
49 {
50 if (iBusy)
51 OsclError::Leave(OsclErrInvalidState);//EExecStillReadyOnDestruct
52 }
53
54 #if(PV_SCHED_ENABLE_AO_STATS)
PVActiveStats(OsclExecSchedulerCommonBase * aScheduler,const char * aAOName,PVActiveBase * aActiveBase)55 PVActiveStats::PVActiveStats(OsclExecSchedulerCommonBase* aScheduler, const char* aAOName, PVActiveBase* aActiveBase)
56 {
57 OSCL_ASSERT(aScheduler);
58
59 iPVActiveBase = aActiveBase;
60 iAOName = aAOName;
61 iScheduler = aScheduler;
62
63 iNumRun = 0;
64 iNumRunError = 0;
65 iMaxTicksInRun = 0;
66 iTotalTicksInRun = 0;
67 i64Valid = true;//make 64-bit the default.
68 i64TotalTicksInRun = 0;
69 iPercent = 0.0;
70 iLeave = OsclErrNone;
71 iNumCancel = 0;
72 iNumInstances = 1;
73 iPriority = (aActiveBase) ? aActiveBase->iPVReadyQLink.iAOPriority : 0;
74 }
~PVActiveStats()75 PVActiveStats::~PVActiveStats()
76 {
77 iPVStatQLink.Remove();
78
79 //destroy the link from the AO to this object
80 if (iPVActiveBase)
81 iPVActiveBase->iPVActiveStats = NULL;
82 }
Combine(PVActiveStats & aStats)83 void PVActiveStats::Combine(PVActiveStats& aStats)
84 {
85 iNumRun += aStats.iNumRun;
86 iNumRunError += aStats.iNumRunError;
87 iTotalTicksInRun += aStats.iTotalTicksInRun;
88 OSCL_ASSERT(i64Valid == aStats.i64Valid);
89 i64TotalTicksInRun += aStats.i64TotalTicksInRun;
90 iNumCancel += aStats.iNumCancel;
91 if (aStats.iLeave != OsclErrNone)
92 iLeave = aStats.iLeave;
93 iNumInstances++;
94 }
95 #endif //#if(PV_SCHED_ENABLE_AO_STATS)
96
97
AddToScheduler()98 void PVActiveBase::AddToScheduler()
99 {
100 iThreadContext.EnterThreadContext();
101 if (iThreadContext.iScheduler)
102 {
103 iAddedNum = iThreadContext.iScheduler->iNumAOAdded++;
104
105 #if(PV_SCHED_ENABLE_AO_STATS)
106 //add to PV stat Q
107 if (!iPVActiveStats)
108 {
109 OsclAny* ptr = iThreadContext.iScheduler->iAlloc->allocate(sizeof(PVActiveStats));
110 OsclError::LeaveIfNull(ptr);
111 iPVActiveStats = OSCL_PLACEMENT_NEW(ptr, PVActiveStats(iThreadContext.iScheduler, (char*)iName.Str(), this));
112 iThreadContext.iScheduler->iPVStatQ.InsertTail(*iPVActiveStats);
113 //note: this memory is cleaned up in CleanupStatQ when the scheduler
114 //exits.
115 }
116 #endif
117 }
118 }
119
RemoveFromScheduler()120 void PVActiveBase::RemoveFromScheduler()
121 {
122 if (IsAdded())
123 {
124 if (iBusy)
125 Cancel();
126 //no additional de-queueing is needed-- once AOs are
127 //canceled they're not in any queues.
128 }
129
130 iThreadContext.ExitThreadContext();
131
132 #if(PV_SCHED_ENABLE_AO_STATS)
133 //destroy the link from the stats object back to this object.
134 //this means that a new stats object will be created if this AO
135 //is added to this or another scheduler again.
136 if (iPVActiveStats)
137 {
138 iPVActiveStats->iPVActiveBase = NULL;
139 //since we've unlinked this to the PVActiveStats object,
140 //we must prevent accessing the object again since it could
141 //get deleted.
142 iPVActiveStats = NULL;
143 }
144 #endif
145 }
146
Destroy()147 void PVActiveBase::Destroy()
148 //common AO cleanup.
149 {
150 RemoveFromScheduler();
151 }
152
Activate()153 void PVActiveBase::Activate()
154 //Activate an AO's request. This only does the portion of the
155 //activation that is common to both timers and non-timers.
156 {
157
158 //mimic standard symbian panics.
159 if (iBusy)
160 OsclError::Leave(OsclErrInvalidState);//EExecAlreadyActive
161 if (!iThreadContext.iOpen)
162 OsclError::Leave(OsclErrInvalidState);//EExecNotAdded
163
164 #if PV_SCHED_ENABLE_THREAD_CONTEXT_CHECKS
165 PVThreadContext::LeaveIfWrongThread(iThreadContext);
166 #endif
167
168 iBusy = true;
169
170 //caller will activate the timer. For
171 //non-timers, nothing else is needed.
172
173 }
174
IsAdded() const175 OSCL_EXPORT_REF bool PVActiveBase::IsAdded() const
176 {
177 return iThreadContext.iOpen;
178 }
179
180
Cancel()181 void PVActiveBase::Cancel()
182 {
183 if (iBusy)
184 {
185 #if PV_SCHED_ENABLE_THREAD_CONTEXT_CHECKS
186 //require same thread context for cancel calls,
187 //since we'll be calling the DoCancel routine.
188 PVThreadContext::LeaveIfWrongThread(iThreadContext);
189 #endif
190
191 //call the cancel handler-- this should
192 //complete the request if needed.
193 //Note: symbian calls the DoCancel even
194 //if the request is already complete, so
195 //I do the same in order to get the same
196 //behavior.
197 #if(PV_SCHED_ENABLE_AO_STATS)
198 iPVActiveStats->iNumCancel++;
199 #endif
200 DoCancel();
201
202 //wait for request to cancel.
203 iThreadContext.iScheduler->RequestCanceled(this);
204 }
205 }
206
207 /////////////////////
208 // OsclActiveObject
209 /////////////////////
210
OsclActiveObject(int32 aPriority,const char name[])211 OSCL_EXPORT_REF OsclActiveObject::OsclActiveObject(int32 aPriority, const char name[]):
212 PVActiveBase(name, aPriority)
213 {
214 iStatus = OSCL_REQUEST_ERR_NONE;
215 }
216
~OsclActiveObject()217 OSCL_EXPORT_REF OsclActiveObject::~OsclActiveObject()
218 {
219 //"typically, a derived class calls Cancel in its
220 //destructor"
221 Cancel();
222 PVActiveBase::Destroy();
223 }
224
PendComplete(int32 aStatus)225 OSCL_EXPORT_REF void OsclActiveObject::PendComplete(int32 aStatus)
226 {
227 iThreadContext.PendComplete(this, aStatus, EPVThreadContext_Undetermined);
228 }
229
AddToScheduler()230 OSCL_EXPORT_REF void OsclActiveObject::AddToScheduler()
231 {
232 PVActiveBase::AddToScheduler();
233 }
234
235
RemoveFromScheduler()236 OSCL_EXPORT_REF void OsclActiveObject::RemoveFromScheduler()
237 {
238 PVActiveBase::RemoveFromScheduler();
239 }
240
SetBusy()241 OSCL_EXPORT_REF void OsclActiveObject::SetBusy()
242 //Need this overload to prevent anyone from using
243 //OsclActiveObject::SetActive directly on systems that have
244 //that method (eg Symbian)
245 {
246 Activate();
247 //nothing else needed.
248 }
249
IsBusy() const250 OSCL_EXPORT_REF bool OsclActiveObject::IsBusy() const
251 //On systems with OsclActiveObj::IsActive, this function
252 //allows us to convert the return type to bool
253 {
254 return iBusy;
255 }
256
257
Cancel()258 OSCL_EXPORT_REF void OsclActiveObject::Cancel()
259 //Need this overload to prevent anyone from using
260 //OsclActiveObject::Cancel on systems that have that method (Symbian).
261 {
262 PVActiveBase::Cancel();
263 }
264
Priority() const265 OSCL_EXPORT_REF int32 OsclActiveObject::Priority() const
266 {
267 return iPVReadyQLink.iAOPriority;
268 }
269
Status() const270 OSCL_EXPORT_REF int32 OsclActiveObject::Status() const
271 //get the AO status value.
272 {
273 return iStatus.Value();
274 }
275
StatusRef()276 OSCL_EXPORT_REF OsclAOStatus& OsclActiveObject::StatusRef()
277 //get a ref to the AO status object.
278 {
279 return iStatus;
280 }
281
SetStatus(int32 s)282 OSCL_EXPORT_REF void OsclActiveObject::SetStatus(int32 s)
283 //set the AO status value.
284 {
285 iStatus = s;
286 }
287
PendForExec()288 OSCL_EXPORT_REF void OsclActiveObject::PendForExec()
289 //activate the AO request.
290 {
291 SetBusy();
292 iStatus = OSCL_REQUEST_PENDING;
293 }
294
RunIfNotReady()295 OSCL_EXPORT_REF void OsclActiveObject::RunIfNotReady()
296 //If the AO request is not active, activate and complete it.
297 {
298 if (!IsBusy())
299 {
300 PendForExec();
301 PendComplete(OSCL_REQUEST_ERR_NONE);
302 }
303 }
304
DoCancel()305 OSCL_EXPORT_REF void OsclActiveObject::DoCancel()
306 //default request canceler for AOs
307 {
308 if (iStatus == OSCL_REQUEST_PENDING)
309 iThreadContext.PendComplete(this, OSCL_REQUEST_ERR_CANCEL, EPVThreadContext_InThread);
310 }
311
RunError(int32 aError)312 OSCL_EXPORT_REF int32 OsclActiveObject::RunError(int32 aError)
313 //default error handler for active objects.
314 {
315 return aError;
316 }
317
318
319 /////////////////////
320 // OsclTimerObject
321 /////////////////////
322
OsclTimerObject(int32 aPriority,const char name[])323 OSCL_EXPORT_REF OsclTimerObject::OsclTimerObject(int32 aPriority, const char name[]):
324 PVActiveBase(name, aPriority)
325 {
326 SetStatus(OSCL_REQUEST_ERR_NONE);
327 }
328
~OsclTimerObject()329 OSCL_EXPORT_REF OsclTimerObject::~OsclTimerObject()
330 {
331 //"typically, a derived class calls Cancel in its
332 //destructor"
333 Cancel();
334 PVActiveBase::Destroy();
335 }
336
AddToScheduler()337 OSCL_EXPORT_REF void OsclTimerObject::AddToScheduler()
338 {
339 iPVReadyQLink.iTimeToRunTicks = 0;
340
341 PVActiveBase::AddToScheduler();
342 }
343
344
RemoveFromScheduler()345 OSCL_EXPORT_REF void OsclTimerObject::RemoveFromScheduler()
346 {
347 PVActiveBase::RemoveFromScheduler();
348
349 }
350
After(int32 aDelayMicrosec)351 OSCL_EXPORT_REF void OsclTimerObject::After(int32 aDelayMicrosec)
352 //like CTimer::After.
353 {
354 PVActiveBase::Activate();
355
356
357 //Just put this AO in the scheduler timer queue-- the scheduler
358 //will complete the request at the correct time.
359 iStatus = OSCL_REQUEST_PENDING;
360 iThreadContext.iScheduler->AddToExecTimerQ(this, aDelayMicrosec);
361
362 }
363
RunIfNotReady(uint32 aDelayMicrosec)364 OSCL_EXPORT_REF void OsclTimerObject::RunIfNotReady(uint32 aDelayMicrosec)
365 //If the AO is not ready, start its timeout for completion.
366 {
367 if (!IsBusy())
368
369 {
370 if (aDelayMicrosec > 0)
371 {
372 OsclTimerObject::After(aDelayMicrosec);
373 }
374 else
375 {
376 // If delay is 0, make ready and complete pend immediately, to avoid going through the timer queue
377 SetBusy();
378 SetStatus(OSCL_REQUEST_PENDING);
379 if (IsAdded())
380 {
381 iThreadContext.PendComplete(this, OSCL_REQUEST_ERR_NONE, EPVThreadContext_InThread);
382 }
383 }
384 }
385 }
386
SetBusy()387 OSCL_EXPORT_REF void OsclTimerObject::SetBusy()
388 //Need this overload to prevent anyone from using
389 //OsclActiveObject::SetActive on Symbian.
390 {
391 PVActiveBase::Activate();
392
393 }
394
IsBusy() const395 OSCL_EXPORT_REF bool OsclTimerObject::IsBusy() const
396 //needed to prevent using OsclActiveObject::IsActive, just to
397 //get correct return type bool instead of TBool.
398 {
399 return iBusy;
400 }
401
402
Cancel()403 OSCL_EXPORT_REF void OsclTimerObject::Cancel()
404 //Need this overload to prevent anyone from using
405 //OsclActiveObject::Cancel on Symbian.
406 {
407 PVActiveBase::Cancel();
408 }
409
Priority() const410 OSCL_EXPORT_REF int32 OsclTimerObject::Priority() const
411 {
412 return iPVReadyQLink.iAOPriority;
413 }
414
Status() const415 OSCL_EXPORT_REF int32 OsclTimerObject::Status() const
416 {
417 return iStatus.Value();
418 }
419
StatusRef()420 OSCL_EXPORT_REF OsclAOStatus& OsclTimerObject::StatusRef()
421 {
422 return iStatus;
423 }
424
SetStatus(int32 s)425 OSCL_EXPORT_REF void OsclTimerObject::SetStatus(int32 s)
426 {
427 iStatus = s;
428 }
429
DoCancel()430 OSCL_EXPORT_REF void OsclTimerObject::DoCancel()
431 //default request canceler for timer objects.
432 {
433 //cancel the pending timeout.
434 if (iStatus == OSCL_REQUEST_PENDING)
435 iThreadContext.iScheduler->PendComplete(this, OSCL_REQUEST_ERR_CANCEL, EPVThreadContext_InThread);
436 }
437
RunError(int32 aError)438 OSCL_EXPORT_REF int32 OsclTimerObject::RunError(int32 aError)
439 //default error handler for timer objects.
440 {
441 return aError;
442 }
443
444
445
446