Home | History | Annotate | Download | only in src
      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 
     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 
     48 PVActiveBase::~PVActiveBase()
     49 {
     50     if (iBusy)
     51         OsclError::Leave(OsclErrInvalidState);//EExecStillReadyOnDestruct
     52 }
     53 
     54 #if(PV_SCHED_ENABLE_AO_STATS)
     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 }
     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 }
     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 
     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 
    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 
    147 void PVActiveBase::Destroy()
    148 //common AO cleanup.
    149 {
    150     RemoveFromScheduler();
    151 }
    152 
    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 
    175 OSCL_EXPORT_REF bool PVActiveBase::IsAdded() const
    176 {
    177     return iThreadContext.iOpen;
    178 }
    179 
    180 
    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 
    211 OSCL_EXPORT_REF OsclActiveObject::OsclActiveObject(int32 aPriority, const char name[]):
    212         PVActiveBase(name, aPriority)
    213 {
    214     iStatus = OSCL_REQUEST_ERR_NONE;
    215 }
    216 
    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 
    225 OSCL_EXPORT_REF void OsclActiveObject::PendComplete(int32 aStatus)
    226 {
    227     iThreadContext.PendComplete(this, aStatus, EPVThreadContext_Undetermined);
    228 }
    229 
    230 OSCL_EXPORT_REF void OsclActiveObject::AddToScheduler()
    231 {
    232     PVActiveBase::AddToScheduler();
    233 }
    234 
    235 
    236 OSCL_EXPORT_REF void OsclActiveObject::RemoveFromScheduler()
    237 {
    238     PVActiveBase::RemoveFromScheduler();
    239 }
    240 
    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 
    250 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 
    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 
    265 OSCL_EXPORT_REF int32 OsclActiveObject::Priority() const
    266 {
    267     return iPVReadyQLink.iAOPriority;
    268 }
    269 
    270 OSCL_EXPORT_REF int32 OsclActiveObject::Status() const
    271 //get the AO status value.
    272 {
    273     return iStatus.Value();
    274 }
    275 
    276 OSCL_EXPORT_REF OsclAOStatus& OsclActiveObject::StatusRef()
    277 //get a ref to the AO status object.
    278 {
    279     return iStatus;
    280 }
    281 
    282 OSCL_EXPORT_REF void OsclActiveObject::SetStatus(int32 s)
    283 //set the AO status value.
    284 {
    285     iStatus = s;
    286 }
    287 
    288 OSCL_EXPORT_REF void OsclActiveObject::PendForExec()
    289 //activate the AO request.
    290 {
    291     SetBusy();
    292     iStatus = OSCL_REQUEST_PENDING;
    293 }
    294 
    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 
    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 
    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 
    323 OSCL_EXPORT_REF OsclTimerObject::OsclTimerObject(int32 aPriority, const char name[]):
    324         PVActiveBase(name, aPriority)
    325 {
    326     SetStatus(OSCL_REQUEST_ERR_NONE);
    327 }
    328 
    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 
    337 OSCL_EXPORT_REF void OsclTimerObject::AddToScheduler()
    338 {
    339     iPVReadyQLink.iTimeToRunTicks = 0;
    340 
    341     PVActiveBase::AddToScheduler();
    342 }
    343 
    344 
    345 OSCL_EXPORT_REF void OsclTimerObject::RemoveFromScheduler()
    346 {
    347     PVActiveBase::RemoveFromScheduler();
    348 
    349 }
    350 
    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 
    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 
    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 
    395 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 
    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 
    410 OSCL_EXPORT_REF int32 OsclTimerObject::Priority() const
    411 {
    412     return iPVReadyQLink.iAOPriority;
    413 }
    414 
    415 OSCL_EXPORT_REF int32 OsclTimerObject::Status() const
    416 {
    417     return iStatus.Value();
    418 }
    419 
    420 OSCL_EXPORT_REF OsclAOStatus& OsclTimerObject::StatusRef()
    421 {
    422     return iStatus;
    423 }
    424 
    425 OSCL_EXPORT_REF void OsclTimerObject::SetStatus(int32 s)
    426 {
    427     iStatus = s;
    428 }
    429 
    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 
    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