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 25 static 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 // Note that the mutex is locked on entry to and exit from the realize hook, 46 // but the hook is permitted to temporarily unlock the mutex (e.g. for async). 47 result = (*realize)(thiz, SL_BOOLEAN_TRUE); 48 assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState); 49 state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 50 SL_OBJECT_STATE_UNREALIZED; 51 } else { 52 result = SL_RESULT_SUCCESS; 53 state = SL_OBJECT_STATE_REALIZED; 54 } 55 break; 56 57 case SL_OBJECT_STATE_REALIZING_1A: // operation was aborted while on work queue 58 result = SL_RESULT_OPERATION_ABORTED; 59 state = SL_OBJECT_STATE_UNREALIZED; 60 break; 61 62 default: // impossible 63 assert(SL_BOOLEAN_FALSE); 64 result = SL_RESULT_INTERNAL_ERROR; 65 break; 66 67 } 68 69 // mutex is locked, update state 70 thiz->mState = state; 71 72 // Make a copy of these, so we can call the callback with mutex unlocked 73 slObjectCallback callback = thiz->mCallback; 74 void *context = thiz->mContext; 75 object_unlock_exclusive(thiz); 76 77 // Note that the mutex is unlocked during the callback 78 if (NULL != callback) { 79 (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 80 } 81 } 82 83 84 static SLresult IObject_Realize(SLObjectItf self, SLboolean async) 85 { 86 SL_ENTER_INTERFACE 87 88 IObject *thiz = (IObject *) self; 89 SLuint8 state; 90 const ClassTable *clazz = thiz->mClass; 91 bool isSharedEngine = false; 92 object_lock_exclusive(thiz); 93 // note that SL_OBJECTID_ENGINE and XA_OBJECTID_ENGINE map to same class 94 if (clazz == objectIDtoClass(SL_OBJECTID_ENGINE)) { 95 // important: the lock order is engine followed by theOneTrueMutex 96 int ok = pthread_mutex_lock(&theOneTrueMutex); 97 assert(0 == ok); 98 isSharedEngine = 1 < theOneTrueRefCount; 99 ok = pthread_mutex_unlock(&theOneTrueMutex); 100 assert(0 == ok); 101 } 102 state = thiz->mState; 103 // Reject redundant calls to Realize, except on a shared engine 104 if (SL_OBJECT_STATE_UNREALIZED != state) { 105 object_unlock_exclusive(thiz); 106 // redundant realize on the shared engine is permitted 107 if (isSharedEngine && (SL_OBJECT_STATE_REALIZED == state)) { 108 result = SL_RESULT_SUCCESS; 109 } else { 110 result = SL_RESULT_PRECONDITIONS_VIOLATED; 111 } 112 } else { 113 // Asynchronous: mark operation pending and cancellable 114 if (async && (SL_OBJECTID_ENGINE != clazz->mSLObjectID)) { 115 state = SL_OBJECT_STATE_REALIZING_1; 116 // Synchronous: mark operation pending and non-cancellable 117 } else { 118 state = SL_OBJECT_STATE_REALIZING_2; 119 } 120 thiz->mState = state; 121 switch (state) { 122 case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine 123 object_unlock_exclusive(thiz); 124 assert(async); 125 result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleRealize, thiz, NULL, 0); 126 if (SL_RESULT_SUCCESS != result) { 127 // Engine was destroyed during realize, or insufficient memory 128 object_lock_exclusive(thiz); 129 thiz->mState = SL_OBJECT_STATE_UNREALIZED; 130 object_unlock_exclusive(thiz); 131 } 132 break; 133 case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine 134 { 135 AsyncHook realize = clazz->mRealize; 136 // Note that the mutex is locked on entry to and exit from the realize hook, 137 // but the hook is permitted to temporarily unlock the mutex (e.g. for async). 138 result = (NULL != realize) ? (*realize)(thiz, async) : SL_RESULT_SUCCESS; 139 assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState); 140 state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 141 SL_OBJECT_STATE_UNREALIZED; 142 thiz->mState = state; 143 slObjectCallback callback = thiz->mCallback; 144 void *context = thiz->mContext; 145 object_unlock_exclusive(thiz); 146 // asynchronous Realize on an Engine is actually done synchronously, but still has 147 // callback because there is no thread pool yet to do it asynchronously. 148 if (async && (NULL != callback)) { 149 (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, 150 NULL); 151 } 152 } 153 break; 154 default: // impossible 155 object_unlock_exclusive(thiz); 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 168 static 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 // Note that the mutex is locked on entry to and exit from the resume hook, 189 // but the hook is permitted to temporarily unlock the mutex (e.g. for async). 190 result = (*resume)(thiz, SL_BOOLEAN_TRUE); 191 assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState); 192 state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 193 SL_OBJECT_STATE_SUSPENDED; 194 } else { 195 result = SL_RESULT_SUCCESS; 196 state = SL_OBJECT_STATE_REALIZED; 197 } 198 break; 199 200 case SL_OBJECT_STATE_RESUMING_1A: // operation was aborted while on work queue 201 result = SL_RESULT_OPERATION_ABORTED; 202 state = SL_OBJECT_STATE_SUSPENDED; 203 break; 204 205 default: // impossible 206 assert(SL_BOOLEAN_FALSE); 207 result = SL_RESULT_INTERNAL_ERROR; 208 break; 209 210 } 211 212 // mutex is unlocked, update state 213 thiz->mState = state; 214 215 // Make a copy of these, so we can call the callback with mutex unlocked 216 slObjectCallback callback = thiz->mCallback; 217 void *context = thiz->mContext; 218 object_unlock_exclusive(thiz); 219 220 // Note that the mutex is unlocked during the callback 221 if (NULL != callback) { 222 (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 223 } 224 } 225 226 227 static SLresult IObject_Resume(SLObjectItf self, SLboolean async) 228 { 229 SL_ENTER_INTERFACE 230 231 IObject *thiz = (IObject *) self; 232 const ClassTable *clazz = thiz->mClass; 233 SLuint8 state; 234 object_lock_exclusive(thiz); 235 state = thiz->mState; 236 // Reject redundant calls to Resume 237 if (SL_OBJECT_STATE_SUSPENDED != state) { 238 object_unlock_exclusive(thiz); 239 result = SL_RESULT_PRECONDITIONS_VIOLATED; 240 } else { 241 // Asynchronous: mark operation pending and cancellable 242 if (async) { 243 state = SL_OBJECT_STATE_RESUMING_1; 244 // Synchronous: mark operatio pending and non-cancellable 245 } else { 246 state = SL_OBJECT_STATE_RESUMING_2; 247 } 248 thiz->mState = state; 249 switch (state) { 250 case SL_OBJECT_STATE_RESUMING_1: // asynchronous 251 object_unlock_exclusive(thiz); 252 assert(async); 253 result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleResume, thiz, NULL, 0); 254 if (SL_RESULT_SUCCESS != result) { 255 // Engine was destroyed during resume, or insufficient memory 256 object_lock_exclusive(thiz); 257 thiz->mState = SL_OBJECT_STATE_SUSPENDED; 258 object_unlock_exclusive(thiz); 259 } 260 break; 261 case SL_OBJECT_STATE_RESUMING_2: // synchronous 262 { 263 AsyncHook resume = clazz->mResume; 264 // Note that the mutex is locked on entry to and exit from the resume hook, 265 // but the hook is permitted to temporarily unlock the mutex (e.g. for async). 266 result = (NULL != resume) ? (*resume)(thiz, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS; 267 assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState); 268 thiz->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 269 SL_OBJECT_STATE_SUSPENDED; 270 object_unlock_exclusive(thiz); 271 } 272 break; 273 default: // impossible 274 object_unlock_exclusive(thiz); 275 assert(SL_BOOLEAN_FALSE); 276 break; 277 } 278 } 279 280 SL_LEAVE_INTERFACE 281 } 282 283 284 static 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 325 static 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 387 static 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 407 static 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 505 static 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 517 void 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 642 static 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 661 static 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 686 static 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 } 726 out: 727 #else 728 result = SL_RESULT_FEATURE_UNSUPPORTED; 729 #endif 730 731 SL_LEAVE_INTERFACE 732 } 733 734 735 static 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 751 void 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 thiz->mGeneration = 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 787 void 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 810 void 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