IObject.c revision cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0
161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/* 261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * 461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * you may not use this file except in compliance with the License. 661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * You may obtain a copy of the License at 761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * 861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * 1061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * Unless required by applicable law or agreed to in writing, software 1161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 1261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * See the License for the specific language governing permissions and 1461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten * limitations under the License. 1561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten */ 1661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 1761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten/* Object implementation */ 1861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 1961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten#include "sles_allinclusive.h" 2061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 21ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 22510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous Object.Realize. 23510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the Object. 24d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 25cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kastenstatic void HandleRealize(void *self, void *ignored, int unused) 2661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 27510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 28510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // validate input parameters 29bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 30bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(NULL != thiz); 31bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 32bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(NULL != clazz); 33bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten AsyncHook realize = clazz->mRealize; 343a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten SLresult result; 35276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten SLuint8 state; 36510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 37510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // check object state 38bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 39bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten state = thiz->mState; 40510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten switch (state) { 41510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 42510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case SL_OBJECT_STATE_REALIZING_1: // normal case 43510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (NULL != realize) { 44bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_REALIZING_2; 45bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 46510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Note that the mutex is unlocked during the realize hook 47bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten result = (*realize)(thiz, SL_BOOLEAN_TRUE); 48bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 49bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState); 50510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 51510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten SL_OBJECT_STATE_UNREALIZED; 52510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } else { 53510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = SL_RESULT_SUCCESS; 54510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten state = SL_OBJECT_STATE_REALIZED; 55510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 56510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 57510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 58510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case SL_OBJECT_STATE_REALIZING_1A: // operation was aborted while on work queue 59510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = SL_RESULT_OPERATION_ABORTED; 60510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten state = SL_OBJECT_STATE_UNREALIZED; 61510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 62510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 63510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten default: // impossible 64510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(SL_BOOLEAN_FALSE); 65510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = SL_RESULT_INTERNAL_ERROR; 66510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 67510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 6861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 69510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 70510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // mutex is locked, update state 71bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = state; 72510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 73d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten // Make a copy of these, so we can call the callback with mutex unlocked 74bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten slObjectCallback callback = thiz->mCallback; 75bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten void *context = thiz->mContext; 76bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 77510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 78d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten // Note that the mutex is unlocked during the callback 798c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (NULL != callback) { 80bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 818c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 82d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten} 83d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten 84ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 85d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IObject_Realize(SLObjectItf self, SLboolean async) 86d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{ 87ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 88ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 89bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 90276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten SLuint8 state; 91bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 921d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten bool isSharedEngine = false; 93bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 941d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten // note that SL_OBJECTID_ENGINE and XA_OBJECTID_ENGINE map to same class 95bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (clazz == objectIDtoClass(SL_OBJECTID_ENGINE)) { 961d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten // important: the lock order is engine followed by theOneTrueMutex 971d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten int ok = pthread_mutex_lock(&theOneTrueMutex); 981d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten assert(0 == ok); 991d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten isSharedEngine = 1 < theOneTrueRefCount; 1001d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten ok = pthread_mutex_unlock(&theOneTrueMutex); 1011d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten assert(0 == ok); 1021d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten } 103bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten state = thiz->mState; 1041d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten // Reject redundant calls to Realize, except on a shared engine 105d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (SL_OBJECT_STATE_UNREALIZED != state) { 106bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 1071d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten // redundant realize on the shared engine is permitted 1081d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten if (isSharedEngine && (SL_OBJECT_STATE_REALIZED == state)) { 1091d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten result = SL_RESULT_SUCCESS; 1101d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten } else { 1111d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten result = SL_RESULT_PRECONDITIONS_VIOLATED; 1121d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten } 113d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } else { 114ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Asynchronous: mark operation pending and cancellable 115bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (async && (SL_OBJECTID_ENGINE != clazz->mSLObjectID)) { 116ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = SL_OBJECT_STATE_REALIZING_1; 117ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Synchronous: mark operation pending and non-cancellable 118ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 119ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = SL_OBJECT_STATE_REALIZING_2; 120d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 121bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = state; 122bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 123ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten switch (state) { 124ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine 125ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten assert(async); 126cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleRealize, thiz, NULL, 0); 127ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (SL_RESULT_SUCCESS != result) { 128ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Engine was destroyed during realize, or insufficient memory 129bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 130bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_UNREALIZED; 131bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 132ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 133ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 134ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine 135ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten { 136bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten AsyncHook realize = clazz->mRealize; 137ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Note that the mutex is unlocked during the realize hook 138bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten result = (NULL != realize) ? (*realize)(thiz, async) : SL_RESULT_SUCCESS; 139bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 140bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState); 141ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 142ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_OBJECT_STATE_UNREALIZED; 143bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = state; 144bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten slObjectCallback callback = thiz->mCallback; 145bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten void *context = thiz->mContext; 146bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 147ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // asynchronous Realize on an Engine is actually done synchronously, but still has 148ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // callback because there is no thread pool yet to do it asynchronously. 1498c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (async && (NULL != callback)) { 150bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, 151ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten NULL); 152ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 1538c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 154ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 155ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten default: // impossible 156ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten assert(SL_BOOLEAN_FALSE); 157ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 158d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 159d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 160ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 161ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 16261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 16361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 164ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 165510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Called by a worker thread to handle an asynchronous Object.Resume. 166510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten// Parameter self is the Object. 167510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 168cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kastenstatic void HandleResume(void *self, void *ignored, int unused) 16961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 170510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 171510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // valid input parameters 172bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 173bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(NULL != thiz); 174bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 175bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(NULL != clazz); 176bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten AsyncHook resume = clazz->mResume; 1773a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten SLresult result; 178276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten SLuint8 state; 179510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 180510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // check object state 181bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 182bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten state = thiz->mState; 183510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten switch (state) { 184510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 185510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case SL_OBJECT_STATE_RESUMING_1: // normal case 186510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (NULL != resume) { 187bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_RESUMING_2; 188bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 189510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Note that the mutex is unlocked during the resume hook 190bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten result = (*resume)(thiz, SL_BOOLEAN_TRUE); 191bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 192bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState); 193510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED : 194510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten SL_OBJECT_STATE_SUSPENDED; 195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } else { 196510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = SL_RESULT_SUCCESS; 197510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten state = SL_OBJECT_STATE_REALIZED; 1983a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten } 199510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 200510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 201510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case SL_OBJECT_STATE_RESUMING_1A: // operation was aborted while on work queue 202510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = SL_RESULT_OPERATION_ABORTED; 203510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten state = SL_OBJECT_STATE_SUSPENDED; 204510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 205510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 206510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten default: // impossible 207510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(SL_BOOLEAN_FALSE); 208510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten result = SL_RESULT_INTERNAL_ERROR; 209510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 210510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 21161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 212510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 213510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // mutex is unlocked, update state 214bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = state; 215510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 216510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Make a copy of these, so we can call the callback with mutex unlocked 217bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten slObjectCallback callback = thiz->mCallback; 218bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten void *context = thiz->mContext; 219bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 220510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 221510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Note that the mutex is unlocked during the callback 2228c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (NULL != callback) { 223bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL); 2248c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 225510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten} 226510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 227ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 228510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic SLresult IObject_Resume(SLObjectItf self, SLboolean async) 229510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{ 230ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 231ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 232bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 233bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 234276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten SLuint8 state; 235bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 236bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten state = thiz->mState; 237510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Reject redundant calls to Resume 238510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten if (SL_OBJECT_STATE_SUSPENDED != state) { 239bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 240ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PRECONDITIONS_VIOLATED; 241510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } else { 242ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Asynchronous: mark operation pending and cancellable 243ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (async) { 244ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = SL_OBJECT_STATE_RESUMING_1; 245ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Synchronous: mark operatio pending and non-cancellable 246ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 247ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = SL_OBJECT_STATE_RESUMING_2; 248510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 249bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = state; 250bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 251ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten switch (state) { 252ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_RESUMING_1: // asynchronous 253ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten assert(async); 254cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleResume, thiz, NULL, 0); 255ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (SL_RESULT_SUCCESS != result) { 256ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Engine was destroyed during resume, or insufficient memory 257bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 258bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_SUSPENDED; 259bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 261ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 262ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_RESUMING_2: // synchronous 263ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten { 264bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten AsyncHook resume = clazz->mResume; 265ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Note that the mutex is unlocked during the resume hook 266bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten result = (NULL != resume) ? (*resume)(thiz, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS; 267bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 268bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState); 269bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED : 270ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_OBJECT_STATE_SUSPENDED; 271bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 272ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 273ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 274ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten default: // impossible 275ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten assert(SL_BOOLEAN_FALSE); 276ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 277510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 278510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 279ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 280ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 28161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 28261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 283ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 28461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState) 28561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 286ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 287ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 288ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (NULL == pState) { 289ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PARAMETER_INVALID; 290ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 291bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 292ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Note that the state is immediately obsolete, so a peek lock is safe 293bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_peek(thiz); 294bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SLuint8 state = thiz->mState; 295bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_peek(thiz); 296ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Re-map the realizing, resuming, and suspending states 297ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten switch (state) { 298ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_REALIZING_1: 299ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_REALIZING_1A: 300ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_REALIZING_2: 301928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_DESTROYING: // application shouldn't call GetState after Destroy 302ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = SL_OBJECT_STATE_UNREALIZED; 303ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 304ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_RESUMING_1: 305ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_RESUMING_1A: 306ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_RESUMING_2: 307ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_SUSPENDING: 308ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten state = SL_OBJECT_STATE_SUSPENDED; 309ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 310ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_UNREALIZED: 311ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_REALIZED: 312ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case SL_OBJECT_STATE_SUSPENDED: 313ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // These are the "official" object states, return them as is 314ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 315ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten default: 316ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten assert(SL_BOOLEAN_FALSE); 317ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 318ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 319ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten *pState = state; 320ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_SUCCESS; 321d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten } 322ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 323ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 32461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 32561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 3263a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface) 32761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 328ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 329ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 330ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (NULL == pInterface) { 33161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten result = SL_RESULT_PARAMETER_INVALID; 332ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 333ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten void *interface = NULL; 334ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (NULL == iid) { 335ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PARAMETER_INVALID; 336510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } else { 337bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 338bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 339ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten int MPH, index; 340a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten if ((0 > (MPH = IID_to_MPH(iid))) || 341a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // no need to check for an initialization hook 342a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // (NULL == MPH_init_table[MPH].mInit) || 343bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (0 > (index = clazz->mMPH_to_index[MPH]))) { 344ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_FEATURE_UNSUPPORTED; 345510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } else { 346ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten unsigned mask = 1 << index; 347bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 348bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if ((SL_OBJECT_STATE_REALIZED != thiz->mState) && 349bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten !(INTERFACE_PREREALIZE & clazz->mInterfaces[index].mInterface)) { 350104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten // Can't get interface on an unrealized object unless pre-realize is ok 351ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PRECONDITIONS_VIOLATED; 3528b8875067dd02b79361abb00c5d65b02a8ae72b0Glenn Kasten } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER == 353bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten clazz->mSLObjectID) && (1 == ((CAudioPlayer *) thiz)->mNumChannels)) { 354f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten // Can't get the MuteSolo interface of an audio player if the channel count is 355f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten // mono, but _can_ get the MuteSolo interface if the channel count is unknown 356f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten result = SL_RESULT_FEATURE_UNSUPPORTED; 357ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 358bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten switch (thiz->mInterfaceStates[index]) { 359ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case INTERFACE_EXPOSED: 360ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten case INTERFACE_ADDED: 361bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten interface = (char *) thiz + clazz->mInterfaces[index].mOffset; 362ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // Note that interface has been gotten, 363ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten // for debugger and to detect incorrect use of interfaces 364bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (!(thiz->mGottenMask & mask)) { 365bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mGottenMask |= mask; 366711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten // This trickery validates the v-table 367e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten ((size_t *) interface)[0] ^= ~0; 368e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten } 369ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_SUCCESS; 370ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 371a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // Can't get interface if uninitialized, initialized, suspended, 372a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // suspending, resuming, adding, or removing 373ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten default: 374ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_FEATURE_UNSUPPORTED; 375ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten break; 376ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 377510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 378bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 37961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 38061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 381ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten *(void **)pInterface = interface; 38261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 383ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 384ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 38561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 38661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 387ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 38861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_RegisterCallback(SLObjectItf self, 38961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten slObjectCallback callback, void *pContext) 39061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 391ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 392ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 393bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 394bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 395bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mCallback = callback; 396bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mContext = pContext; 397bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 398ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_SUCCESS; 399ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 400ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 40161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 40261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 403ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 404928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief This is internal common code for Abort and Destroy. 405928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten * Note: called with mutex unlocked, and returns with mutex locked. 406928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */ 407510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 408bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenstatic void Abort_internal(IObject *thiz) 409510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{ 410bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 411928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten bool anyAsync = false; 412bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 413928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten 414510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Abort asynchronous operations on the object 415bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten switch (thiz->mState) { 416510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case SL_OBJECT_STATE_REALIZING_1: // Realize 417bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_REALIZING_1A; 418928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 419510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 420510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case SL_OBJECT_STATE_RESUMING_1: // Resume 421bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_RESUMING_1A; 422928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 423928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 424928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_REALIZING_1A: // Realize 425928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_REALIZING_2: 426928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_RESUMING_1A: // Resume 427928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_RESUMING_2: 428928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 429928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 430928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_DESTROYING: 431928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten assert(false); 432510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 433510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten default: 434510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 435510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 436928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten 437510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten // Abort asynchronous operations on interfaces 438bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SLuint8 *interfaceStateP = thiz->mInterfaceStates; 439510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten unsigned index; 440bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) { 441510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten switch (*interfaceStateP) { 442510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_ADDING_1: // AddInterface 443510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten *interfaceStateP = INTERFACE_ADDING_1A; 444928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 445510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 446510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_RESUMING_1: // ResumeInterface 447510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten *interfaceStateP = INTERFACE_RESUMING_1A; 448928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 449928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 450928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_ADDING_1A: // AddInterface 451928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_ADDING_2: 452928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_RESUMING_1A: // ResumeInterface 453928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_RESUMING_2: 454711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten case INTERFACE_REMOVING: // not observable: RemoveInterface is synchronous & mutex locked 455928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 456510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 457510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten default: 458510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 459510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 460510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 461928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten 462928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // Wait until all asynchronous operations either complete normally or recognize the abort 463928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten while (anyAsync) { 464bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 465928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // FIXME should use condition variable instead of polling 466928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten usleep(20000); 467928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = false; 468bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 469bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten switch (thiz->mState) { 470928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_REALIZING_1: // state 1 means it cycled during the usleep window 471928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_RESUMING_1: 472928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_REALIZING_1A: 473928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_REALIZING_2: 474928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_RESUMING_1A: 475928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_RESUMING_2: 476928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 477928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 478928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case SL_OBJECT_STATE_DESTROYING: 479928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten assert(false); 480928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 481928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten default: 482928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 483928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 484bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten interfaceStateP = thiz->mInterfaceStates; 485bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) { 486928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten switch (*interfaceStateP) { 487928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_ADDING_1: // state 1 means it cycled during the usleep window 488928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_RESUMING_1: 489928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_ADDING_1A: 490928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_ADDING_2: 491928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_RESUMING_1A: 492928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_RESUMING_2: 493928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten case INTERFACE_REMOVING: 494928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten anyAsync = true; 495928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 496928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten default: 497928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten break; 498928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 499928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 500928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 501928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten 502928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // At this point there are no pending asynchronous operations 503510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten} 504510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten 505ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 50661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic void IObject_AbortAsyncOperation(SLObjectItf self) 50761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 508ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE_VOID 509ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 510bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 511bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten Abort_internal(thiz); 512bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 513ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 514ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE_VOID 51561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 51661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 517ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 518f51dba65751107c930759938775b75531ec1f330Glenn Kastenvoid IObject_Destroy(SLObjectItf self) 51961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 520ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE_VOID 521ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 522bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 523928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // mutex is unlocked 524bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten Abort_internal(thiz); 525928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // mutex is locked 526bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 527bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten PreDestroyHook preDestroy = clazz->mPreDestroy; 528928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // The pre-destroy hook is called with mutex locked, and should block until it is safe to 529928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // destroy. It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex 530928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // before returning. 531928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten if (NULL != preDestroy) { 532bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten predestroy_t okToDestroy = (*preDestroy)(thiz); 5331d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten switch (okToDestroy) { 5341d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten case predestroy_ok: 5351d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten break; 5361d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten case predestroy_error: 537bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SL_LOGE("Object::Destroy(%p) not allowed", thiz); 5381d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten // fall through 5391d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten case predestroy_again: 540bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 541928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // unfortunately Destroy doesn't return a result 542928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten SL_LEAVE_INTERFACE_VOID 5431d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten // unreachable 5441d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten default: 5451d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten assert(false); 5461d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten break; 547928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 548928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 549bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_DESTROYING; 550bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten VoidHook destroy = clazz->mDestroy; 551ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten // const, no lock needed 552bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IEngine *thisEngine = &thiz->mEngine->mEngine; 553bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten unsigned i = thiz->mInstanceID; 554f51dba65751107c930759938775b75531ec1f330Glenn Kasten assert(MAX_INSTANCE >= i); 555928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // avoid a recursive lock on the engine when destroying the engine itself 556bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (thisEngine->mThis != thiz) { 557928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten interface_lock_exclusive(thisEngine); 558928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 559f51dba65751107c930759938775b75531ec1f330Glenn Kasten // An unpublished object has a slot reserved, but the ID hasn't been chosen yet 560ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten assert(0 < thisEngine->mInstanceCount); 561ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten --thisEngine->mInstanceCount; 562f51dba65751107c930759938775b75531ec1f330Glenn Kasten // If object is published, then remove it from exposure to sync thread and debugger 563f51dba65751107c930759938775b75531ec1f330Glenn Kasten if (0 != i) { 564f51dba65751107c930759938775b75531ec1f330Glenn Kasten --i; 565104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten unsigned mask = 1 << i; 566104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten assert(thisEngine->mInstanceMask & mask); 567104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten thisEngine->mInstanceMask &= ~mask; 568bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(thisEngine->mInstances[i] == thiz); 569f51dba65751107c930759938775b75531ec1f330Glenn Kasten thisEngine->mInstances[i] = NULL; 57000d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten } 571928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // avoid a recursive unlock on the engine when destroying the engine itself 572bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (thisEngine->mThis != thiz) { 573928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten interface_unlock_exclusive(thisEngine); 574928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 575d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten // The destroy hook is called with mutex locked 5768c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (NULL != destroy) { 577bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (*destroy)(thiz); 5788c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 579a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // Call the deinitializer for each currently initialized interface, 58061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten // whether it is implicit, explicit, optional, or dynamically added. 5814597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten // The deinitializers are called in the reverse order that the 5824597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten // initializers were called, so that IObject_deinit is called last. 583bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten unsigned index = clazz->mInterfaceCount; 584bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const struct iid_vtable *x = &clazz->mInterfaces[index]; 585bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SLuint8 *interfaceStateP = &thiz->mInterfaceStates[index]; 5864597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten for ( ; index > 0; --index) { 5874597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten --x; 588711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten size_t offset = x->mOffset; 589bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten void *thisItf = (char *) thiz + offset; 5904597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten SLuint32 state = *--interfaceStateP; 591510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten switch (state) { 592510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_UNINITIALIZED: 593510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 594510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_EXPOSED: // quiescent states 595510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_ADDED: 596510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_SUSPENDED: 597711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten // The remove hook is called with mutex locked 598711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten { 599711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten VoidHook remove = MPH_init_table[x->mMPH].mRemove; 600711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten if (NULL != remove) { 601711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten (*remove)(thisItf); 602711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten } 603711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten *interfaceStateP = INTERFACE_INITIALIZED; 604711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten } 605a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // fall through 606a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten case INTERFACE_INITIALIZED: 607510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten { 60861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten VoidHook deinit = MPH_init_table[x->mMPH].mDeinit; 6098c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (NULL != deinit) { 610a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten (*deinit)(thisItf); 611510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten } 612a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten *interfaceStateP = INTERFACE_UNINITIALIZED; 6138c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 614510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 615510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_ADDING_1: // active states indicate incorrect use of API 616510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_ADDING_1A: 617510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_ADDING_2: 618510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_RESUMING_1: 619510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_RESUMING_1A: 620510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_RESUMING_2: 621510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_REMOVING: 622510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten case INTERFACE_SUSPENDING: 623bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SL_LOGE("Object::Destroy(%p) while interface %u active", thiz, index); 624510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 625510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten default: 626510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten assert(SL_BOOLEAN_FALSE); 627510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten break; 62861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 62961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 6304597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer 631bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten memset(thiz, 0x55, clazz->mSize); // catch broken applications that continue using interfaces 632711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten // was ifdef USE_DEBUG but safer to do this unconditionally 633bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten free(thiz); 634ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 635bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten if (SL_OBJECTID_ENGINE == clazz->mSLObjectID) { 636bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten CEngine_Destroyed((CEngine *) thiz); 637711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten } 638711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten 639ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE_VOID 64061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 64161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 642ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 6433a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable) 64461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 645ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 646ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 647a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE 648bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 649bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 650bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPriority = priority; 651bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize 652bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 653ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_SUCCESS; 6547a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else 6557a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten result = SL_RESULT_FEATURE_UNSUPPORTED; 6567a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif 657ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 658ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 65961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 66061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 661ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 6623a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable) 66361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 664ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 665ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 666a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE 667ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (NULL == pPriority || NULL == pPreemptable) { 668ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PARAMETER_INVALID; 669ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 670bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 671bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_shared(thiz); 672bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SLint32 priority = thiz->mPriority; 673bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten SLboolean preemptable = thiz->mPreemptable; 674bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_shared(thiz); 675ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten *pPriority = priority; 676ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten *pPreemptable = preemptable; 677ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_SUCCESS; 678ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 6797a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else 6807a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten result = SL_RESULT_FEATURE_UNSUPPORTED; 6817a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif 682ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 683ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 68461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 68561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 686ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 68761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self, 68861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled) 68961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 690ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE 691ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 692a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE 693ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_SUCCESS; 69461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten if (0 < numInterfaces) { 69561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten SLuint32 i; 696ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (NULL == pInterfaceIDs) { 697ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PARAMETER_INVALID; 698ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } else { 699bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 700bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten const ClassTable *clazz = thiz->mClass; 701ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten unsigned lossOfControlMask = 0; 7027a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten // The cast is due to a typo in the spec, bug 6482 703ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten for (i = 0; i < (SLuint32) numInterfaces; ++i) { 704ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SLInterfaceID iid = pInterfaceIDs[i]; 705ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten if (NULL == iid) { 706ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten result = SL_RESULT_PARAMETER_INVALID; 707ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten goto out; 708ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 709ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten int MPH, index; 7107a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten // We ignore without error any invalid MPH or index, but spec is unclear 711a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten if ((0 <= (MPH = IID_to_MPH(iid))) && 712a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten // no need to check for an initialization hook 713a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten // (NULL == MPH_init_table[MPH].mInit) || 714bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten (0 <= (index = clazz->mMPH_to_index[MPH]))) { 715ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten lossOfControlMask |= (1 << index); 716928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 717ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten } 718bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_lock_exclusive(thiz); 7198c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (enabled) { 720bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mLossOfControlMask |= lossOfControlMask; 7218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } else { 722bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mLossOfControlMask &= ~lossOfControlMask; 7238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 724bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten object_unlock_exclusive(thiz); 72561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 72661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten } 727ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kastenout: 7287a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else 7297a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten result = SL_RESULT_FEATURE_UNSUPPORTED; 7307a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif 731ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 732ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE 73361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 73461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 735ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 73661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic const struct SLObjectItf_ IObject_Itf = { 73761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_Realize, 73861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_Resume, 73961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_GetState, 74061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_GetInterface, 74161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_RegisterCallback, 74261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_AbortAsyncOperation, 74361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_Destroy, 74461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_SetPriority, 74561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten IObject_GetPriority, 746a361b51914aeb5f8f65c7ecad719d1e01f90913bGlenn Kasten IObject_SetLossOfControlInterfaces 74761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}; 74861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten 7494597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten 7504597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten/** \brief This must be the first initializer called for an object */ 7514597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten 75261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenvoid IObject_init(void *self) 75361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{ 754bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 755bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mItf = &IObject_Itf; 7560b167267bda99b68346045ccab14e810121d5de4Glenn Kasten // initialized in construct: 7570b167267bda99b68346045ccab14e810121d5de4Glenn Kasten // mClass 758ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten // mInstanceID 7590b167267bda99b68346045ccab14e810121d5de4Glenn Kasten // mLossOfControlMask 760ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten // mEngine 761a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten // mInterfaceStates 762bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mState = SL_OBJECT_STATE_UNREALIZED; 763bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mGottenMask = 1; // IObject 764bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mAttributesMask = 0; 765bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mCallback = NULL; 766bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mContext = NULL; 767a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE 768bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPriority = SL_PRIORITY_NORMAL; 769bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mPreemptable = SL_BOOLEAN_FALSE; 7707a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif 771bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mStrongRefCount = 0; 77261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten int ok; 773bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_mutex_init(&thiz->mMutex, (const pthread_mutexattr_t *) NULL); 77461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten assert(0 == ok); 775fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG 776bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten memset(&thiz->mOwner, 0, sizeof(pthread_t)); 777bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mFile = NULL; 778bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mLine = 0; 779fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif 780bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_cond_init(&thiz->mCond, (const pthread_condattr_t *) NULL); 78161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten assert(0 == ok); 78261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten} 7834597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten 7844597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten 7854597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten/** \brief This must be the last deinitializer called for an object */ 7864597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten 7874597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kastenvoid IObject_deinit(void *self) 7884597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten{ 789bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IObject *thiz = (IObject *) self; 7904597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#ifdef USE_DEBUG 791bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten assert(pthread_equal(pthread_self(), thiz->mOwner)); 7924597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#endif 7934597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten int ok; 794bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_cond_destroy(&thiz->mCond); 7954597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 7964597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten // equivalent to object_unlock_exclusive, but without the rigmarole 797bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_mutex_unlock(&thiz->mMutex); 7984597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 799bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten ok = pthread_mutex_destroy(&thiz->mMutex); 8004597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten assert(0 == ok); 801bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten // redundant: thiz->mState = SL_OBJECT_STATE_UNREALIZED; 8024597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten} 803f51dba65751107c930759938775b75531ec1f330Glenn Kasten 804f51dba65751107c930759938775b75531ec1f330Glenn Kasten 805f51dba65751107c930759938775b75531ec1f330Glenn Kasten/** \brief Publish a new object after it is fully initialized. 806f51dba65751107c930759938775b75531ec1f330Glenn Kasten * Publishing will expose the object to sync thread and debugger, 807f51dba65751107c930759938775b75531ec1f330Glenn Kasten * and make it safe to return the SLObjectItf to the application. 808f51dba65751107c930759938775b75531ec1f330Glenn Kasten */ 809f51dba65751107c930759938775b75531ec1f330Glenn Kasten 810bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid IObject_Publish(IObject *thiz) 811f51dba65751107c930759938775b75531ec1f330Glenn Kasten{ 812bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten IEngine *thisEngine = &thiz->mEngine->mEngine; 813f51dba65751107c930759938775b75531ec1f330Glenn Kasten interface_lock_exclusive(thisEngine); 814f51dba65751107c930759938775b75531ec1f330Glenn Kasten // construct earlier reserved a pending slot, but did not choose the actual slot number 815f51dba65751107c930759938775b75531ec1f330Glenn Kasten unsigned availMask = ~thisEngine->mInstanceMask; 816f51dba65751107c930759938775b75531ec1f330Glenn Kasten assert(availMask); 817f51dba65751107c930759938775b75531ec1f330Glenn Kasten unsigned i = ctz(availMask); 818f51dba65751107c930759938775b75531ec1f330Glenn Kasten assert(MAX_INSTANCE > i); 819f51dba65751107c930759938775b75531ec1f330Glenn Kasten assert(NULL == thisEngine->mInstances[i]); 820bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thisEngine->mInstances[i] = thiz; 821f51dba65751107c930759938775b75531ec1f330Glenn Kasten thisEngine->mInstanceMask |= 1 << i; 822f51dba65751107c930759938775b75531ec1f330Glenn Kasten // avoid zero as a valid instance ID 823bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten thiz->mInstanceID = i + 1; 824f51dba65751107c930759938775b75531ec1f330Glenn Kasten interface_unlock_exclusive(thisEngine); 825f51dba65751107c930759938775b75531ec1f330Glenn Kasten} 826