IObject.c revision 7a79f519d89eb0e1a5b3f4005484b16d6854d7e2
1/* 2 * Copyright (C) 2010 The Android Open Source Project 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 express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* Object implementation */ 18 19#include "sles_allinclusive.h" 20 21 22// Called by a worker thread to handle an asynchronous Object.Realize. 23// Parameter self is the Object. 24 25static void HandleRealize(void *self, int unused) 26{ 27 28 // validate input parameters 29 IObject *this = (IObject *) self; 30 assert(NULL != this); 31 const ClassTable *class__ = this->mClass; 32 assert(NULL != class__); 33 AsyncHook realize = class__->mRealize; 34 SLresult result; 35 SLuint8 state; 36 37 // check object state 38 object_lock_exclusive(this); 39 state = this->mState; 40 switch (state) { 41 42 case SL_OBJECT_STATE_REALIZING_1: // normal case 43 if (NULL != realize) { 44 this->mState = SL_OBJECT_STATE_REALIZING_2; 45 object_unlock_exclusive(this); 46 // Note that the mutex is unlocked during the realize hook 47 result = (*realize)(this, SL_BOOLEAN_TRUE); 48 object_lock_exclusive(this); 49 assert(SL_OBJECT_STATE_REALIZING_2 == this->mState); 50 state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 51 SL_OBJECT_STATE_UNREALIZED; 52 } else { 53 result = SL_RESULT_SUCCESS; 54 state = SL_OBJECT_STATE_REALIZED; 55 } 56 break; 57 58 case SL_OBJECT_STATE_REALIZING_1A: // operation was aborted while on work queue 59 result = SL_RESULT_OPERATION_ABORTED; 60 state = SL_OBJECT_STATE_UNREALIZED; 61 break; 62 63 default: // impossible 64 assert(SL_BOOLEAN_FALSE); 65 result = SL_RESULT_INTERNAL_ERROR; 66 break; 67 68 } 69 70 // mutex is locked, update state 71 this->mState = state; 72 73 // Make a copy of these, so we can call the callback with mutex unlocked 74 slObjectCallback callback = this->mCallback; 75 void *context = this->mContext; 76 object_unlock_exclusive(this); 77 78 // Note that the mutex is unlocked during the callback 79 if (NULL != callback) 80 (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 81} 82 83 84static SLresult IObject_Realize(SLObjectItf self, SLboolean async) 85{ 86 SL_ENTER_INTERFACE 87 88 IObject *this = (IObject *) self; 89 SLuint8 state; 90 const ClassTable *class__ = this->mClass; 91 object_lock_exclusive(this); 92 state = this->mState; 93 // Reject redundant calls to Realize 94 if (SL_OBJECT_STATE_UNREALIZED != state) { 95 object_unlock_exclusive(this); 96 result = SL_RESULT_PRECONDITIONS_VIOLATED; 97 } else { 98 // Asynchronous: mark operation pending and cancellable 99 if (async && (SL_OBJECTID_ENGINE != class__->mObjectID)) { 100 state = SL_OBJECT_STATE_REALIZING_1; 101 // Synchronous: mark operation pending and non-cancellable 102 } else { 103 state = SL_OBJECT_STATE_REALIZING_2; 104 } 105 this->mState = state; 106 object_unlock_exclusive(this); 107 switch (state) { 108 case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine 109 assert(async); 110 result = ThreadPool_add(&this->mEngine->mThreadPool, HandleRealize, this, 0); 111 if (SL_RESULT_SUCCESS != result) { 112 // Engine was destroyed during realize, or insufficient memory 113 object_lock_exclusive(this); 114 this->mState = SL_OBJECT_STATE_UNREALIZED; 115 object_unlock_exclusive(this); 116 } 117 break; 118 case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine 119 { 120 AsyncHook realize = class__->mRealize; 121 // Note that the mutex is unlocked during the realize hook 122 result = (NULL != realize) ? (*realize)(this, async) : SL_RESULT_SUCCESS; 123 object_lock_exclusive(this); 124 assert(SL_OBJECT_STATE_REALIZING_2 == this->mState); 125 state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 126 SL_OBJECT_STATE_UNREALIZED; 127 this->mState = state; 128 slObjectCallback callback = this->mCallback; 129 void *context = this->mContext; 130 object_unlock_exclusive(this); 131 // asynchronous Realize on an Engine is actually done synchronously, but still has 132 // callback because there is no thread pool yet to do it asynchronously. 133 if (async && (NULL != callback)) 134 (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, 135 NULL); 136 } 137 break; 138 default: // impossible 139 assert(SL_BOOLEAN_FALSE); 140 break; 141 } 142 } 143 144 SL_LEAVE_INTERFACE 145} 146 147 148// Called by a worker thread to handle an asynchronous Object.Resume. 149// Parameter self is the Object. 150 151static void HandleResume(void *self, int unused) 152{ 153 154 // valid input parameters 155 IObject *this = (IObject *) self; 156 assert(NULL != this); 157 const ClassTable *class__ = this->mClass; 158 assert(NULL != class__); 159 AsyncHook resume = class__->mResume; 160 SLresult result; 161 SLuint8 state; 162 163 // check object state 164 object_lock_exclusive(this); 165 state = this->mState; 166 switch (state) { 167 168 case SL_OBJECT_STATE_RESUMING_1: // normal case 169 if (NULL != resume) { 170 this->mState = SL_OBJECT_STATE_RESUMING_2; 171 object_unlock_exclusive(this); 172 // Note that the mutex is unlocked during the resume hook 173 result = (*resume)(this, SL_BOOLEAN_TRUE); 174 object_lock_exclusive(this); 175 assert(SL_OBJECT_STATE_RESUMING_2 == this->mState); 176 state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 177 SL_OBJECT_STATE_SUSPENDED; 178 } else { 179 result = SL_RESULT_SUCCESS; 180 state = SL_OBJECT_STATE_REALIZED; 181 } 182 break; 183 184 case SL_OBJECT_STATE_RESUMING_1A: // operation was aborted while on work queue 185 result = SL_RESULT_OPERATION_ABORTED; 186 state = SL_OBJECT_STATE_SUSPENDED; 187 break; 188 189 default: // impossible 190 assert(SL_BOOLEAN_FALSE); 191 result = SL_RESULT_INTERNAL_ERROR; 192 break; 193 194 } 195 196 // mutex is unlocked, update state 197 this->mState = state; 198 199 // Make a copy of these, so we can call the callback with mutex unlocked 200 slObjectCallback callback = this->mCallback; 201 void *context = this->mContext; 202 object_unlock_exclusive(this); 203 204 // Note that the mutex is unlocked during the callback 205 if (NULL != callback) 206 (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 207} 208 209 210static SLresult IObject_Resume(SLObjectItf self, SLboolean async) 211{ 212 SL_ENTER_INTERFACE 213 214 IObject *this = (IObject *) self; 215 const ClassTable *class__ = this->mClass; 216 SLuint8 state; 217 object_lock_exclusive(this); 218 state = this->mState; 219 // Reject redundant calls to Resume 220 if (SL_OBJECT_STATE_SUSPENDED != state) { 221 object_unlock_exclusive(this); 222 result = SL_RESULT_PRECONDITIONS_VIOLATED; 223 } else { 224 // Asynchronous: mark operation pending and cancellable 225 if (async) { 226 state = SL_OBJECT_STATE_RESUMING_1; 227 // Synchronous: mark operatio pending and non-cancellable 228 } else { 229 state = SL_OBJECT_STATE_RESUMING_2; 230 } 231 this->mState = state; 232 object_unlock_exclusive(this); 233 switch (state) { 234 case SL_OBJECT_STATE_RESUMING_1: // asynchronous 235 assert(async); 236 result = ThreadPool_add(&this->mEngine->mThreadPool, HandleResume, this, 0); 237 if (SL_RESULT_SUCCESS != result) { 238 // Engine was destroyed during resume, or insufficient memory 239 object_lock_exclusive(this); 240 this->mState = SL_OBJECT_STATE_SUSPENDED; 241 object_unlock_exclusive(this); 242 } 243 break; 244 case SL_OBJECT_STATE_RESUMING_2: // synchronous 245 { 246 AsyncHook resume = class__->mResume; 247 // Note that the mutex is unlocked during the resume hook 248 result = (NULL != resume) ? (*resume)(this, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS; 249 object_lock_exclusive(this); 250 assert(SL_OBJECT_STATE_RESUMING_2 == this->mState); 251 this->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 252 SL_OBJECT_STATE_SUSPENDED; 253 object_unlock_exclusive(this); 254 } 255 break; 256 default: // impossible 257 assert(SL_BOOLEAN_FALSE); 258 break; 259 } 260 } 261 262 SL_LEAVE_INTERFACE 263} 264 265 266static SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState) 267{ 268 SL_ENTER_INTERFACE 269 270 if (NULL == pState) { 271 result = SL_RESULT_PARAMETER_INVALID; 272 } else { 273 IObject *this = (IObject *) self; 274 // Note that the state is immediately obsolete, so a peek lock is safe 275 object_lock_peek(this); 276 SLuint8 state = this->mState; 277 object_unlock_peek(this); 278 // Re-map the realizing, resuming, and suspending states 279 switch (state) { 280 case SL_OBJECT_STATE_REALIZING_1: 281 case SL_OBJECT_STATE_REALIZING_1A: 282 case SL_OBJECT_STATE_REALIZING_2: 283 state = SL_OBJECT_STATE_UNREALIZED; 284 break; 285 case SL_OBJECT_STATE_RESUMING_1: 286 case SL_OBJECT_STATE_RESUMING_1A: 287 case SL_OBJECT_STATE_RESUMING_2: 288 case SL_OBJECT_STATE_SUSPENDING: 289 state = SL_OBJECT_STATE_SUSPENDED; 290 break; 291 case SL_OBJECT_STATE_UNREALIZED: 292 case SL_OBJECT_STATE_REALIZED: 293 case SL_OBJECT_STATE_SUSPENDED: 294 // These are the "official" object states, return them as is 295 break; 296 default: 297 assert(SL_BOOLEAN_FALSE); 298 break; 299 } 300 *pState = state; 301 result = SL_RESULT_SUCCESS; 302 } 303 304 SL_LEAVE_INTERFACE 305} 306 307 308static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface) 309{ 310 SL_ENTER_INTERFACE 311 312 if (NULL == pInterface) { 313 result = SL_RESULT_PARAMETER_INVALID; 314 } else { 315 void *interface = NULL; 316 if (NULL == iid) { 317 result = SL_RESULT_PARAMETER_INVALID; 318 } else { 319 IObject *this = (IObject *) self; 320 const ClassTable *class__ = this->mClass; 321 int MPH, index; 322 if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH]))) { 323 result = SL_RESULT_FEATURE_UNSUPPORTED; 324 } else { 325 unsigned mask = 1 << index; 326 object_lock_exclusive(this); 327 // Can't get interface on a suspended/suspending/resuming object 328 if (SL_OBJECT_STATE_REALIZED != this->mState) { 329 result = SL_RESULT_PRECONDITIONS_VIOLATED; 330 } else { 331 switch (this->mInterfaceStates[index]) { 332 case INTERFACE_EXPOSED: 333 case INTERFACE_ADDED: 334 // Note that interface has been gotten, 335 // for debugger and to detect incorrect use of interfaces 336 this->mGottenMask |= mask; 337 interface = (char *) this + class__->mInterfaces[index].mOffset; 338 result = SL_RESULT_SUCCESS; 339 break; 340 // Can't get interface if uninitialized/suspend(ed,ing)/resuming/adding/removing 341 default: 342 result = SL_RESULT_FEATURE_UNSUPPORTED; 343 break; 344 } 345 } 346 object_unlock_exclusive(this); 347 } 348 } 349 *(void **)pInterface = interface; 350 } 351 352 SL_LEAVE_INTERFACE 353} 354 355 356static SLresult IObject_RegisterCallback(SLObjectItf self, 357 slObjectCallback callback, void *pContext) 358{ 359 SL_ENTER_INTERFACE 360 361 IObject *this = (IObject *) self; 362 object_lock_exclusive(this); 363 this->mCallback = callback; 364 this->mContext = pContext; 365 object_unlock_exclusive(this); 366 result = SL_RESULT_SUCCESS; 367 368 SL_LEAVE_INTERFACE 369} 370 371 372// internal common code for Abort and Destroy 373 374static void Abort_internal(IObject *this, SLboolean shutdown) 375{ 376 const ClassTable *class__ = this->mClass; 377 object_lock_exclusive(this); 378 // Abort asynchronous operations on the object 379 switch (this->mState) { 380 case SL_OBJECT_STATE_REALIZING_1: // Realize 381 this->mState = SL_OBJECT_STATE_REALIZING_1A; 382 break; 383 case SL_OBJECT_STATE_RESUMING_1: // Resume 384 this->mState = SL_OBJECT_STATE_RESUMING_1A; 385 break; 386 default: 387 break; 388 } 389 // Abort asynchronous operations on interfaces 390 SLuint8 *interfaceStateP = this->mInterfaceStates; 391 unsigned index; 392 for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) { 393 switch (*interfaceStateP) { 394 case INTERFACE_ADDING_1: // AddInterface 395 *interfaceStateP = INTERFACE_ADDING_1A; 396 break; 397 case INTERFACE_RESUMING_1: // ResumeInterface 398 *interfaceStateP = INTERFACE_RESUMING_1A; 399 break; 400 default: 401 break; 402 } 403 } 404 object_unlock_exclusive(this); 405} 406 407 408static void IObject_AbortAsyncOperation(SLObjectItf self) 409{ 410 SL_ENTER_INTERFACE_VOID 411 412 IObject *this = (IObject *) self; 413 Abort_internal(this, SL_BOOLEAN_FALSE); 414 415 SL_LEAVE_INTERFACE_VOID 416} 417 418 419static void IObject_Destroy(SLObjectItf self) 420{ 421 SL_ENTER_INTERFACE_VOID 422 423 IObject *this = (IObject *) self; 424 Abort_internal(this, SL_BOOLEAN_TRUE); 425 const ClassTable *class__ = this->mClass; 426 VoidHook destroy = class__->mDestroy; 427 const struct iid_vtable *x = class__->mInterfaces; 428 // const, no lock needed 429 IEngine *thisEngine = this->mEngine; 430 unsigned i = this->mInstanceID; 431 assert(0 < i && i <= MAX_INSTANCE); 432 --i; 433 // remove object from exposure to sync thread and debugger 434 interface_lock_exclusive(thisEngine); 435 assert(0 < thisEngine->mInstanceCount); 436 --thisEngine->mInstanceCount; 437 assert(0 != thisEngine->mInstanceMask); 438 thisEngine->mInstanceMask &= ~(1 << i); 439 assert(thisEngine->mInstances[i] == this); 440 thisEngine->mInstances[i] = NULL; 441#ifdef USE_SDL 442 if ((SL_OBJECTID_OUTPUTMIX == class__->mObjectID) && 443 (((COutputMix *) this == thisEngine->mOutputMix))) { 444 SDL_PauseAudio(1); 445 thisEngine->mOutputMix = NULL; 446 // Note we don't attempt to connect another output mix to SDL 447 } 448#endif 449 interface_unlock_exclusive(thisEngine); 450 object_lock_exclusive(this); 451 if (NULL != destroy) 452 (*destroy)(this); 453 // Call the deinitializer for each currently exposed interface, 454 // whether it is implicit, explicit, optional, or dynamically added. 455 unsigned incorrect = 0; 456 SLuint8 *interfaceStateP = this->mInterfaceStates; 457 unsigned index; 458 for (index = 0; index < class__->mInterfaceCount; ++index, ++x, ++interfaceStateP) { 459 SLuint32 state = *interfaceStateP; 460 switch (state) { 461 case INTERFACE_UNINITIALIZED: 462 break; 463 case INTERFACE_EXPOSED: // quiescent states 464 case INTERFACE_ADDED: 465 case INTERFACE_SUSPENDED: 466 { 467 VoidHook deinit = MPH_init_table[x->mMPH].mDeinit; 468 if (NULL != deinit) 469 (*deinit)((char *) this + x->mOffset); 470 } 471 break; 472 case INTERFACE_ADDING_1: // active states indicate incorrect use of API 473 case INTERFACE_ADDING_1A: 474 case INTERFACE_ADDING_2: 475 case INTERFACE_RESUMING_1: 476 case INTERFACE_RESUMING_1A: 477 case INTERFACE_RESUMING_2: 478 case INTERFACE_REMOVING: 479 case INTERFACE_SUSPENDING: 480 ++incorrect; 481 break; 482 default: 483 assert(SL_BOOLEAN_FALSE); 484 break; 485 } 486 } 487 // redundant: this->mState = SL_OBJECT_STATE_UNREALIZED; 488 object_unlock_exclusive(this); 489#ifndef NDEBUG 490 memset(this, 0x55, class__->mSize); 491#endif 492 free(this); 493 // one or more interfaces was actively changing at time of Destroy 494 assert(incorrect == 0); 495 496 SL_LEAVE_INTERFACE_VOID 497} 498 499 500static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable) 501{ 502 SL_ENTER_INTERFACE 503 504#ifdef USE_CONFORMANCE 505 IObject *this = (IObject *) self; 506 object_lock_exclusive(this); 507 this->mPriority = priority; 508 this->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize 509 object_unlock_exclusive(this); 510 result = SL_RESULT_SUCCESS; 511#else 512 result = SL_RESULT_FEATURE_UNSUPPORTED; 513#endif 514 515 SL_LEAVE_INTERFACE 516} 517 518 519static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable) 520{ 521 SL_ENTER_INTERFACE 522 523#ifdef USE_CONFORMANCE 524 if (NULL == pPriority || NULL == pPreemptable) { 525 result = SL_RESULT_PARAMETER_INVALID; 526 } else { 527 IObject *this = (IObject *) self; 528 object_lock_shared(this); 529 SLint32 priority = this->mPriority; 530 SLboolean preemptable = this->mPreemptable; 531 object_unlock_shared(this); 532 *pPriority = priority; 533 *pPreemptable = preemptable; 534 result = SL_RESULT_SUCCESS; 535 } 536#else 537 result = SL_RESULT_FEATURE_UNSUPPORTED; 538#endif 539 540 SL_LEAVE_INTERFACE 541} 542 543 544static SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self, 545 SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled) 546{ 547 SL_ENTER_INTERFACE 548 549#ifdef USE_CONFORMANCE 550 result = SL_RESULT_SUCCESS; 551 if (0 < numInterfaces) { 552 SLuint32 i; 553 if (NULL == pInterfaceIDs) { 554 result = SL_RESULT_PARAMETER_INVALID; 555 } else { 556 IObject *this = (IObject *) self; 557 const ClassTable *class__ = this->mClass; 558 unsigned lossOfControlMask = 0; 559 // The cast is due to a typo in the spec, bug 6482 560 for (i = 0; i < (SLuint32) numInterfaces; ++i) { 561 SLInterfaceID iid = pInterfaceIDs[i]; 562 if (NULL == iid) { 563 result = SL_RESULT_PARAMETER_INVALID; 564 goto out; 565 } 566 int MPH, index; 567 // We ignore without error any invalid MPH or index, but spec is unclear 568 if ((0 <= (MPH = IID_to_MPH(iid))) && (0 <= (index = class__->mMPH_to_index[MPH]))) 569 lossOfControlMask |= (1 << index); 570 } 571 object_lock_exclusive(this); 572 if (enabled) 573 this->mLossOfControlMask |= lossOfControlMask; 574 else 575 this->mLossOfControlMask &= ~lossOfControlMask; 576 object_unlock_exclusive(this); 577 } 578 } 579out: 580#else 581 result = SL_RESULT_FEATURE_UNSUPPORTED; 582#endif 583 584 SL_LEAVE_INTERFACE 585} 586 587 588static const struct SLObjectItf_ IObject_Itf = { 589 IObject_Realize, 590 IObject_Resume, 591 IObject_GetState, 592 IObject_GetInterface, 593 IObject_RegisterCallback, 594 IObject_AbortAsyncOperation, 595 IObject_Destroy, 596 IObject_SetPriority, 597 IObject_GetPriority, 598 IObject_SetLossOfControlInterfaces, 599}; 600 601void IObject_init(void *self) 602{ 603 IObject *this = (IObject *) self; 604 this->mItf = &IObject_Itf; 605 // initialized in construct: 606 // mClass 607 // mInstanceID 608 // mLossOfControlMask 609 // mEngine 610 // mInstanceStates 611 this->mState = SL_OBJECT_STATE_UNREALIZED; 612 this->mGottenMask = 1; // IObject 613 this->mAttributesMask = 0; 614 this->mCallback = NULL; 615 this->mContext = NULL; 616#ifdef USE_CONFORMANCE 617 this->mPriority = SL_PRIORITY_NORMAL; 618 this->mPreemptable = SL_BOOLEAN_FALSE; 619#endif 620 int ok; 621 ok = pthread_mutex_init(&this->mMutex, (const pthread_mutexattr_t *) NULL); 622 assert(0 == ok); 623 ok = pthread_cond_init(&this->mCond, (const pthread_condattr_t *) NULL); 624 assert(0 == ok); 625} 626