IDynamicInterfaceManagement.cpp revision 510f3671f716f6835282e4b0fd0275c20e9dadd8
1ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff/*
2ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * Copyright (C) 2010 The Android Open Source Project
3ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff *
4ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License");
5ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * you may not use this file except in compliance with the License.
6ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * You may obtain a copy of the License at
7ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff *
8ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff *      http://www.apache.org/licenses/LICENSE-2.0
9ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff *
10ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * Unless required by applicable law or agreed to in writing, software
11ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS,
12ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * See the License for the specific language governing permissions and
14ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff * limitations under the License.
15ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff */
16ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
17ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff/* DynamicInterfaceManagement implementation */
18ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
19fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi#include "sles_allinclusive.h"
20fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi
21fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi// Called by a worker thread to handle an asynchronous AddInterface.
22fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi// Parameter self is the DynamicInterface, and MPH specifies which interface to add.
23fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi
24fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichistatic void HandleAdd(void *self, int MPH)
25fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi{
26fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi
27fd31b9d46ea09dc7d74ddc03ab7e5ecfbe80b3dcHugo Benichi    // validate input parameters
28ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    IDynamicInterfaceManagement *thisDIM = (IDynamicInterfaceManagement *) self;
29ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    assert(NULL != thisDIM);
308c6c2c3c929acad783b9a56b8d9efa597d0ae609Lorenzo Colitti    IObject *thisObject = thisDIM->mThis;
31ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    assert(NULL != thisObject);
32b979f79158f9c470fa09ff3b96d72db274262201Robert Greenwalt    assert(0 <= MPH && MPH < MPH_MAX);
33befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    const ClassTable *class__ = thisObject->mClass;
34ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    assert(NULL != class__);
35ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    int index = class__->mMPH_to_index[MPH];
36ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    assert(0 <= index && index < (int) class__->mInterfaceCount);
37ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
38ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    SLresult result;
39e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti
4064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // check interface state
4164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    object_lock_exclusive(thisObject);
4264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    SLuint32 state = *interfaceStateP;
4364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    switch (state) {
4464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
457dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti    case INTERFACE_ADDING_1:    // normal case
467dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        {
477dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        // change state to indicate we are now adding the interface
487dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        *interfaceStateP = INTERFACE_ADDING_2;
497dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        object_unlock_exclusive(thisObject);
507dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti
517dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        // this section runs with mutex unlocked
52ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        const struct iid_vtable *x = &class__->mInterfaces[index];
53ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        size_t offset = x->mOffset;
54ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        void *thisItf = (char *) thisObject + offset;
55ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
56ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            class__->mSize : x[1].mOffset) - offset;
576eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti        memset(thisItf, 0, size);
58ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        ((void **) thisItf)[1] = thisObject;
59ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        VoidHook init = MPH_init_table[MPH].mInit;
60e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti        if (NULL != init)
61ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            (*init)(thisItf);
626eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti        result = SL_RESULT_SUCCESS;
63ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
6464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        // re-lock mutex to update state
6564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        object_lock_exclusive(thisObject);
6664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        assert(INTERFACE_ADDING_2 == *interfaceStateP);
6764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        state = INTERFACE_ADDED;
6864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        }
6964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        break;
7064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
7164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    case INTERFACE_ADDING_1A:   // operation was aborted while on work queue
7264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        result = SL_RESULT_OPERATION_ABORTED;
7364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        state = INTERFACE_UNINITIALIZED;
7464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        break;
7564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
7664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    default:                    // impossible
7764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        assert(SL_BOOLEAN_FALSE);
7864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        result = SL_RESULT_INTERNAL_ERROR;
791dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi        break;
8064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
8164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    }
8264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
8364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // mutex is locked, update state
8464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    *interfaceStateP = state;
8564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
8664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // Make a copy of these, so we can call the callback with mutex unlocked
8764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    slDynamicInterfaceManagementCallback callback = thisDIM->mCallback;
8864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    void *context = thisDIM->mContext;
8964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    object_unlock_exclusive(thisObject);
9064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
9164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // Note that the mutex is unlocked during the callback
9264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    if (NULL != callback) {
9364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
9464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        (*callback)(&thisDIM->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
9564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    }
9664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
9764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti}
98befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline
99befe778c73e48417942fc31c06509bac8e5ca0d2Erik Klinestatic SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,
100befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    const SLInterfaceID iid, SLboolean async)
101befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline{
102befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    // validate input parameters
103befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    if (NULL == iid)
1041dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi        return SL_RESULT_PARAMETER_INVALID;
105befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
1061eb8c69bed1615e9502e94b1a676773ed28abfd9Erik Kline    IObject *thisObject = this->mThis;
107befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    const ClassTable *class__ = thisObject->mClass;
108befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    int MPH, index;
109befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH])))
110befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline        return SL_RESULT_FEATURE_UNSUPPORTED;
111befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    assert(index < (int) class__->mInterfaceCount);
1121dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
1131dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi    SLresult result;
1141dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi
1151dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi    // check interface state
1161dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi    object_lock_exclusive(thisObject);
1171dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi    switch (*interfaceStateP) {
1181dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi
1191dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi    case INTERFACE_UNINITIALIZED:   // normal case
1201dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi        if (async) {
1211dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi            // Asynchronous: mark operation pending and cancellable
1221dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi            *interfaceStateP = INTERFACE_ADDING_1;
1231dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi            object_unlock_exclusive(thisObject);
1241dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi
1251dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi            // this section runs with mutex unlocked
1261dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi            result = ThreadPool_add(&thisObject->mEngine->mThreadPool, HandleAdd, this, MPH);
1271dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi            if (SL_RESULT_SUCCESS != result) {
12864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                // Engine was destroyed during add, or insufficient memory,
12964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                // so restore mInterfaceStates state to prior value
13064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                object_lock_exclusive(thisObject);
13164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                switch (*interfaceStateP) {
13264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                case INTERFACE_ADDING_1:    // normal
13364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                case INTERFACE_ADDING_1A:   // operation aborted while mutex unlocked
1341dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi                    *interfaceStateP = INTERFACE_UNINITIALIZED;
135b979f79158f9c470fa09ff3b96d72db274262201Robert Greenwalt                    break;
136b979f79158f9c470fa09ff3b96d72db274262201Robert Greenwalt                default:                    // unexpected
1376eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti                    // leave state alone
138b979f79158f9c470fa09ff3b96d72db274262201Robert Greenwalt                    break;
139ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                }
14096ca91761e6857c1ca2e4fafe5b35e4b5fefe5a1Irfan Sheriff            }
14164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
14264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        } else {
14364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            // Synchronous: mark operation pending to prevent duplication
14464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            *interfaceStateP = INTERFACE_ADDING_2;
14564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            object_unlock_exclusive(thisObject);
14664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
14764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            // this section runs with mutex unlocked
14864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            const struct iid_vtable *x = &class__->mInterfaces[index];
14964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            size_t offset = x->mOffset;
150fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt            size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
151fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt                class__->mSize : x[1].mOffset) - offset;
152fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt            void *thisItf = (char *) thisObject + offset;
153fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt            memset(thisItf, 0, size);
15464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            ((void **) thisItf)[1] = thisObject;
15564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            VoidHook init = MPH_init_table[MPH].mInit;
15664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            if (NULL != init)
157ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                (*init)(thisItf);
158ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            result = SL_RESULT_SUCCESS;
159e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti
160e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            // re-lock mutex to update state
16164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            object_lock_exclusive(thisObject);
162e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            assert(INTERFACE_ADDING_2 == *interfaceStateP);
163e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            *interfaceStateP = INTERFACE_ADDED;
164fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt        }
165e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti
1666eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti        // mutex is still locked
16764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        break;
16864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
1696eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    default:    // disallow adding of (partially) initialized interfaces
1706eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti        result = SL_RESULT_PRECONDITIONS_VIOLATED;
171e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti        break;
172e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti
17364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    }
174e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti
175fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    object_unlock_exclusive(thisObject);
176e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti    return result;
177ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff}
17864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
1796eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colittistatic SLresult IDynamicInterfaceManagement_RemoveInterface(
1806eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    SLDynamicInterfaceManagementItf self, const SLInterfaceID iid)
1816eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti{
1826eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    // validate input parameters
1836eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    if (NULL == iid)
18464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        return SL_RESULT_PARAMETER_INVALID;
1856eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
186fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    IObject *thisObject = (IObject *) this->mThis;
1876eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    const ClassTable *class__ = thisObject->mClass;
1886eb8a62a26f35ed1c2938945bb86a65f486a8052Lorenzo Colitti    int MPH, index;
18964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH])))
19064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        return SL_RESULT_PRECONDITIONS_VIOLATED;
19164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    SLresult result;
19264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
19364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
19464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // check interface state
19564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    object_lock_exclusive(thisObject);
19664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    switch (*interfaceStateP) {
19764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
19864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    case INTERFACE_ADDED:       // normal cases
199fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    case INTERFACE_SUSPENDED:
20064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        {
20164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        // Mark operation pending to prevent duplication
2028c6c2c3c929acad783b9a56b8d9efa597d0ae609Lorenzo Colitti        *interfaceStateP = INTERFACE_REMOVING;
2031dfb6b67555d04973dfb9d1100dfc1c6a5200633Hugo Benichi        thisObject->mGottenMask &= ~(1 << index);
2048c6c2c3c929acad783b9a56b8d9efa597d0ae609Lorenzo Colitti        object_unlock_exclusive(thisObject);
2058c6c2c3c929acad783b9a56b8d9efa597d0ae609Lorenzo Colitti
206ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        // The deinitialization is done with mutex unlocked
207ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        const struct iid_vtable *x = &class__->mInterfaces[index];
20864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        size_t offset = x->mOffset;
20964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        void *thisItf = (char *) thisObject + offset;
21064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        VoidHook deinit = MPH_init_table[MPH].mDeinit;
21164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        if (NULL != deinit)
21264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti            (*deinit)(thisItf);
213ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff#ifndef NDEBUG
214ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
215e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            class__->mSize : x[1].mOffset) - offset;
216ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        memset(thisItf, 0x55, size);
217ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff#endif
218ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        result = SL_RESULT_SUCCESS;
21964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
2207dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        // Note that this was previously locked, but then unlocked for the deinit hook
2217dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        object_lock_exclusive(thisObject);
2227dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        assert(INTERFACE_REMOVING == *interfaceStateP);
223ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        *interfaceStateP = INTERFACE_UNINITIALIZED;
224ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        }
225ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
226ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        // mutex is still locked
227ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        break;
228ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
229ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    default:
230ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        // disallow removal of non-dynamic interfaces, or interfaces which are
231ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        // currently being resumed (will not auto-cancel an asynchronous resume)
232ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        result = SL_RESULT_PRECONDITIONS_VIOLATED;
233ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        break;
23464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
23564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    }
23664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
237ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    object_unlock_exclusive(thisObject);
238ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    return result;
239e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti}
240e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti
2414e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang// Called by a worker thread to handle an asynchronous ResumeInterface.
242e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti// Parameter self is the DynamicInterface, and MPH specifies which interface to resume.
2434e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang
24464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colittistatic void HandleResume(void *self, int MPH)
24564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti{
24664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
24764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // validate input parameters
248fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    IDynamicInterfaceManagement *thisDIM = (IDynamicInterfaceManagement *) self;
249fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    assert(NULL != thisDIM);
250fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    IObject *thisObject = thisDIM->mThis;
251fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    assert(NULL != thisObject);
25264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    assert(0 <= MPH && MPH < MPH_MAX);
25364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    const ClassTable *class__ = thisObject->mClass;
25464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    assert(NULL != class__);
25564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    int index = class__->mMPH_to_index[MPH];
2567dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti    assert(0 <= index && index < (int) class__->mInterfaceCount);
25764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
25864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    SLresult result;
25964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
2604e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    // check interface state
2614e900091c4da26eb1c9f0d232ee0e50f4522cc69John Wang    object_lock_exclusive(thisObject);
262ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    SLuint32 state = *interfaceStateP;
263fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt    switch (state) {
264ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
265ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    case INTERFACE_RESUMING_1:      // normal case
266ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        {
267ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        // change state to indicate we are now resuming the interface
268ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        *interfaceStateP = INTERFACE_RESUMING_2;
269ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        object_unlock_exclusive(thisObject);
270fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt
271ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        // this section runs with mutex unlocked
2727dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        const struct iid_vtable *x = &class__->mInterfaces[index];
27396ca91761e6857c1ca2e4fafe5b35e4b5fefe5a1Irfan Sheriff        size_t offset = x->mOffset;
274ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        void *thisItf = (char *) thisObject + offset;
275ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        VoidHook resume = MPH_init_table[MPH].mResume;
276ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        if (NULL != resume)
2777dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti            (*resume)(thisItf);
2787dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        result = SL_RESULT_SUCCESS;
2797dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti
2807dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        // re-lock mutex to update state
2817dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        object_lock_exclusive(thisObject);
2827dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        assert(INTERFACE_RESUMING_2 == *interfaceStateP);
2837dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        state = INTERFACE_ADDED;
2847dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        }
2857dc78cf3af9fd11a4f1e2e981ce584a23755ea9eLorenzo Colitti        break;
286fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt
28764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    case INTERFACE_RESUMING_1A:     // operation was aborted while on work queue
28864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        result = SL_RESULT_OPERATION_ABORTED;
28964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        state = INTERFACE_SUSPENDED;
29064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        break;
29164483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
29264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    default:                        // impossible
293fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt        assert(SL_BOOLEAN_FALSE);
29464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        result = SL_RESULT_INTERNAL_ERROR;
29564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        break;
29664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
29764483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    }
29864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
29964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // mutex is locked, update state
30064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    *interfaceStateP = state;
301fd202e6f84ab0ee6a64aa81f94c3039eb10f8e17Robert Greenwalt
30264483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // Make a copy of these, so we can call the callback with mutex unlocked
30364483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    slDynamicInterfaceManagementCallback callback = thisDIM->mCallback;
304befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    void *context = thisDIM->mContext;
305befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    object_unlock_exclusive(thisObject);
306befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline
307befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    // Note that the mutex is unlocked during the callback
308befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    if (NULL != callback) {
309befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
31064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti        (*callback)(&thisDIM->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
311befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline    }
312befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline}
313befe778c73e48417942fc31c06509bac8e5ca0d2Erik Kline
31464483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colittistatic SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
31564483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    const SLInterfaceID iid, SLboolean async)
31664483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti{
317e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti    // validate input parameters
318ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    if (NULL == iid)
319ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        return SL_RESULT_PARAMETER_INVALID;
320ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
321ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    IObject *thisObject = (IObject *) this->mThis;
322ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    const ClassTable *class__ = thisObject->mClass;
323ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    int MPH, index;
324ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH])))
325ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        return SL_RESULT_PRECONDITIONS_VIOLATED;
326ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    assert(index < (int) class__->mInterfaceCount);
327e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
328e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti    SLresult result;
32964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti
33064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti    // check interface state
331ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    object_lock_exclusive(thisObject);
332ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    switch (*interfaceStateP) {
333ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
334ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff    case INTERFACE_SUSPENDED:   // normal case
335ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        if (async) {
336ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            // Asynchronous: mark operation pending and cancellable
337ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            *interfaceStateP = INTERFACE_RESUMING_1;
338ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            object_unlock_exclusive(thisObject);
339ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
340e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            // this section runs with mutex unlocked
341e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            result = ThreadPool_add(&thisObject->mEngine->mThreadPool, HandleResume, this, MPH);
342e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti            if (SL_RESULT_SUCCESS != result) {
343e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti                // Engine was destroyed during resume, or insufficient memory,
344e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti                // so restore mInterfaceStates state to prior value
345e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti                object_lock_exclusive(thisObject);
346ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                switch (*interfaceStateP) {
347e1ad1849f3a65c1ff06919351ef1d73e9bc8854eLorenzo Colitti                case INTERFACE_RESUMING_1:  // normal
34864483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                case INTERFACE_RESUMING_1A: // operation aborted while mutex unlocked
34964483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                    *interfaceStateP = INTERFACE_SUSPENDED;
35064483947fdb03bf838e317ac0a4af5e0f53a5bbfLorenzo Colitti                    break;
351ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                default:                    // unexpected
352ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                    // leave state alone
353ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                    break;
354ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff                }
355ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff            }
356ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff
357ed5d7d17c9e9837ce7a6a10698cce9f6e4101acdIrfan Sheriff        } else {
358            // Synchronous: mark operation pending to prevent duplication
359            *interfaceStateP = INTERFACE_RESUMING_2;
360            object_unlock_exclusive(thisObject);
361
362            // this section runs with mutex unlocked
363            const struct iid_vtable *x = &class__->mInterfaces[index];
364            size_t offset = x->mOffset;
365            void *thisItf = (char *) this + offset;
366            VoidHook resume = MPH_init_table[MPH].mResume;
367            if (NULL != resume)
368                (*resume)(thisItf);
369            result = SL_RESULT_SUCCESS;
370
371            // re-lock mutex to update state
372            object_lock_exclusive(thisObject);
373            assert(INTERFACE_RESUMING_2 == *interfaceStateP);
374            *interfaceStateP = INTERFACE_ADDED;
375        }
376
377        // mutex is now unlocked
378        break;
379
380    default:    // disallow resumption of non-suspended interfaces
381        object_unlock_exclusive(thisObject);
382        result = SL_RESULT_PRECONDITIONS_VIOLATED;
383        break;
384    }
385
386    object_unlock_exclusive(thisObject);
387    return result;
388}
389
390static SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
391    slDynamicInterfaceManagementCallback callback, void *pContext)
392{
393    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
394    IObject *thisObject = this->mThis;
395    object_lock_exclusive(thisObject);
396    this->mCallback = callback;
397    this->mContext = pContext;
398    object_unlock_exclusive(thisObject);
399    return SL_RESULT_SUCCESS;
400}
401
402static const struct SLDynamicInterfaceManagementItf_ IDynamicInterfaceManagement_Itf = {
403    IDynamicInterfaceManagement_AddInterface,
404    IDynamicInterfaceManagement_RemoveInterface,
405    IDynamicInterfaceManagement_ResumeInterface,
406    IDynamicInterfaceManagement_RegisterCallback
407};
408
409void IDynamicInterfaceManagement_init(void *self)
410{
411    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
412    this->mItf = &IDynamicInterfaceManagement_Itf;
413    this->mCallback = NULL;
414    this->mContext = NULL;
415}
416