• 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 
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