IObject.c revision bcc5c7225e3b7a1dbf2e9e830987f69167acf06f
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 *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(&thiz->mEngine->mThreadPool, HandleRealize, thiz, 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, 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(&thiz->mEngine->mThreadPool, HandleResume, thiz, 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 // Note that the state is immediately obsolete, so a peek lock is safe 293 object_lock_peek(thiz); 294 SLuint8 state = thiz->mState; 295 object_unlock_peek(thiz); 296 // Re-map the realizing, resuming, and suspending states 297 switch (state) { 298 case SL_OBJECT_STATE_REALIZING_1: 299 case SL_OBJECT_STATE_REALIZING_1A: 300 case SL_OBJECT_STATE_REALIZING_2: 301 case SL_OBJECT_STATE_DESTROYING: // application shouldn't call GetState after Destroy 302 state = SL_OBJECT_STATE_UNREALIZED; 303 break; 304 case SL_OBJECT_STATE_RESUMING_1: 305 case SL_OBJECT_STATE_RESUMING_1A: 306 case SL_OBJECT_STATE_RESUMING_2: 307 case SL_OBJECT_STATE_SUSPENDING: 308 state = SL_OBJECT_STATE_SUSPENDED; 309 break; 310 case SL_OBJECT_STATE_UNREALIZED: 311 case SL_OBJECT_STATE_REALIZED: 312 case SL_OBJECT_STATE_SUSPENDED: 313 // These are the "official" object states, return them as is 314 break; 315 default: 316 assert(SL_BOOLEAN_FALSE); 317 break; 318 } 319 *pState = state; 320 result = SL_RESULT_SUCCESS; 321 } 322 323 SL_LEAVE_INTERFACE 324} 325 326static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface) 327{ 328 SL_ENTER_INTERFACE 329 330 if (NULL == pInterface) { 331 result = SL_RESULT_PARAMETER_INVALID; 332 } else { 333 void *interface = NULL; 334 if (NULL == iid) { 335 result = SL_RESULT_PARAMETER_INVALID; 336 } else { 337 IObject *thiz = (IObject *) self; 338 const ClassTable *clazz = thiz->mClass; 339 int MPH, index; 340 if ((0 > (MPH = IID_to_MPH(iid))) || 341 // no need to check for an initialization hook 342 // (NULL == MPH_init_table[MPH].mInit) || 343 (0 > (index = clazz->mMPH_to_index[MPH]))) { 344 result = SL_RESULT_FEATURE_UNSUPPORTED; 345 } else { 346 unsigned mask = 1 << index; 347 object_lock_exclusive(thiz); 348 if ((SL_OBJECT_STATE_REALIZED != thiz->mState) && 349 !(INTERFACE_PREREALIZE & clazz->mInterfaces[index].mInterface)) { 350 // Can't get interface on an unrealized object unless pre-realize is ok 351 result = SL_RESULT_PRECONDITIONS_VIOLATED; 352 } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER == 353 clazz->mSLObjectID) && (1 == ((CAudioPlayer *) thiz)->mNumChannels)) { 354 // Can't get the MuteSolo interface of an audio player if the channel count is 355 // mono, but _can_ get the MuteSolo interface if the channel count is unknown 356 result = SL_RESULT_FEATURE_UNSUPPORTED; 357 } else { 358 switch (thiz->mInterfaceStates[index]) { 359 case INTERFACE_EXPOSED: 360 case INTERFACE_ADDED: 361 interface = (char *) thiz + clazz->mInterfaces[index].mOffset; 362 // Note that interface has been gotten, 363 // for debugger and to detect incorrect use of interfaces 364 if (!(thiz->mGottenMask & mask)) { 365 thiz->mGottenMask |= mask; 366 // This trickery validates the v-table 367 ((size_t *) interface)[0] ^= ~0; 368 } 369 result = SL_RESULT_SUCCESS; 370 break; 371 // Can't get interface if uninitialized, initialized, suspended, 372 // suspending, resuming, adding, or removing 373 default: 374 result = SL_RESULT_FEATURE_UNSUPPORTED; 375 break; 376 } 377 } 378 object_unlock_exclusive(thiz); 379 } 380 } 381 *(void **)pInterface = interface; 382 } 383 384 SL_LEAVE_INTERFACE 385} 386 387 388static SLresult IObject_RegisterCallback(SLObjectItf self, 389 slObjectCallback callback, void *pContext) 390{ 391 SL_ENTER_INTERFACE 392 393 IObject *thiz = (IObject *) self; 394 object_lock_exclusive(thiz); 395 thiz->mCallback = callback; 396 thiz->mContext = pContext; 397 object_unlock_exclusive(thiz); 398 result = SL_RESULT_SUCCESS; 399 400 SL_LEAVE_INTERFACE 401} 402 403 404/** \brief This is internal common code for Abort and Destroy. 405 * Note: called with mutex unlocked, and returns with mutex locked. 406 */ 407 408static void Abort_internal(IObject *thiz) 409{ 410 const ClassTable *clazz = thiz->mClass; 411 bool anyAsync = false; 412 object_lock_exclusive(thiz); 413 414 // Abort asynchronous operations on the object 415 switch (thiz->mState) { 416 case SL_OBJECT_STATE_REALIZING_1: // Realize 417 thiz->mState = SL_OBJECT_STATE_REALIZING_1A; 418 anyAsync = true; 419 break; 420 case SL_OBJECT_STATE_RESUMING_1: // Resume 421 thiz->mState = SL_OBJECT_STATE_RESUMING_1A; 422 anyAsync = true; 423 break; 424 case SL_OBJECT_STATE_REALIZING_1A: // Realize 425 case SL_OBJECT_STATE_REALIZING_2: 426 case SL_OBJECT_STATE_RESUMING_1A: // Resume 427 case SL_OBJECT_STATE_RESUMING_2: 428 anyAsync = true; 429 break; 430 case SL_OBJECT_STATE_DESTROYING: 431 assert(false); 432 break; 433 default: 434 break; 435 } 436 437 // Abort asynchronous operations on interfaces 438 SLuint8 *interfaceStateP = thiz->mInterfaceStates; 439 unsigned index; 440 for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) { 441 switch (*interfaceStateP) { 442 case INTERFACE_ADDING_1: // AddInterface 443 *interfaceStateP = INTERFACE_ADDING_1A; 444 anyAsync = true; 445 break; 446 case INTERFACE_RESUMING_1: // ResumeInterface 447 *interfaceStateP = INTERFACE_RESUMING_1A; 448 anyAsync = true; 449 break; 450 case INTERFACE_ADDING_1A: // AddInterface 451 case INTERFACE_ADDING_2: 452 case INTERFACE_RESUMING_1A: // ResumeInterface 453 case INTERFACE_RESUMING_2: 454 case INTERFACE_REMOVING: // not observable: RemoveInterface is synchronous & mutex locked 455 anyAsync = true; 456 break; 457 default: 458 break; 459 } 460 } 461 462 // Wait until all asynchronous operations either complete normally or recognize the abort 463 while (anyAsync) { 464 object_unlock_exclusive(thiz); 465 // FIXME should use condition variable instead of polling 466 usleep(20000); 467 anyAsync = false; 468 object_lock_exclusive(thiz); 469 switch (thiz->mState) { 470 case SL_OBJECT_STATE_REALIZING_1: // state 1 means it cycled during the usleep window 471 case SL_OBJECT_STATE_RESUMING_1: 472 case SL_OBJECT_STATE_REALIZING_1A: 473 case SL_OBJECT_STATE_REALIZING_2: 474 case SL_OBJECT_STATE_RESUMING_1A: 475 case SL_OBJECT_STATE_RESUMING_2: 476 anyAsync = true; 477 break; 478 case SL_OBJECT_STATE_DESTROYING: 479 assert(false); 480 break; 481 default: 482 break; 483 } 484 interfaceStateP = thiz->mInterfaceStates; 485 for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) { 486 switch (*interfaceStateP) { 487 case INTERFACE_ADDING_1: // state 1 means it cycled during the usleep window 488 case INTERFACE_RESUMING_1: 489 case INTERFACE_ADDING_1A: 490 case INTERFACE_ADDING_2: 491 case INTERFACE_RESUMING_1A: 492 case INTERFACE_RESUMING_2: 493 case INTERFACE_REMOVING: 494 anyAsync = true; 495 break; 496 default: 497 break; 498 } 499 } 500 } 501 502 // At this point there are no pending asynchronous operations 503} 504 505 506static void IObject_AbortAsyncOperation(SLObjectItf self) 507{ 508 SL_ENTER_INTERFACE_VOID 509 510 IObject *thiz = (IObject *) self; 511 Abort_internal(thiz); 512 object_unlock_exclusive(thiz); 513 514 SL_LEAVE_INTERFACE_VOID 515} 516 517 518void IObject_Destroy(SLObjectItf self) 519{ 520 SL_ENTER_INTERFACE_VOID 521 522 IObject *thiz = (IObject *) self; 523 // mutex is unlocked 524 Abort_internal(thiz); 525 // mutex is locked 526 const ClassTable *clazz = thiz->mClass; 527 PreDestroyHook preDestroy = clazz->mPreDestroy; 528 // The pre-destroy hook is called with mutex locked, and should block until it is safe to 529 // destroy. It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex 530 // before returning. 531 if (NULL != preDestroy) { 532 predestroy_t okToDestroy = (*preDestroy)(thiz); 533 switch (okToDestroy) { 534 case predestroy_ok: 535 break; 536 case predestroy_error: 537 SL_LOGE("Object::Destroy(%p) not allowed", thiz); 538 // fall through 539 case predestroy_again: 540 object_unlock_exclusive(thiz); 541 // unfortunately Destroy doesn't return a result 542 SL_LEAVE_INTERFACE_VOID 543 // unreachable 544 default: 545 assert(false); 546 break; 547 } 548 } 549 thiz->mState = SL_OBJECT_STATE_DESTROYING; 550 VoidHook destroy = clazz->mDestroy; 551 // const, no lock needed 552 IEngine *thisEngine = &thiz->mEngine->mEngine; 553 unsigned i = thiz->mInstanceID; 554 assert(MAX_INSTANCE >= i); 555 // avoid a recursive lock on the engine when destroying the engine itself 556 if (thisEngine->mThis != thiz) { 557 interface_lock_exclusive(thisEngine); 558 } 559 // An unpublished object has a slot reserved, but the ID hasn't been chosen yet 560 assert(0 < thisEngine->mInstanceCount); 561 --thisEngine->mInstanceCount; 562 // If object is published, then remove it from exposure to sync thread and debugger 563 if (0 != i) { 564 --i; 565 unsigned mask = 1 << i; 566 assert(thisEngine->mInstanceMask & mask); 567 thisEngine->mInstanceMask &= ~mask; 568 assert(thisEngine->mInstances[i] == thiz); 569 thisEngine->mInstances[i] = NULL; 570 } 571 // avoid a recursive unlock on the engine when destroying the engine itself 572 if (thisEngine->mThis != thiz) { 573 interface_unlock_exclusive(thisEngine); 574 } 575 // The destroy hook is called with mutex locked 576 if (NULL != destroy) { 577 (*destroy)(thiz); 578 } 579 // Call the deinitializer for each currently initialized interface, 580 // whether it is implicit, explicit, optional, or dynamically added. 581 // The deinitializers are called in the reverse order that the 582 // initializers were called, so that IObject_deinit is called last. 583 unsigned index = clazz->mInterfaceCount; 584 const struct iid_vtable *x = &clazz->mInterfaces[index]; 585 SLuint8 *interfaceStateP = &thiz->mInterfaceStates[index]; 586 for ( ; index > 0; --index) { 587 --x; 588 size_t offset = x->mOffset; 589 void *thisItf = (char *) thiz + offset; 590 SLuint32 state = *--interfaceStateP; 591 switch (state) { 592 case INTERFACE_UNINITIALIZED: 593 break; 594 case INTERFACE_EXPOSED: // quiescent states 595 case INTERFACE_ADDED: 596 case INTERFACE_SUSPENDED: 597 // The remove hook is called with mutex locked 598 { 599 VoidHook remove = MPH_init_table[x->mMPH].mRemove; 600 if (NULL != remove) { 601 (*remove)(thisItf); 602 } 603 *interfaceStateP = INTERFACE_INITIALIZED; 604 } 605 // fall through 606 case INTERFACE_INITIALIZED: 607 { 608 VoidHook deinit = MPH_init_table[x->mMPH].mDeinit; 609 if (NULL != deinit) { 610 (*deinit)(thisItf); 611 } 612 *interfaceStateP = INTERFACE_UNINITIALIZED; 613 } 614 break; 615 case INTERFACE_ADDING_1: // active states indicate incorrect use of API 616 case INTERFACE_ADDING_1A: 617 case INTERFACE_ADDING_2: 618 case INTERFACE_RESUMING_1: 619 case INTERFACE_RESUMING_1A: 620 case INTERFACE_RESUMING_2: 621 case INTERFACE_REMOVING: 622 case INTERFACE_SUSPENDING: 623 SL_LOGE("Object::Destroy(%p) while interface %u active", thiz, index); 624 break; 625 default: 626 assert(SL_BOOLEAN_FALSE); 627 break; 628 } 629 } 630 // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer 631 memset(thiz, 0x55, clazz->mSize); // catch broken applications that continue using interfaces 632 // was ifdef USE_DEBUG but safer to do this unconditionally 633 free(thiz); 634 635 if (SL_OBJECTID_ENGINE == clazz->mSLObjectID) { 636 CEngine_Destroyed((CEngine *) thiz); 637 } 638 639 SL_LEAVE_INTERFACE_VOID 640} 641 642 643static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable) 644{ 645 SL_ENTER_INTERFACE 646 647#if USE_PROFILES & USE_PROFILES_BASE 648 IObject *thiz = (IObject *) self; 649 object_lock_exclusive(thiz); 650 thiz->mPriority = priority; 651 thiz->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize 652 object_unlock_exclusive(thiz); 653 result = SL_RESULT_SUCCESS; 654#else 655 result = SL_RESULT_FEATURE_UNSUPPORTED; 656#endif 657 658 SL_LEAVE_INTERFACE 659} 660 661 662static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable) 663{ 664 SL_ENTER_INTERFACE 665 666#if USE_PROFILES & USE_PROFILES_BASE 667 if (NULL == pPriority || NULL == pPreemptable) { 668 result = SL_RESULT_PARAMETER_INVALID; 669 } else { 670 IObject *thiz = (IObject *) self; 671 object_lock_shared(thiz); 672 SLint32 priority = thiz->mPriority; 673 SLboolean preemptable = thiz->mPreemptable; 674 object_unlock_shared(thiz); 675 *pPriority = priority; 676 *pPreemptable = preemptable; 677 result = SL_RESULT_SUCCESS; 678 } 679#else 680 result = SL_RESULT_FEATURE_UNSUPPORTED; 681#endif 682 683 SL_LEAVE_INTERFACE 684} 685 686 687static SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self, 688 SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled) 689{ 690 SL_ENTER_INTERFACE 691 692#if USE_PROFILES & USE_PROFILES_BASE 693 result = SL_RESULT_SUCCESS; 694 if (0 < numInterfaces) { 695 SLuint32 i; 696 if (NULL == pInterfaceIDs) { 697 result = SL_RESULT_PARAMETER_INVALID; 698 } else { 699 IObject *thiz = (IObject *) self; 700 const ClassTable *clazz = thiz->mClass; 701 unsigned lossOfControlMask = 0; 702 // The cast is due to a typo in the spec, bug 6482 703 for (i = 0; i < (SLuint32) numInterfaces; ++i) { 704 SLInterfaceID iid = pInterfaceIDs[i]; 705 if (NULL == iid) { 706 result = SL_RESULT_PARAMETER_INVALID; 707 goto out; 708 } 709 int MPH, index; 710 // We ignore without error any invalid MPH or index, but spec is unclear 711 if ((0 <= (MPH = IID_to_MPH(iid))) && 712 // no need to check for an initialization hook 713 // (NULL == MPH_init_table[MPH].mInit) || 714 (0 <= (index = clazz->mMPH_to_index[MPH]))) { 715 lossOfControlMask |= (1 << index); 716 } 717 } 718 object_lock_exclusive(thiz); 719 if (enabled) { 720 thiz->mLossOfControlMask |= lossOfControlMask; 721 } else { 722 thiz->mLossOfControlMask &= ~lossOfControlMask; 723 } 724 object_unlock_exclusive(thiz); 725 } 726 } 727out: 728#else 729 result = SL_RESULT_FEATURE_UNSUPPORTED; 730#endif 731 732 SL_LEAVE_INTERFACE 733} 734 735 736static const struct SLObjectItf_ IObject_Itf = { 737 IObject_Realize, 738 IObject_Resume, 739 IObject_GetState, 740 IObject_GetInterface, 741 IObject_RegisterCallback, 742 IObject_AbortAsyncOperation, 743 IObject_Destroy, 744 IObject_SetPriority, 745 IObject_GetPriority, 746 IObject_SetLossOfControlInterfaces, 747}; 748 749 750/** \brief This must be the first initializer called for an object */ 751 752void IObject_init(void *self) 753{ 754 IObject *thiz = (IObject *) self; 755 thiz->mItf = &IObject_Itf; 756 // initialized in construct: 757 // mClass 758 // mInstanceID 759 // mLossOfControlMask 760 // mEngine 761 // mInterfaceStates 762 thiz->mState = SL_OBJECT_STATE_UNREALIZED; 763 thiz->mGottenMask = 1; // IObject 764 thiz->mAttributesMask = 0; 765 thiz->mCallback = NULL; 766 thiz->mContext = NULL; 767#if USE_PROFILES & USE_PROFILES_BASE 768 thiz->mPriority = SL_PRIORITY_NORMAL; 769 thiz->mPreemptable = SL_BOOLEAN_FALSE; 770#endif 771 thiz->mStrongRefCount = 0; 772 int ok; 773 ok = pthread_mutex_init(&thiz->mMutex, (const pthread_mutexattr_t *) NULL); 774 assert(0 == ok); 775#ifdef USE_DEBUG 776 memset(&thiz->mOwner, 0, sizeof(pthread_t)); 777 thiz->mFile = NULL; 778 thiz->mLine = 0; 779#endif 780 ok = pthread_cond_init(&thiz->mCond, (const pthread_condattr_t *) NULL); 781 assert(0 == ok); 782} 783 784 785/** \brief This must be the last deinitializer called for an object */ 786 787void IObject_deinit(void *self) 788{ 789 IObject *thiz = (IObject *) self; 790#ifdef USE_DEBUG 791 assert(pthread_equal(pthread_self(), thiz->mOwner)); 792#endif 793 int ok; 794 ok = pthread_cond_destroy(&thiz->mCond); 795 assert(0 == ok); 796 // equivalent to object_unlock_exclusive, but without the rigmarole 797 ok = pthread_mutex_unlock(&thiz->mMutex); 798 assert(0 == ok); 799 ok = pthread_mutex_destroy(&thiz->mMutex); 800 assert(0 == ok); 801 // redundant: thiz->mState = SL_OBJECT_STATE_UNREALIZED; 802} 803 804 805/** \brief Publish a new object after it is fully initialized. 806 * Publishing will expose the object to sync thread and debugger, 807 * and make it safe to return the SLObjectItf to the application. 808 */ 809 810void IObject_Publish(IObject *thiz) 811{ 812 IEngine *thisEngine = &thiz->mEngine->mEngine; 813 interface_lock_exclusive(thisEngine); 814 // construct earlier reserved a pending slot, but did not choose the actual slot number 815 unsigned availMask = ~thisEngine->mInstanceMask; 816 assert(availMask); 817 unsigned i = ctz(availMask); 818 assert(MAX_INSTANCE > i); 819 assert(NULL == thisEngine->mInstances[i]); 820 thisEngine->mInstances[i] = thiz; 821 thisEngine->mInstanceMask |= 1 << i; 822 // avoid zero as a valid instance ID 823 thiz->mInstanceID = i + 1; 824 interface_unlock_exclusive(thisEngine); 825} 826