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