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