IDynamicInterfaceManagement.c revision ed46c29d6a09112dbbf584c82953f63289596fd6
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* DynamicInterfaceManagement implementation */
18
19#include "sles_allinclusive.h"
20
21
22// Called by a worker thread to handle an asynchronous AddInterface.
23// Parameter self is the DynamicInterface, and MPH specifies which interface to add.
24
25static void HandleAdd(void *self, int MPH)
26{
27
28    // validate input parameters
29    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
30    assert(NULL != this);
31    IObject *thisObject = InterfaceToIObject(this);
32    assert(NULL != thisObject);
33    assert(0 <= MPH && MPH < MPH_MAX);
34    const ClassTable *class__ = thisObject->mClass;
35    assert(NULL != class__);
36    int index = class__->mMPH_to_index[MPH];
37    assert(0 <= index && index < (int) class__->mInterfaceCount);
38    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
39    SLresult result;
40
41    // check interface state
42    object_lock_exclusive(thisObject);
43    SLuint8 state = *interfaceStateP;
44    switch (state) {
45
46    case INTERFACE_ADDING_1:    // normal case
47        {
48        // change state to indicate we are now adding the interface
49        *interfaceStateP = INTERFACE_ADDING_2;
50        object_unlock_exclusive(thisObject);
51
52        // this section runs with mutex unlocked
53        const struct iid_vtable *x = &class__->mInterfaces[index];
54        size_t offset = x->mOffset;
55        void *thisItf = (char *) thisObject + offset;
56        size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
57            class__->mSize : x[1].mOffset) - offset;
58        memset(thisItf, 0, size);
59        // Will never add IObject, so [1] is always defined
60        ((void **) thisItf)[1] = thisObject;
61        VoidHook init = MPH_init_table[MPH].mInit;
62        if (NULL != init)
63            (*init)(thisItf);
64        result = SL_RESULT_SUCCESS;
65
66        // re-lock mutex to update state
67        object_lock_exclusive(thisObject);
68        assert(INTERFACE_ADDING_2 == *interfaceStateP);
69        state = INTERFACE_ADDED;
70        }
71        break;
72
73    case INTERFACE_ADDING_1A:   // operation was aborted while on work queue
74        result = SL_RESULT_OPERATION_ABORTED;
75        state = INTERFACE_UNINITIALIZED;
76        break;
77
78    default:                    // impossible
79        assert(SL_BOOLEAN_FALSE);
80        result = SL_RESULT_INTERNAL_ERROR;
81        break;
82
83    }
84
85    // mutex is locked, update state
86    *interfaceStateP = state;
87
88    // Make a copy of these, so we can call the callback with mutex unlocked
89    slDynamicInterfaceManagementCallback callback = this->mCallback;
90    void *context = this->mContext;
91    object_unlock_exclusive(thisObject);
92
93    // Note that the mutex is unlocked during the callback
94    if (NULL != callback) {
95        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
96        (*callback)(&this->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
97    }
98
99}
100
101
102static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,
103    const SLInterfaceID iid, SLboolean async)
104{
105    SL_ENTER_INTERFACE
106
107    // validate input parameters
108    if (NULL == iid) {
109        result = SL_RESULT_PARAMETER_INVALID;
110    } else {
111        IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
112        IObject *thisObject = InterfaceToIObject(this);
113        const ClassTable *class__ = thisObject->mClass;
114        int MPH, index;
115        if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH]))) {
116            result = SL_RESULT_FEATURE_UNSUPPORTED;
117        } else {
118            assert(index < (int) class__->mInterfaceCount);
119            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
120
121            // check interface state
122            object_lock_exclusive(thisObject);
123            switch (*interfaceStateP) {
124
125            case INTERFACE_UNINITIALIZED:   // normal case
126                if (async) {
127                    // Asynchronous: mark operation pending and cancellable
128                    *interfaceStateP = INTERFACE_ADDING_1;
129                    object_unlock_exclusive(thisObject);
130
131                    // this section runs with mutex unlocked
132                    result = ThreadPool_add(&thisObject->mEngine->mThreadPool, HandleAdd, this,
133                        MPH);
134                    if (SL_RESULT_SUCCESS != result) {
135                        // Engine was destroyed during add, or insufficient memory,
136                        // so restore mInterfaceStates state to prior value
137                        object_lock_exclusive(thisObject);
138                        switch (*interfaceStateP) {
139                        case INTERFACE_ADDING_1:    // normal
140                        case INTERFACE_ADDING_1A:   // operation aborted while mutex unlocked
141                            *interfaceStateP = INTERFACE_UNINITIALIZED;
142                            break;
143                        default:                    // unexpected
144                            // leave state alone
145                            break;
146                        }
147                    }
148
149                } else {
150                    // Synchronous: mark operation pending to prevent duplication
151                    *interfaceStateP = INTERFACE_ADDING_2;
152                    object_unlock_exclusive(thisObject);
153
154                    // this section runs with mutex unlocked
155                    const struct iid_vtable *x = &class__->mInterfaces[index];
156                    size_t offset = x->mOffset;
157                    size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
158                        class__->mSize : x[1].mOffset) - offset;
159                    void *thisItf = (char *) thisObject + offset;
160                    memset(thisItf, 0, size);
161                    // Will never add IObject, so [1] is always defined
162                    ((void **) thisItf)[1] = thisObject;
163                    VoidHook init = MPH_init_table[MPH].mInit;
164                    if (NULL != init)
165                        (*init)(thisItf);
166                    result = SL_RESULT_SUCCESS;
167
168                    // re-lock mutex to update state
169                    object_lock_exclusive(thisObject);
170                    assert(INTERFACE_ADDING_2 == *interfaceStateP);
171                    *interfaceStateP = INTERFACE_ADDED;
172                }
173
174                // mutex is still locked
175                break;
176
177            default:    // disallow adding of (partially) initialized interfaces
178                result = SL_RESULT_PRECONDITIONS_VIOLATED;
179                break;
180
181            }
182
183            object_unlock_exclusive(thisObject);
184
185        }
186    }
187
188    SL_LEAVE_INTERFACE
189}
190
191
192static SLresult IDynamicInterfaceManagement_RemoveInterface(
193    SLDynamicInterfaceManagementItf self, const SLInterfaceID iid)
194{
195    SL_ENTER_INTERFACE
196
197    // validate input parameters
198    if (NULL == iid) {
199        result = SL_RESULT_PARAMETER_INVALID;
200    } else {
201        IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
202        IObject *thisObject = InterfaceToIObject(this);
203        const ClassTable *class__ = thisObject->mClass;
204        int MPH, index;
205        if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH]))) {
206            result = SL_RESULT_PRECONDITIONS_VIOLATED;
207        } else {
208            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
209
210            // check interface state
211            object_lock_exclusive(thisObject);
212            switch (*interfaceStateP) {
213
214            case INTERFACE_ADDED:       // normal cases
215            case INTERFACE_SUSPENDED:
216                {
217                // Mark operation pending to prevent duplication
218                *interfaceStateP = INTERFACE_REMOVING;
219                thisObject->mGottenMask &= ~(1 << index);
220                object_unlock_exclusive(thisObject);
221
222                // The deinitialization is done with mutex unlocked
223                const struct iid_vtable *x = &class__->mInterfaces[index];
224                size_t offset = x->mOffset;
225                void *thisItf = (char *) thisObject + offset;
226                VoidHook deinit = MPH_init_table[MPH].mDeinit;
227                if (NULL != deinit)
228                    (*deinit)(thisItf);
229        #ifndef NDEBUG
230                size_t size = ((SLuint32) (index + 1) == class__->mInterfaceCount ?
231                    class__->mSize : x[1].mOffset) - offset;
232                memset(thisItf, 0x55, size);
233        #endif
234                result = SL_RESULT_SUCCESS;
235
236                // Note that this was previously locked, but then unlocked for the deinit hook
237                object_lock_exclusive(thisObject);
238                assert(INTERFACE_REMOVING == *interfaceStateP);
239                *interfaceStateP = INTERFACE_UNINITIALIZED;
240                }
241
242                // mutex is still locked
243                break;
244
245            default:
246                // disallow removal of non-dynamic interfaces, or interfaces which are
247                // currently being resumed (will not auto-cancel an asynchronous resume)
248                result = SL_RESULT_PRECONDITIONS_VIOLATED;
249                break;
250
251            }
252
253            object_unlock_exclusive(thisObject);
254        }
255    }
256
257    SL_LEAVE_INTERFACE
258}
259
260
261// Called by a worker thread to handle an asynchronous ResumeInterface.
262// Parameter self is the DynamicInterface, and MPH specifies which interface to resume.
263
264static void HandleResume(void *self, int MPH)
265{
266
267    // validate input parameters
268    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
269    assert(NULL != this);
270    IObject *thisObject = InterfaceToIObject(this);
271    assert(NULL != thisObject);
272    assert(0 <= MPH && MPH < MPH_MAX);
273    const ClassTable *class__ = thisObject->mClass;
274    assert(NULL != class__);
275    int index = class__->mMPH_to_index[MPH];
276    assert(0 <= index && index < (int) class__->mInterfaceCount);
277    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
278    SLresult result;
279
280    // check interface state
281    object_lock_exclusive(thisObject);
282    SLuint8 state = *interfaceStateP;
283    switch (state) {
284
285    case INTERFACE_RESUMING_1:      // normal case
286        {
287        // change state to indicate we are now resuming the interface
288        *interfaceStateP = INTERFACE_RESUMING_2;
289        object_unlock_exclusive(thisObject);
290
291        // this section runs with mutex unlocked
292        const struct iid_vtable *x = &class__->mInterfaces[index];
293        size_t offset = x->mOffset;
294        void *thisItf = (char *) thisObject + offset;
295        VoidHook resume = MPH_init_table[MPH].mResume;
296        if (NULL != resume)
297            (*resume)(thisItf);
298        result = SL_RESULT_SUCCESS;
299
300        // re-lock mutex to update state
301        object_lock_exclusive(thisObject);
302        assert(INTERFACE_RESUMING_2 == *interfaceStateP);
303        state = INTERFACE_ADDED;
304        }
305        break;
306
307    case INTERFACE_RESUMING_1A:     // operation was aborted while on work queue
308        result = SL_RESULT_OPERATION_ABORTED;
309        state = INTERFACE_SUSPENDED;
310        break;
311
312    default:                        // impossible
313        assert(SL_BOOLEAN_FALSE);
314        result = SL_RESULT_INTERNAL_ERROR;
315        break;
316
317    }
318
319    // mutex is locked, update state
320    *interfaceStateP = state;
321
322    // Make a copy of these, so we can call the callback with mutex unlocked
323    slDynamicInterfaceManagementCallback callback = this->mCallback;
324    void *context = this->mContext;
325    object_unlock_exclusive(thisObject);
326
327    // Note that the mutex is unlocked during the callback
328    if (NULL != callback) {
329        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
330        (*callback)(&this->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
331    }
332}
333
334
335static SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
336    const SLInterfaceID iid, SLboolean async)
337{
338    SL_ENTER_INTERFACE
339
340    // validate input parameters
341    if (NULL == iid) {
342        result = SL_RESULT_PARAMETER_INVALID;
343    } else {
344        IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
345        IObject *thisObject = InterfaceToIObject(this);
346        const ClassTable *class__ = thisObject->mClass;
347        int MPH, index;
348        if ((0 > (MPH = IID_to_MPH(iid))) || (0 > (index = class__->mMPH_to_index[MPH]))) {
349            result = SL_RESULT_PRECONDITIONS_VIOLATED;
350        } else {
351            assert(index < (int) class__->mInterfaceCount);
352            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
353
354            // check interface state
355            object_lock_exclusive(thisObject);
356            switch (*interfaceStateP) {
357
358            case INTERFACE_SUSPENDED:   // normal case
359                if (async) {
360                    // Asynchronous: mark operation pending and cancellable
361                    *interfaceStateP = INTERFACE_RESUMING_1;
362                    object_unlock_exclusive(thisObject);
363
364                    // this section runs with mutex unlocked
365                    result = ThreadPool_add(&thisObject->mEngine->mThreadPool, HandleResume, this,
366                        MPH);
367                    if (SL_RESULT_SUCCESS != result) {
368                        // Engine was destroyed during resume, or insufficient memory,
369                        // so restore mInterfaceStates state to prior value
370                        object_lock_exclusive(thisObject);
371                        switch (*interfaceStateP) {
372                        case INTERFACE_RESUMING_1:  // normal
373                        case INTERFACE_RESUMING_1A: // operation aborted while mutex unlocked
374                            *interfaceStateP = INTERFACE_SUSPENDED;
375                            break;
376                        default:                    // unexpected
377                            // leave state alone
378                            break;
379                        }
380                    }
381
382                } else {
383                    // Synchronous: mark operation pending to prevent duplication
384                    *interfaceStateP = INTERFACE_RESUMING_2;
385                    object_unlock_exclusive(thisObject);
386
387                    // this section runs with mutex unlocked
388                    const struct iid_vtable *x = &class__->mInterfaces[index];
389                    size_t offset = x->mOffset;
390                    void *thisItf = (char *) this + offset;
391                    VoidHook resume = MPH_init_table[MPH].mResume;
392                    if (NULL != resume)
393                        (*resume)(thisItf);
394                    result = SL_RESULT_SUCCESS;
395
396                    // re-lock mutex to update state
397                    object_lock_exclusive(thisObject);
398                    assert(INTERFACE_RESUMING_2 == *interfaceStateP);
399                    *interfaceStateP = INTERFACE_ADDED;
400                }
401
402                // mutex is now unlocked
403                break;
404
405            default:    // disallow resumption of non-suspended interfaces
406                object_unlock_exclusive(thisObject);
407                result = SL_RESULT_PRECONDITIONS_VIOLATED;
408                break;
409            }
410
411            object_unlock_exclusive(thisObject);
412        }
413    }
414
415    SL_LEAVE_INTERFACE
416}
417
418
419static SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
420    slDynamicInterfaceManagementCallback callback, void *pContext)
421{
422    SL_ENTER_INTERFACE
423
424    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
425    IObject *thisObject = InterfaceToIObject(this);
426    object_lock_exclusive(thisObject);
427    this->mCallback = callback;
428    this->mContext = pContext;
429    object_unlock_exclusive(thisObject);
430    result = SL_RESULT_SUCCESS;
431
432    SL_LEAVE_INTERFACE
433}
434
435
436static const struct SLDynamicInterfaceManagementItf_ IDynamicInterfaceManagement_Itf = {
437    IDynamicInterfaceManagement_AddInterface,
438    IDynamicInterfaceManagement_RemoveInterface,
439    IDynamicInterfaceManagement_ResumeInterface,
440    IDynamicInterfaceManagement_RegisterCallback
441};
442
443void IDynamicInterfaceManagement_init(void *self)
444{
445    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
446    this->mItf = &IDynamicInterfaceManagement_Itf;
447    this->mCallback = NULL;
448    this->mContext = NULL;
449}
450