IObject.c revision f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1ee
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 84 85static SLresult IObject_Realize(SLObjectItf self, SLboolean async) 86{ 87 SL_ENTER_INTERFACE 88 89 IObject *this = (IObject *) self; 90 SLuint8 state; 91 const ClassTable *class__ = this->mClass; 92 object_lock_exclusive(this); 93 state = this->mState; 94 // Reject redundant calls to Realize 95 if (SL_OBJECT_STATE_UNREALIZED != state) { 96 object_unlock_exclusive(this); 97 result = SL_RESULT_PRECONDITIONS_VIOLATED; 98 } else { 99 // Asynchronous: mark operation pending and cancellable 100 if (async && (SL_OBJECTID_ENGINE != class__->mObjectID)) { 101 state = SL_OBJECT_STATE_REALIZING_1; 102 // Synchronous: mark operation pending and non-cancellable 103 } else { 104 state = SL_OBJECT_STATE_REALIZING_2; 105 } 106 this->mState = state; 107 object_unlock_exclusive(this); 108 switch (state) { 109 case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine 110 assert(async); 111 result = ThreadPool_add(&this->mEngine->mThreadPool, HandleRealize, this, 0); 112 if (SL_RESULT_SUCCESS != result) { 113 // Engine was destroyed during realize, or insufficient memory 114 object_lock_exclusive(this); 115 this->mState = SL_OBJECT_STATE_UNREALIZED; 116 object_unlock_exclusive(this); 117 } 118 break; 119 case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine 120 { 121 AsyncHook realize = class__->mRealize; 122 // Note that the mutex is unlocked during the realize hook 123 result = (NULL != realize) ? (*realize)(this, async) : SL_RESULT_SUCCESS; 124 object_lock_exclusive(this); 125 assert(SL_OBJECT_STATE_REALIZING_2 == this->mState); 126 state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 127 SL_OBJECT_STATE_UNREALIZED; 128 this->mState = state; 129 slObjectCallback callback = this->mCallback; 130 void *context = this->mContext; 131 object_unlock_exclusive(this); 132 // asynchronous Realize on an Engine is actually done synchronously, but still has 133 // callback because there is no thread pool yet to do it asynchronously. 134 if (async && (NULL != callback)) { 135 (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, 136 NULL); 137 } 138 } 139 break; 140 default: // impossible 141 assert(SL_BOOLEAN_FALSE); 142 break; 143 } 144 } 145 146 SL_LEAVE_INTERFACE 147} 148 149 150// Called by a worker thread to handle an asynchronous Object.Resume. 151// Parameter self is the Object. 152 153static void HandleResume(void *self, int unused) 154{ 155 156 // valid input parameters 157 IObject *this = (IObject *) self; 158 assert(NULL != this); 159 const ClassTable *class__ = this->mClass; 160 assert(NULL != class__); 161 AsyncHook resume = class__->mResume; 162 SLresult result; 163 SLuint8 state; 164 165 // check object state 166 object_lock_exclusive(this); 167 state = this->mState; 168 switch (state) { 169 170 case SL_OBJECT_STATE_RESUMING_1: // normal case 171 if (NULL != resume) { 172 this->mState = SL_OBJECT_STATE_RESUMING_2; 173 object_unlock_exclusive(this); 174 // Note that the mutex is unlocked during the resume hook 175 result = (*resume)(this, SL_BOOLEAN_TRUE); 176 object_lock_exclusive(this); 177 assert(SL_OBJECT_STATE_RESUMING_2 == this->mState); 178 state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 179 SL_OBJECT_STATE_SUSPENDED; 180 } else { 181 result = SL_RESULT_SUCCESS; 182 state = SL_OBJECT_STATE_REALIZED; 183 } 184 break; 185 186 case SL_OBJECT_STATE_RESUMING_1A: // operation was aborted while on work queue 187 result = SL_RESULT_OPERATION_ABORTED; 188 state = SL_OBJECT_STATE_SUSPENDED; 189 break; 190 191 default: // impossible 192 assert(SL_BOOLEAN_FALSE); 193 result = SL_RESULT_INTERNAL_ERROR; 194 break; 195 196 } 197 198 // mutex is unlocked, update state 199 this->mState = state; 200 201 // Make a copy of these, so we can call the callback with mutex unlocked 202 slObjectCallback callback = this->mCallback; 203 void *context = this->mContext; 204 object_unlock_exclusive(this); 205 206 // Note that the mutex is unlocked during the callback 207 if (NULL != callback) { 208 (*callback)(&this->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 209 } 210} 211 212 213static SLresult IObject_Resume(SLObjectItf self, SLboolean async) 214{ 215 SL_ENTER_INTERFACE 216 217 IObject *this = (IObject *) self; 218 const ClassTable *class__ = this->mClass; 219 SLuint8 state; 220 object_lock_exclusive(this); 221 state = this->mState; 222 // Reject redundant calls to Resume 223 if (SL_OBJECT_STATE_SUSPENDED != state) { 224 object_unlock_exclusive(this); 225 result = SL_RESULT_PRECONDITIONS_VIOLATED; 226 } else { 227 // Asynchronous: mark operation pending and cancellable 228 if (async) { 229 state = SL_OBJECT_STATE_RESUMING_1; 230 // Synchronous: mark operatio pending and non-cancellable 231 } else { 232 state = SL_OBJECT_STATE_RESUMING_2; 233 } 234 this->mState = state; 235 object_unlock_exclusive(this); 236 switch (state) { 237 case SL_OBJECT_STATE_RESUMING_1: // asynchronous 238 assert(async); 239 result = ThreadPool_add(&this->mEngine->mThreadPool, HandleResume, this, 0); 240 if (SL_RESULT_SUCCESS != result) { 241 // Engine was destroyed during resume, or insufficient memory 242 object_lock_exclusive(this); 243 this->mState = SL_OBJECT_STATE_SUSPENDED; 244 object_unlock_exclusive(this); 245 } 246 break; 247 case SL_OBJECT_STATE_RESUMING_2: // synchronous 248 { 249 AsyncHook resume = class__->mResume; 250 // Note that the mutex is unlocked during the resume hook 251 result = (NULL != resume) ? (*resume)(this, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS; 252 object_lock_exclusive(this); 253 assert(SL_OBJECT_STATE_RESUMING_2 == this->mState); 254 this->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 255 SL_OBJECT_STATE_SUSPENDED; 256 object_unlock_exclusive(this); 257 } 258 break; 259 default: // impossible 260 assert(SL_BOOLEAN_FALSE); 261 break; 262 } 263 } 264 265 SL_LEAVE_INTERFACE 266} 267 268 269static SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState) 270{ 271 SL_ENTER_INTERFACE 272 273 if (NULL == pState) { 274 result = SL_RESULT_PARAMETER_INVALID; 275 } else { 276 IObject *this = (IObject *) self; 277 // Note that the state is immediately obsolete, so a peek lock is safe 278 object_lock_peek(this); 279 SLuint8 state = this->mState; 280 object_unlock_peek(this); 281 // Re-map the realizing, resuming, and suspending states 282 switch (state) { 283 case SL_OBJECT_STATE_REALIZING_1: 284 case SL_OBJECT_STATE_REALIZING_1A: 285 case SL_OBJECT_STATE_REALIZING_2: 286 case SL_OBJECT_STATE_DESTROYING: // application shouldn't call GetState after Destroy 287 state = SL_OBJECT_STATE_UNREALIZED; 288 break; 289 case SL_OBJECT_STATE_RESUMING_1: 290 case SL_OBJECT_STATE_RESUMING_1A: 291 case SL_OBJECT_STATE_RESUMING_2: 292 case SL_OBJECT_STATE_SUSPENDING: 293 state = SL_OBJECT_STATE_SUSPENDED; 294 break; 295 case SL_OBJECT_STATE_UNREALIZED: 296 case SL_OBJECT_STATE_REALIZED: 297 case SL_OBJECT_STATE_SUSPENDED: 298 // These are the "official" object states, return them as is 299 break; 300 default: 301 assert(SL_BOOLEAN_FALSE); 302 break; 303 } 304 *pState = state; 305 result = SL_RESULT_SUCCESS; 306 } 307 308 SL_LEAVE_INTERFACE 309} 310 311static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface) 312{ 313 SL_ENTER_INTERFACE 314 315 if (NULL == pInterface) { 316 result = SL_RESULT_PARAMETER_INVALID; 317 } else { 318 void *interface = NULL; 319 if (NULL == iid) { 320 result = SL_RESULT_PARAMETER_INVALID; 321 } else { 322 IObject *this = (IObject *) self; 323 const ClassTable *class__ = this->mClass; 324 int MPH, index; 325 if ((0 > (MPH = IID_to_MPH(iid))) || 326 // there must an initialization hook present 327 (NULL == MPH_init_table[MPH].mInit) || 328 (0 > (index = class__->mMPH_to_index[MPH]))) { 329 result = SL_RESULT_FEATURE_UNSUPPORTED; 330 } else { 331 unsigned mask = 1 << index; 332 object_lock_exclusive(this); 333 if ((SL_OBJECT_STATE_REALIZED != this->mState) && (INTERFACE_EXPLICIT_PREREALIZE != 334 class__->mInterfaces[index].mInterface)) { 335 // Can't get interface on a suspended/suspending/resuming object 336 // unless this is an explicit pre-realize interface 337 result = SL_RESULT_PRECONDITIONS_VIOLATED; 338 } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER == class__->mObjectID) 339 && (1 == ((CAudioPlayer *) this)->mNumChannels)) { 340 // Can't get the MuteSolo interface of an audio player if the channel count is 341 // mono, but _can_ get the MuteSolo interface if the channel count is unknown 342 result = SL_RESULT_FEATURE_UNSUPPORTED; 343 } else { 344 switch (this->mInterfaceStates[index]) { 345 case INTERFACE_EXPOSED: 346 case INTERFACE_ADDED: 347 interface = (char *) this + class__->mInterfaces[index].mOffset; 348 // Note that interface has been gotten, 349 // for debugger and to detect incorrect use of interfaces 350 if (!(this->mGottenMask & mask)) { 351 this->mGottenMask |= mask; 352 ((size_t *) interface)[0] ^= ~0; 353 } 354 result = SL_RESULT_SUCCESS; 355 break; 356 // Can't get interface if uninitialized/suspend(ed,ing)/resuming/adding/removing 357 default: 358 result = SL_RESULT_FEATURE_UNSUPPORTED; 359 break; 360 } 361 } 362 object_unlock_exclusive(this); 363 } 364 } 365 *(void **)pInterface = interface; 366 } 367 368 SL_LEAVE_INTERFACE 369} 370 371 372static SLresult IObject_RegisterCallback(SLObjectItf self, 373 slObjectCallback callback, void *pContext) 374{ 375 SL_ENTER_INTERFACE 376 377 IObject *this = (IObject *) self; 378 object_lock_exclusive(this); 379 this->mCallback = callback; 380 this->mContext = pContext; 381 object_unlock_exclusive(this); 382 result = SL_RESULT_SUCCESS; 383 384 SL_LEAVE_INTERFACE 385} 386 387 388/** \brief This is internal common code for Abort and Destroy. 389 * Note: called with mutex unlocked, and returns with mutex locked. 390 */ 391 392static void Abort_internal(IObject *this) 393{ 394 const ClassTable *class__ = this->mClass; 395 bool anyAsync = false; 396 object_lock_exclusive(this); 397 398 // Abort asynchronous operations on the object 399 switch (this->mState) { 400 case SL_OBJECT_STATE_REALIZING_1: // Realize 401 this->mState = SL_OBJECT_STATE_REALIZING_1A; 402 anyAsync = true; 403 break; 404 case SL_OBJECT_STATE_RESUMING_1: // Resume 405 this->mState = SL_OBJECT_STATE_RESUMING_1A; 406 anyAsync = true; 407 break; 408 case SL_OBJECT_STATE_REALIZING_1A: // Realize 409 case SL_OBJECT_STATE_REALIZING_2: 410 case SL_OBJECT_STATE_RESUMING_1A: // Resume 411 case SL_OBJECT_STATE_RESUMING_2: 412 anyAsync = true; 413 break; 414 case SL_OBJECT_STATE_DESTROYING: 415 assert(false); 416 break; 417 default: 418 break; 419 } 420 421 // Abort asynchronous operations on interfaces 422 SLuint8 *interfaceStateP = this->mInterfaceStates; 423 unsigned index; 424 for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) { 425 switch (*interfaceStateP) { 426 case INTERFACE_ADDING_1: // AddInterface 427 *interfaceStateP = INTERFACE_ADDING_1A; 428 anyAsync = true; 429 break; 430 case INTERFACE_RESUMING_1: // ResumeInterface 431 *interfaceStateP = INTERFACE_RESUMING_1A; 432 anyAsync = true; 433 break; 434 case INTERFACE_ADDING_1A: // AddInterface 435 case INTERFACE_ADDING_2: 436 case INTERFACE_RESUMING_1A: // ResumeInterface 437 case INTERFACE_RESUMING_2: 438 case INTERFACE_REMOVING: // RemoveInterface is sync, but partially without a mutex lock 439 anyAsync = true; 440 break; 441 default: 442 break; 443 } 444 } 445 446 // Wait until all asynchronous operations either complete normally or recognize the abort 447 while (anyAsync) { 448 object_unlock_exclusive(this); 449 // FIXME should use condition variable instead of polling 450 usleep(20000); 451 anyAsync = false; 452 object_lock_exclusive(this); 453 switch (this->mState) { 454 case SL_OBJECT_STATE_REALIZING_1: // state 1 means it cycled during the usleep window 455 case SL_OBJECT_STATE_RESUMING_1: 456 case SL_OBJECT_STATE_REALIZING_1A: 457 case SL_OBJECT_STATE_REALIZING_2: 458 case SL_OBJECT_STATE_RESUMING_1A: 459 case SL_OBJECT_STATE_RESUMING_2: 460 anyAsync = true; 461 break; 462 case SL_OBJECT_STATE_DESTROYING: 463 assert(false); 464 break; 465 default: 466 break; 467 } 468 interfaceStateP = this->mInterfaceStates; 469 for (index = 0; index < class__->mInterfaceCount; ++index, ++interfaceStateP) { 470 switch (*interfaceStateP) { 471 case INTERFACE_ADDING_1: // state 1 means it cycled during the usleep window 472 case INTERFACE_RESUMING_1: 473 case INTERFACE_ADDING_1A: 474 case INTERFACE_ADDING_2: 475 case INTERFACE_RESUMING_1A: 476 case INTERFACE_RESUMING_2: 477 case INTERFACE_REMOVING: 478 anyAsync = true; 479 break; 480 default: 481 break; 482 } 483 } 484 } 485 486 // At this point there are no pending asynchronous operations 487} 488 489 490static void IObject_AbortAsyncOperation(SLObjectItf self) 491{ 492 SL_ENTER_INTERFACE_VOID 493 494 IObject *this = (IObject *) self; 495 Abort_internal(this); 496 object_unlock_exclusive(this); 497 498 SL_LEAVE_INTERFACE_VOID 499} 500 501 502void IObject_Destroy(SLObjectItf self) 503{ 504 SL_ENTER_INTERFACE_VOID 505 506 IObject *this = (IObject *) self; 507 // mutex is unlocked 508 Abort_internal(this); 509 // mutex is locked 510 const ClassTable *class__ = this->mClass; 511 BoolHook preDestroy = class__->mPreDestroy; 512 // The pre-destroy hook is called with mutex locked, and should block until it is safe to 513 // destroy. It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex 514 // before returning. 515 if (NULL != preDestroy) { 516 bool okToDestroy = (*preDestroy)(this); 517 if (!okToDestroy) { 518 object_unlock_exclusive(this); 519 // unfortunately Destroy doesn't return a result 520 SL_LOGE("Object::Destroy(%p) not allowed", this); 521 SL_LEAVE_INTERFACE_VOID 522 } 523 } 524 this->mState = SL_OBJECT_STATE_DESTROYING; 525 VoidHook destroy = class__->mDestroy; 526 // const, no lock needed 527 IEngine *thisEngine = this->mEngine; 528 unsigned i = this->mInstanceID; 529 assert(MAX_INSTANCE >= i); 530 // avoid a recursive lock on the engine when destroying the engine itself 531 if (thisEngine->mThis != this) { 532 interface_lock_exclusive(thisEngine); 533 } 534 // An unpublished object has a slot reserved, but the ID hasn't been chosen yet 535 assert(0 < thisEngine->mInstanceCount); 536 --thisEngine->mInstanceCount; 537 // If object is published, then remove it from exposure to sync thread and debugger 538 if (0 != i) { 539 --i; 540 assert(0 != thisEngine->mInstanceMask); 541 thisEngine->mInstanceMask &= ~(1 << i); 542 assert(thisEngine->mInstances[i] == this); 543 thisEngine->mInstances[i] = NULL; 544 } 545 // avoid a recursive unlock on the engine when destroying the engine itself 546 if (thisEngine->mThis != this) { 547 interface_unlock_exclusive(thisEngine); 548 } 549 // The destroy hook is called with mutex locked 550 if (NULL != destroy) { 551 (*destroy)(this); 552 } 553 // Call the deinitializer for each currently exposed interface, 554 // whether it is implicit, explicit, optional, or dynamically added. 555 // The deinitializers are called in the reverse order that the 556 // initializers were called, so that IObject_deinit is called last. 557 unsigned incorrect = 0; 558 unsigned index = class__->mInterfaceCount; 559 const struct iid_vtable *x = &class__->mInterfaces[index]; 560 SLuint8 *interfaceStateP = &this->mInterfaceStates[index]; 561 for ( ; index > 0; --index) { 562 --x; 563 SLuint32 state = *--interfaceStateP; 564 switch (state) { 565 case INTERFACE_UNINITIALIZED: 566 break; 567 case INTERFACE_EXPOSED: // quiescent states 568 case INTERFACE_ADDED: 569 case INTERFACE_SUSPENDED: 570 { 571 VoidHook deinit = MPH_init_table[x->mMPH].mDeinit; 572 if (NULL != deinit) { 573 (*deinit)((char *) this + x->mOffset); 574 } 575 } 576 break; 577 case INTERFACE_ADDING_1: // active states indicate incorrect use of API 578 case INTERFACE_ADDING_1A: 579 case INTERFACE_ADDING_2: 580 case INTERFACE_RESUMING_1: 581 case INTERFACE_RESUMING_1A: 582 case INTERFACE_RESUMING_2: 583 case INTERFACE_REMOVING: 584 case INTERFACE_SUSPENDING: 585 ++incorrect; 586 break; 587 default: 588 assert(SL_BOOLEAN_FALSE); 589 break; 590 } 591 } 592 // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer 593#ifdef USE_DEBUG 594 memset(this, 0x55, class__->mSize); 595#endif 596 free(this); 597 // one or more interfaces was actively changing at time of Destroy 598 assert(incorrect == 0); 599 600 SL_LEAVE_INTERFACE_VOID 601} 602 603 604static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable) 605{ 606 SL_ENTER_INTERFACE 607 608#if USE_PROFILES & USE_PROFILES_BASE 609 IObject *this = (IObject *) self; 610 object_lock_exclusive(this); 611 this->mPriority = priority; 612 this->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize 613 object_unlock_exclusive(this); 614 result = SL_RESULT_SUCCESS; 615#else 616 result = SL_RESULT_FEATURE_UNSUPPORTED; 617#endif 618 619 SL_LEAVE_INTERFACE 620} 621 622 623static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable) 624{ 625 SL_ENTER_INTERFACE 626 627#if USE_PROFILES & USE_PROFILES_BASE 628 if (NULL == pPriority || NULL == pPreemptable) { 629 result = SL_RESULT_PARAMETER_INVALID; 630 } else { 631 IObject *this = (IObject *) self; 632 object_lock_shared(this); 633 SLint32 priority = this->mPriority; 634 SLboolean preemptable = this->mPreemptable; 635 object_unlock_shared(this); 636 *pPriority = priority; 637 *pPreemptable = preemptable; 638 result = SL_RESULT_SUCCESS; 639 } 640#else 641 result = SL_RESULT_FEATURE_UNSUPPORTED; 642#endif 643 644 SL_LEAVE_INTERFACE 645} 646 647 648static SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self, 649 SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled) 650{ 651 SL_ENTER_INTERFACE 652 653#if USE_PROFILES & USE_PROFILES_BASE 654 result = SL_RESULT_SUCCESS; 655 if (0 < numInterfaces) { 656 SLuint32 i; 657 if (NULL == pInterfaceIDs) { 658 result = SL_RESULT_PARAMETER_INVALID; 659 } else { 660 IObject *this = (IObject *) self; 661 const ClassTable *class__ = this->mClass; 662 unsigned lossOfControlMask = 0; 663 // The cast is due to a typo in the spec, bug 6482 664 for (i = 0; i < (SLuint32) numInterfaces; ++i) { 665 SLInterfaceID iid = pInterfaceIDs[i]; 666 if (NULL == iid) { 667 result = SL_RESULT_PARAMETER_INVALID; 668 goto out; 669 } 670 int MPH, index; 671 // We ignore without error any invalid MPH or index, but spec is unclear 672 if ((0 <= (MPH = IID_to_MPH(iid))) && 673 // no need to check for an initialization hook 674 // (NULL == MPH_init_table[MPH].mInit) || 675 (0 <= (index = class__->mMPH_to_index[MPH]))) { 676 lossOfControlMask |= (1 << index); 677 } 678 } 679 object_lock_exclusive(this); 680 if (enabled) { 681 this->mLossOfControlMask |= lossOfControlMask; 682 } else { 683 this->mLossOfControlMask &= ~lossOfControlMask; 684 } 685 object_unlock_exclusive(this); 686 } 687 } 688out: 689#else 690 result = SL_RESULT_FEATURE_UNSUPPORTED; 691#endif 692 693 SL_LEAVE_INTERFACE 694} 695 696 697static const struct SLObjectItf_ IObject_Itf = { 698 IObject_Realize, 699 IObject_Resume, 700 IObject_GetState, 701 IObject_GetInterface, 702 IObject_RegisterCallback, 703 IObject_AbortAsyncOperation, 704 IObject_Destroy, 705 IObject_SetPriority, 706 IObject_GetPriority, 707 IObject_SetLossOfControlInterfaces, 708}; 709 710 711/** \brief This must be the first initializer called for an object */ 712 713void IObject_init(void *self) 714{ 715 IObject *this = (IObject *) self; 716 this->mItf = &IObject_Itf; 717 // initialized in construct: 718 // mClass 719 // mInstanceID 720 // mLossOfControlMask 721 // mEngine 722 // mInstanceStates 723 this->mState = SL_OBJECT_STATE_UNREALIZED; 724 this->mGottenMask = 1; // IObject 725 this->mAttributesMask = 0; 726 this->mCallback = NULL; 727 this->mContext = NULL; 728#if USE_PROFILES & USE_PROFILES_BASE 729 this->mPriority = SL_PRIORITY_NORMAL; 730 this->mPreemptable = SL_BOOLEAN_FALSE; 731#endif 732 this->mStrongRefCount = 0; 733 int ok; 734 ok = pthread_mutex_init(&this->mMutex, (const pthread_mutexattr_t *) NULL); 735 assert(0 == ok); 736#ifdef USE_DEBUG 737 memset(&this->mOwner, 0, sizeof(pthread_t)); 738 this->mFile = NULL; 739 this->mLine = 0; 740#endif 741 ok = pthread_cond_init(&this->mCond, (const pthread_condattr_t *) NULL); 742 assert(0 == ok); 743} 744 745 746/** \brief This must be the last deinitializer called for an object */ 747 748void IObject_deinit(void *self) 749{ 750 IObject *this = (IObject *) self; 751#ifdef USE_DEBUG 752 assert(pthread_equal(pthread_self(), this->mOwner)); 753#endif 754 int ok; 755 ok = pthread_cond_destroy(&this->mCond); 756 assert(0 == ok); 757 // equivalent to object_unlock_exclusive, but without the rigmarole 758 ok = pthread_mutex_unlock(&this->mMutex); 759 assert(0 == ok); 760 ok = pthread_mutex_destroy(&this->mMutex); 761 assert(0 == ok); 762 // redundant: this->mState = SL_OBJECT_STATE_UNREALIZED; 763} 764 765 766/** \brief Publish a new object after it is fully initialized. 767 * Publishing will expose the object to sync thread and debugger, 768 * and make it safe to return the SLObjectItf to the application. 769 */ 770 771void IObject_Publish(IObject *this) 772{ 773 IEngine *thisEngine = this->mEngine; 774 interface_lock_exclusive(thisEngine); 775 // construct earlier reserved a pending slot, but did not choose the actual slot number 776 unsigned availMask = ~thisEngine->mInstanceMask; 777 assert(availMask); 778 unsigned i = ctz(availMask); 779 assert(MAX_INSTANCE > i); 780 assert(NULL == thisEngine->mInstances[i]); 781 thisEngine->mInstances[i] = this; 782 thisEngine->mInstanceMask |= 1 << i; 783 // avoid zero as a valid instance ID 784 this->mInstanceID = i + 1; 785 interface_unlock_exclusive(thisEngine); 786} 787