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