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;
454260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // Note that the mutex is locked on entry to and exit from the realize hook,
464260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
47bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            result = (*realize)(thiz, SL_BOOLEAN_TRUE);
48bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState);
49510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
50510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                SL_OBJECT_STATE_UNREALIZED;
51510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
52510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = SL_RESULT_SUCCESS;
53510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_OBJECT_STATE_REALIZED;
54510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
55510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
56510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
57510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1A:  // operation was aborted while on work queue
58510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
59510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_UNREALIZED;
60510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
61510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
62510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                            // impossible
63510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
64510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
65510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
66510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
6761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
68510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
69510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is locked, update state
70bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState = state;
71510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
72d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
73bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    slObjectCallback callback = thiz->mCallback;
74bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    void *context = thiz->mContext;
75bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_unlock_exclusive(thiz);
76510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
77d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    // Note that the mutex is unlocked during the callback
788c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != callback) {
79bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
808c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
81d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten}
82d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten
83ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
84d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kastenstatic SLresult IObject_Realize(SLObjectItf self, SLboolean async)
85d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten{
86ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
87ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
88bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
89276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state;
90bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const ClassTable *clazz = thiz->mClass;
911d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    bool isSharedEngine = false;
92bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_lock_exclusive(thiz);
931d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    // note that SL_OBJECTID_ENGINE and XA_OBJECTID_ENGINE map to same class
94bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (clazz == objectIDtoClass(SL_OBJECTID_ENGINE)) {
951d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        // important: the lock order is engine followed by theOneTrueMutex
961d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        int ok = pthread_mutex_lock(&theOneTrueMutex);
971d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        assert(0 == ok);
981d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        isSharedEngine = 1 < theOneTrueRefCount;
991d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        ok = pthread_mutex_unlock(&theOneTrueMutex);
1001d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        assert(0 == ok);
1011d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    }
102bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    state = thiz->mState;
1031d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten    // Reject redundant calls to Realize, except on a shared engine
104d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    if (SL_OBJECT_STATE_UNREALIZED != state) {
105bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        object_unlock_exclusive(thiz);
1061d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        // redundant realize on the shared engine is permitted
1071d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        if (isSharedEngine && (SL_OBJECT_STATE_REALIZED == state)) {
1081d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            result = SL_RESULT_SUCCESS;
1091d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        } else {
1101d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            result = SL_RESULT_PRECONDITIONS_VIOLATED;
1111d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        }
112d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    } else {
113ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Asynchronous: mark operation pending and cancellable
114bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        if (async && (SL_OBJECTID_ENGINE != clazz->mSLObjectID)) {
115ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_REALIZING_1;
116ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Synchronous: mark operation pending and non-cancellable
117ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
118ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_REALIZING_2;
119d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten        }
120bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mState = state;
121ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        switch (state) {
122ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine
1234260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            object_unlock_exclusive(thiz);
124ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(async);
125cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten            result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleRealize, thiz, NULL, 0);
126ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            if (SL_RESULT_SUCCESS != result) {
127ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // Engine was destroyed during realize, or insufficient memory
128bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                object_lock_exclusive(thiz);
129bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mState = SL_OBJECT_STATE_UNREALIZED;
130bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                object_unlock_exclusive(thiz);
131ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
132ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
133ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine
134ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            {
135bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            AsyncHook realize = clazz->mRealize;
1364260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // Note that the mutex is locked on entry to and exit from the realize hook,
1374260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
138bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            result = (NULL != realize) ? (*realize)(thiz, async) : SL_RESULT_SUCCESS;
139bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState);
140ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
141ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                SL_OBJECT_STATE_UNREALIZED;
142bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mState = state;
143bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            slObjectCallback callback = thiz->mCallback;
144bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            void *context = thiz->mContext;
145bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            object_unlock_exclusive(thiz);
146ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // asynchronous Realize on an Engine is actually done synchronously, but still has
147ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // callback because there is no thread pool yet to do it asynchronously.
1488c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (async && (NULL != callback)) {
149bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state,
150ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    NULL);
151ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
1528c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
153ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
154ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        default:                          // impossible
1554260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            object_unlock_exclusive(thiz);
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;
1884260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // Note that the mutex is locked on entry to and exit from the resume hook,
1894260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
190bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            result = (*resume)(thiz, SL_BOOLEAN_TRUE);
191bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState);
192510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
193510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                SL_OBJECT_STATE_SUSPENDED;
194510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
195510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            result = SL_RESULT_SUCCESS;
196510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            state = SL_OBJECT_STATE_REALIZED;
1973a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten        }
198510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
199510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
200510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1A:   // operation was aborted while on work queue
201510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_OPERATION_ABORTED;
202510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        state = SL_OBJECT_STATE_SUSPENDED;
203510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
204510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
205510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:                            // impossible
206510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        assert(SL_BOOLEAN_FALSE);
207510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        result = SL_RESULT_INTERNAL_ERROR;
208510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
209510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
21061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
211510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
212510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // mutex is unlocked, update state
213bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState = state;
214510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
215510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Make a copy of these, so we can call the callback with mutex unlocked
216bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    slObjectCallback callback = thiz->mCallback;
217bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    void *context = thiz->mContext;
218bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_unlock_exclusive(thiz);
219510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
220510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Note that the mutex is unlocked during the callback
2218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != callback) {
222bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
2238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
224510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
225510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
226ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
227510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kastenstatic SLresult IObject_Resume(SLObjectItf self, SLboolean async)
228510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
229ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
230ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
231bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
232bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const ClassTable *clazz = thiz->mClass;
233276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    SLuint8 state;
234bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_lock_exclusive(thiz);
235bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    state = thiz->mState;
236510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Reject redundant calls to Resume
237510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    if (SL_OBJECT_STATE_SUSPENDED != state) {
238bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        object_unlock_exclusive(thiz);
239ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PRECONDITIONS_VIOLATED;
240510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    } else {
241ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Asynchronous: mark operation pending and cancellable
242ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (async) {
243ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_RESUMING_1;
244ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Synchronous: mark operatio pending and non-cancellable
245ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
246ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_RESUMING_2;
247510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
248bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mState = state;
249ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        switch (state) {
250ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1: // asynchronous
2514260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            object_unlock_exclusive(thiz);
252ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(async);
253cf3a6383a9bc9a94ca5b424ea97313293ee0dcb0Glenn Kasten            result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleResume, thiz, NULL, 0);
254ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            if (SL_RESULT_SUCCESS != result) {
255ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                // Engine was destroyed during resume, or insufficient memory
256bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                object_lock_exclusive(thiz);
257bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mState = SL_OBJECT_STATE_SUSPENDED;
258bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                object_unlock_exclusive(thiz);
259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
261ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_2: // synchronous
262ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            {
263bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            AsyncHook resume = clazz->mResume;
2644260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // Note that the mutex is locked on entry to and exit from the resume hook,
2654260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
266bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            result = (NULL != resume) ? (*resume)(thiz, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS;
267bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState);
268bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            thiz->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
269ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                SL_OBJECT_STATE_SUSPENDED;
270bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            object_unlock_exclusive(thiz);
271ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
272ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
273ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        default:                        // impossible
2744260ff7b8f65fdfe8d0176cdce66faf0a10c4b10Glenn Kasten            object_unlock_exclusive(thiz);
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;
292b566926611b2105a46c4ff98238ad06aca54104dGlenn Kasten        object_lock_shared(thiz);
293bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLuint8 state = thiz->mState;
294b566926611b2105a46c4ff98238ad06aca54104dGlenn Kasten        object_unlock_shared(thiz);
295ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        // Re-map the realizing, resuming, and suspending states
296ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        switch (state) {
297ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1:
298ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1A:
299ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZING_2:
300928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_DESTROYING:    // application shouldn't call GetState after Destroy
301ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_UNREALIZED;
302ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
303ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1:
304ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1A:
305ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_RESUMING_2:
306ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_SUSPENDING:
307ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            state = SL_OBJECT_STATE_SUSPENDED;
308ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
309ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_UNREALIZED:
310ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_REALIZED:
311ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        case SL_OBJECT_STATE_SUSPENDED:
312ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            // These are the "official" object states, return them as is
313ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
314ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        default:
315ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            assert(SL_BOOLEAN_FALSE);
316ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            break;
317ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        }
318ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pState = state;
319ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
320d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten    }
321ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
322ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
32361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
32461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
3253a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface)
32661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
327ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
328ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
329ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pInterface) {
33061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
331ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
332ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        void *interface = NULL;
333ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == iid) {
334ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
335510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        } else {
336bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            IObject *thiz = (IObject *) self;
337bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            const ClassTable *clazz = thiz->mClass;
338ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            int MPH, index;
339a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten            if ((0 > (MPH = IID_to_MPH(iid))) ||
340a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // no need to check for an initialization hook
341a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // (NULL == MPH_init_table[MPH].mInit) ||
342bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    (0 > (index = clazz->mMPH_to_index[MPH]))) {
343ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                result = SL_RESULT_FEATURE_UNSUPPORTED;
344510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            } else {
345ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                unsigned mask = 1 << index;
346bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                object_lock_exclusive(thiz);
347bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                if ((SL_OBJECT_STATE_REALIZED != thiz->mState) &&
348bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                        !(INTERFACE_PREREALIZE & clazz->mInterfaces[index].mInterface)) {
349104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten                    // Can't get interface on an unrealized object unless pre-realize is ok
350ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    result = SL_RESULT_PRECONDITIONS_VIOLATED;
3518b8875067dd02b79361abb00c5d65b02a8ae72b0Glenn Kasten                } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER ==
352bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                        clazz->mSLObjectID) && (1 == ((CAudioPlayer *) thiz)->mNumChannels)) {
353f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten                    // Can't get the MuteSolo interface of an audio player if the channel count is
354f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten                    // mono, but _can_ get the MuteSolo interface if the channel count is unknown
355f6f5ceb363286d5ebef2c2e70c8a5aa135d5d1eeGlenn Kasten                    result = SL_RESULT_FEATURE_UNSUPPORTED;
356ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                } else {
357bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                    switch (thiz->mInterfaceStates[index]) {
358ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    case INTERFACE_EXPOSED:
359ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    case INTERFACE_ADDED:
360bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                        interface = (char *) thiz + clazz->mInterfaces[index].mOffset;
361ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // Note that interface has been gotten,
362ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        // for debugger and to detect incorrect use of interfaces
363bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                        if (!(thiz->mGottenMask & mask)) {
364bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                            thiz->mGottenMask |= mask;
365711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                            // This trickery validates the v-table
366e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                            ((size_t *) interface)[0] ^= ~0;
367e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten                        }
368ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        result = SL_RESULT_SUCCESS;
369ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        break;
370a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // Can't get interface if uninitialized, initialized, suspended,
371a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                    // suspending, resuming, adding, or removing
372ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    default:
373ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        result = SL_RESULT_FEATURE_UNSUPPORTED;
374ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                        break;
375ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    }
376510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten                }
377bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                object_unlock_exclusive(thiz);
37861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            }
37961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
380ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *(void **)pInterface = interface;
38161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
382ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
383ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
38461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
38561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
386ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
38761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_RegisterCallback(SLObjectItf self,
38861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    slObjectCallback callback, void *pContext)
38961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
390ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
391ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
392bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
393bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_lock_exclusive(thiz);
394bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = callback;
395bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = pContext;
396bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_unlock_exclusive(thiz);
397ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
398ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
399ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
40061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
40161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
402ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
403928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief This is internal common code for Abort and Destroy.
404928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten *  Note: called with mutex unlocked, and returns with mutex locked.
405928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */
406510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
407bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenstatic void Abort_internal(IObject *thiz)
408510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten{
409bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const ClassTable *clazz = thiz->mClass;
410928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    bool anyAsync = false;
411bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_lock_exclusive(thiz);
412928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
413510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Abort asynchronous operations on the object
414bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    switch (thiz->mState) {
415510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1:   // Realize
416bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mState = SL_OBJECT_STATE_REALIZING_1A;
417928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = true;
418510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
419510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1:    // Resume
420bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mState = SL_OBJECT_STATE_RESUMING_1A;
421928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = true;
422928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        break;
423928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_REALIZING_1A:  // Realize
424928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_REALIZING_2:
425928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_RESUMING_1A:   // Resume
426928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_RESUMING_2:
427928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = true;
428928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        break;
429928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    case SL_OBJECT_STATE_DESTROYING:
430928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        assert(false);
431510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
432510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    default:
433510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        break;
434510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
435928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
436510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    // Abort asynchronous operations on interfaces
437bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    SLuint8 *interfaceStateP = thiz->mInterfaceStates;
438510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    unsigned index;
439bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) {
440510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        switch (*interfaceStateP) {
441510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1:    // AddInterface
442510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            *interfaceStateP = INTERFACE_ADDING_1A;
443928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
444510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
445510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1:  // ResumeInterface
446510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            *interfaceStateP = INTERFACE_RESUMING_1A;
447928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
448928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
449928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_ADDING_1A:   // AddInterface
450928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_ADDING_2:
451928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_RESUMING_1A: // ResumeInterface
452928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case INTERFACE_RESUMING_2:
453711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten        case INTERFACE_REMOVING:    // not observable: RemoveInterface is synchronous & mutex locked
454928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
455510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
456510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        default:
457510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
458510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        }
459510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten    }
460928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
461928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // Wait until all asynchronous operations either complete normally or recognize the abort
462928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    while (anyAsync) {
463bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        object_unlock_exclusive(thiz);
464928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        // FIXME should use condition variable instead of polling
465928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        usleep(20000);
466928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        anyAsync = false;
467bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        object_lock_exclusive(thiz);
468bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        switch (thiz->mState) {
469928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1:   // state 1 means it cycled during the usleep window
470928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1:
471928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_REALIZING_1A:
472928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_REALIZING_2:
473928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_RESUMING_1A:
474928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_RESUMING_2:
475928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            anyAsync = true;
476928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
477928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        case SL_OBJECT_STATE_DESTROYING:
478928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            assert(false);
479928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
480928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        default:
481928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            break;
482928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
483bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        interfaceStateP = thiz->mInterfaceStates;
484bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) {
485928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            switch (*interfaceStateP) {
486928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_ADDING_1:    // state 1 means it cycled during the usleep window
487928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_RESUMING_1:
488928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_ADDING_1A:
489928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_ADDING_2:
490928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_RESUMING_1A:
491928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_RESUMING_2:
492928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            case INTERFACE_REMOVING:
493928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                anyAsync = true;
494928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                break;
495928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            default:
496928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                break;
497928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            }
498928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
499928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
500928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
501928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // At this point there are no pending asynchronous operations
502510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten}
503510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten
504ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
50561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic void IObject_AbortAsyncOperation(SLObjectItf self)
50661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
507ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE_VOID
508ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
509bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
510bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    Abort_internal(thiz);
511bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_unlock_exclusive(thiz);
512ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
513ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
51461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
51561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
516ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
517f51dba65751107c930759938775b75531ec1f330Glenn Kastenvoid IObject_Destroy(SLObjectItf self)
51861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
519ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE_VOID
520ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
521bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
522928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // mutex is unlocked
523bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    Abort_internal(thiz);
524928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // mutex is locked
525bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const ClassTable *clazz = thiz->mClass;
526bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    PreDestroyHook preDestroy = clazz->mPreDestroy;
527928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // The pre-destroy hook is called with mutex locked, and should block until it is safe to
528928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // destroy.  It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex
529928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // before returning.
530928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    if (NULL != preDestroy) {
531bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        predestroy_t okToDestroy = (*preDestroy)(thiz);
5321d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        switch (okToDestroy) {
5331d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        case predestroy_ok:
5341d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            break;
5351d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        case predestroy_error:
536bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            SL_LOGE("Object::Destroy(%p) not allowed", thiz);
5371d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            // fall through
5381d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        case predestroy_again:
539bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            object_unlock_exclusive(thiz);
540928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            // unfortunately Destroy doesn't return a result
541928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            SL_LEAVE_INTERFACE_VOID
5421d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            // unreachable
5431d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten        default:
5441d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            assert(false);
5451d081e49a10543018e1ae33792bd3d30504719baGlenn Kasten            break;
546928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
547928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
548bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState = SL_OBJECT_STATE_DESTROYING;
549bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    VoidHook destroy = clazz->mDestroy;
550ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // const, no lock needed
551bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IEngine *thisEngine = &thiz->mEngine->mEngine;
552bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    unsigned i = thiz->mInstanceID;
553f51dba65751107c930759938775b75531ec1f330Glenn Kasten    assert(MAX_INSTANCE >= i);
554928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // avoid a recursive lock on the engine when destroying the engine itself
555bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (thisEngine->mThis != thiz) {
556928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interface_lock_exclusive(thisEngine);
557928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
558f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // An unpublished object has a slot reserved, but the ID hasn't been chosen yet
559ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    assert(0 < thisEngine->mInstanceCount);
560ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    --thisEngine->mInstanceCount;
561f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // If object is published, then remove it from exposure to sync thread and debugger
562f51dba65751107c930759938775b75531ec1f330Glenn Kasten    if (0 != i) {
563f51dba65751107c930759938775b75531ec1f330Glenn Kasten        --i;
564104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten        unsigned mask = 1 << i;
565104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten        assert(thisEngine->mInstanceMask & mask);
566104c000a6f36b871ca11e0394db1e5217f374cafGlenn Kasten        thisEngine->mInstanceMask &= ~mask;
567bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        assert(thisEngine->mInstances[i] == thiz);
568f51dba65751107c930759938775b75531ec1f330Glenn Kasten        thisEngine->mInstances[i] = NULL;
56900d2d554e04ac369367c903dbf53b975355d1bcdGlenn Kasten    }
570928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    // avoid a recursive unlock on the engine when destroying the engine itself
571bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (thisEngine->mThis != thiz) {
572928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interface_unlock_exclusive(thisEngine);
573928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
574d48ff338b8338c1e3e54e0f9dcd03567a0aa9de4Glenn Kasten    // The destroy hook is called with mutex locked
5758c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (NULL != destroy) {
576bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        (*destroy)(thiz);
5778c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
578a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten    // Call the deinitializer for each currently initialized interface,
57961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    // whether it is implicit, explicit, optional, or dynamically added.
5804597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // The deinitializers are called in the reverse order that the
5814597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // initializers were called, so that IObject_deinit is called last.
582bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    unsigned index = clazz->mInterfaceCount;
583bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const struct iid_vtable *x = &clazz->mInterfaces[index];
584bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    SLuint8 *interfaceStateP = &thiz->mInterfaceStates[index];
5854597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    for ( ; index > 0; --index) {
5864597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten        --x;
587711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten        size_t offset = x->mOffset;
588bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        void *thisItf = (char *) thiz + offset;
5894597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten        SLuint32 state = *--interfaceStateP;
590510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        switch (state) {
591510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_UNINITIALIZED:
592510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
593510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_EXPOSED:     // quiescent states
594510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDED:
595510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_SUSPENDED:
596711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            // The remove hook is called with mutex locked
597711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            {
598711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            VoidHook remove = MPH_init_table[x->mMPH].mRemove;
599711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            if (NULL != remove) {
600711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                (*remove)(thisItf);
601711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            }
602711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            *interfaceStateP = INTERFACE_INITIALIZED;
603711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten            }
604a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            // fall through
605a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten        case INTERFACE_INITIALIZED:
606510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            {
60761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten            VoidHook deinit = MPH_init_table[x->mMPH].mDeinit;
6088c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (NULL != deinit) {
609a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten                (*deinit)(thisItf);
610510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            }
611a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten            *interfaceStateP = INTERFACE_UNINITIALIZED;
6128c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
613510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
614510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1:    // active states indicate incorrect use of API
615510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_1A:
616510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_ADDING_2:
617510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1:
618510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_1A:
619510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_RESUMING_2:
620510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_REMOVING:
621510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        case INTERFACE_SUSPENDING:
622bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            SL_LOGE("Object::Destroy(%p) while interface %u active", thiz, index);
623510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
624510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten        default:
625510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            assert(SL_BOOLEAN_FALSE);
626510f3671f716f6835282e4b0fd0275c20e9dadd8Glenn Kasten            break;
62761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
62861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
6294597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer
630bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(thiz, 0x55, clazz->mSize); // catch broken applications that continue using interfaces
631711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten                                        // was ifdef USE_DEBUG but safer to do this unconditionally
632bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    free(thiz);
633ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
634bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (SL_OBJECTID_ENGINE == clazz->mSLObjectID) {
635bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        CEngine_Destroyed((CEngine *) thiz);
636711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten    }
637711332800108ad6e0e594796e5f8db0da3eff402Glenn Kasten
638ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
63961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
64061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
641ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
6423a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable)
64361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
644ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
645ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
646a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
647bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
648bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_lock_exclusive(thiz);
649bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPriority = priority;
650bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize
651bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    object_unlock_exclusive(thiz);
652ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
6537a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else
6547a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
6557a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
656ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
657ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
65861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
65961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
660ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
6613a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kastenstatic SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable)
66261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
663ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
664ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
665a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
666ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    if (NULL == pPriority || NULL == pPreemptable) {
667ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_PARAMETER_INVALID;
668ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    } else {
669bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        IObject *thiz = (IObject *) self;
670bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        object_lock_shared(thiz);
671bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLint32 priority = thiz->mPriority;
672bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        SLboolean preemptable = thiz->mPreemptable;
673bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        object_unlock_shared(thiz);
674ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pPriority = priority;
675ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        *pPreemptable = preemptable;
676ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        result = SL_RESULT_SUCCESS;
677ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    }
6787a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else
6797a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
6807a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
681ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
682ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
68361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
68461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
685ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
68661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self,
68761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled)
68861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
689ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE
690ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
691a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
692ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    result = SL_RESULT_SUCCESS;
69361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    if (0 < numInterfaces) {
69461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        SLuint32 i;
695ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        if (NULL == pInterfaceIDs) {
696ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            result = SL_RESULT_PARAMETER_INVALID;
697ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten        } else {
698bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            IObject *thiz = (IObject *) self;
699bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            const ClassTable *clazz = thiz->mClass;
700ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            unsigned lossOfControlMask = 0;
7017a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten            // The cast is due to a typo in the spec, bug 6482
702ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            for (i = 0; i < (SLuint32) numInterfaces; ++i) {
703ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                SLInterfaceID iid = pInterfaceIDs[i];
704ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                if (NULL == iid) {
705ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    result = SL_RESULT_PARAMETER_INVALID;
706ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    goto out;
707ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                }
708ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                int MPH, index;
7097a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten                // We ignore without error any invalid MPH or index, but spec is unclear
710a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                if ((0 <= (MPH = IID_to_MPH(iid))) &&
711a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                        // no need to check for an initialization hook
712a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten                        // (NULL == MPH_init_table[MPH].mInit) ||
713bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                        (0 <= (index = clazz->mMPH_to_index[MPH]))) {
714ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten                    lossOfControlMask |= (1 << index);
715928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten                }
716ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten            }
717bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            object_lock_exclusive(thiz);
7188c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (enabled) {
719bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mLossOfControlMask |= lossOfControlMask;
7208c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            } else {
721bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                thiz->mLossOfControlMask &= ~lossOfControlMask;
7228c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
723bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            object_unlock_exclusive(thiz);
72461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten        }
72561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    }
726ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kastenout:
7277a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#else
7287a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten    result = SL_RESULT_FEATURE_UNSUPPORTED;
7297a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
730ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
731ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE
73261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten}
73361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
734ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
73561ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenstatic const struct SLObjectItf_ IObject_Itf = {
73661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Realize,
73761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Resume,
73861ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetState,
73961ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetInterface,
74061ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_RegisterCallback,
74161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_AbortAsyncOperation,
74261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_Destroy,
74361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_SetPriority,
74461ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    IObject_GetPriority,
745a361b51914aeb5f8f65c7ecad719d1e01f90913bGlenn Kasten    IObject_SetLossOfControlInterfaces
74661ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten};
74761ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten
7484597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
7494597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten/** \brief This must be the first initializer called for an object */
7504597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten
75161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kastenvoid IObject_init(void *self)
75261ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten{
753bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thiz = (IObject *) self;
754bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IObject_Itf;
7550b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // initialized in construct:
7560b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // mClass
757ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // mInstanceID
7580b167267bda99b68346045ccab14e810121d5de4Glenn Kasten    // mLossOfControlMask
759ccdf07b17f23b4c040dd3f62478d0965eba804e3Glenn Kasten    // mEngine
760a9a70a4451545034c9263dd55b181f2912534c37Glenn Kasten    // mInterfaceStates
761bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mState = SL_OBJECT_STATE_UNREALIZED;
762bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mGottenMask = 1;  // IObject
763bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mAttributesMask = 0;
764bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mCallback = NULL;
765bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mContext = NULL;
766a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten#if USE_PROFILES & USE_PROFILES_BASE
767bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPriority = SL_PRIORITY_NORMAL;
768bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mPreemptable = SL_BOOLEAN_FALSE;
7697a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten#endif
770bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mStrongRefCount = 0;
77161ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    int ok;
772bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_init(&thiz->mMutex, (const pthread_mutexattr_t *) NULL);
77361ac0ade16f84d877dfd8d0e984eb203d4a2901dGlenn Kasten    assert(0 == ok);
774fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
775bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
776bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = NULL;
777bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = 0;
7784ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    thiz->mGeneration = 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