IDynamicInterfaceManagement.c revision 262059f71a68edc5e510427c63f5f1623d3672a8
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        BoolHook expose = MPH_init_table[MPH].mExpose;
57        // call the optional expose hook
58        if ((NULL == expose) || (*expose)(thisItf)) {
59            result = SL_RESULT_SUCCESS;
60        } else {
61            result = SL_RESULT_FEATURE_UNSUPPORTED;
62        }
63
64        // re-lock mutex to update state
65        object_lock_exclusive(thisObject);
66        assert(INTERFACE_ADDING_2 == *interfaceStateP);
67        if (SL_RESULT_SUCCESS == result) {
68            ((size_t *) thisItf)[0] ^= ~0;
69            state = INTERFACE_ADDED;
70        } else {
71            state = INTERFACE_INITIALIZED;
72        }
73        }
74        break;
75
76    case INTERFACE_ADDING_1A:   // operation was aborted while on work queue
77        result = SL_RESULT_OPERATION_ABORTED;
78        state = INTERFACE_INITIALIZED;
79        break;
80
81    default:                    // impossible
82        assert(SL_BOOLEAN_FALSE);
83        result = SL_RESULT_INTERNAL_ERROR;
84        break;
85
86    }
87
88    // mutex is locked, update state
89    *interfaceStateP = state;
90
91    // Make a copy of these, so we can call the callback with mutex unlocked
92    slDynamicInterfaceManagementCallback callback = this->mCallback;
93    void *context = this->mContext;
94    object_unlock_exclusive(thisObject);
95
96    // Note that the mutex is unlocked during the callback
97    if (NULL != callback) {
98        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
99        (*callback)(&this->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
100    }
101
102}
103
104
105static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,
106    const SLInterfaceID iid, SLboolean async)
107{
108    SL_ENTER_INTERFACE
109
110    // validate input parameters
111    if (NULL == iid) {
112        result = SL_RESULT_PARAMETER_INVALID;
113    } else {
114        IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
115        IObject *thisObject = InterfaceToIObject(this);
116        const ClassTable *class__ = thisObject->mClass;
117        int MPH, index;
118        if ((0 > (MPH = IID_to_MPH(iid))) ||
119                // no need to check for an initialization hook
120                // (NULL == MPH_init_table[MPH].mInit) ||
121                (0 > (index = class__->mMPH_to_index[MPH]))) {
122            result = SL_RESULT_FEATURE_UNSUPPORTED;
123        } else {
124            assert(index < (int) class__->mInterfaceCount);
125            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
126
127            // check interface state
128            object_lock_exclusive(thisObject);
129            switch (*interfaceStateP) {
130
131            case INTERFACE_INITIALIZED: // normal case
132                if (async) {
133                    // Asynchronous: mark operation pending and cancellable
134                    *interfaceStateP = INTERFACE_ADDING_1;
135                    object_unlock_exclusive(thisObject);
136
137                    // this section runs with mutex unlocked
138                    result = ThreadPool_add(&thisObject->mEngine->mThreadPool, HandleAdd, this,
139                        MPH);
140                    if (SL_RESULT_SUCCESS != result) {
141                        // Engine was destroyed during add, or insufficient memory,
142                        // so restore mInterfaceStates state to prior value
143                        object_lock_exclusive(thisObject);
144                        switch (*interfaceStateP) {
145                        case INTERFACE_ADDING_1:    // normal
146                        case INTERFACE_ADDING_1A:   // operation aborted while mutex unlocked
147                            *interfaceStateP = INTERFACE_INITIALIZED;
148                            break;
149                        default:                    // unexpected
150                            // leave state alone
151                            break;
152                        }
153                    }
154
155                } else {
156                    // Synchronous: mark operation pending to prevent duplication
157                    *interfaceStateP = INTERFACE_ADDING_2;
158                    object_unlock_exclusive(thisObject);
159
160                    // this section runs with mutex unlocked
161                    const struct iid_vtable *x = &class__->mInterfaces[index];
162                    size_t offset = x->mOffset;
163                    void *thisItf = (char *) thisObject + offset;
164                    // call the optional expose hook
165                    BoolHook expose = MPH_init_table[MPH].mExpose;
166                    if ((NULL == expose) || (*expose)(thisItf)) {
167                        result = SL_RESULT_SUCCESS;
168                    } else {
169                        result = SL_RESULT_FEATURE_UNSUPPORTED;
170                    }
171
172                    // re-lock mutex to update state
173                    object_lock_exclusive(thisObject);
174                    assert(INTERFACE_ADDING_2 == *interfaceStateP);
175                    if (SL_RESULT_SUCCESS == result) {
176                        ((size_t *) thisItf)[0] ^= ~0;
177                        *interfaceStateP = INTERFACE_ADDED;
178                    } else {
179                        *interfaceStateP = INTERFACE_INITIALIZED;
180                    }
181                }
182
183                // mutex is still locked
184                break;
185
186            default:    // disallow adding of (partially) initialized interfaces
187                result = SL_RESULT_PRECONDITIONS_VIOLATED;
188                break;
189
190            }
191
192            object_unlock_exclusive(thisObject);
193
194        }
195    }
196
197    SL_LEAVE_INTERFACE
198}
199
200
201static SLresult IDynamicInterfaceManagement_RemoveInterface(
202    SLDynamicInterfaceManagementItf self, const SLInterfaceID iid)
203{
204    SL_ENTER_INTERFACE
205
206#if USE_PROFILES & USE_PROFILES_BASE
207    // validate input parameters
208    if (NULL == iid) {
209        result = SL_RESULT_PARAMETER_INVALID;
210    } else {
211        IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
212        IObject *thisObject = InterfaceToIObject(this);
213        const ClassTable *class__ = thisObject->mClass;
214        int MPH, index;
215        if ((0 > (MPH = IID_to_MPH(iid))) ||
216                // no need to check for an initialization hook
217                // (NULL == MPH_init_table[MPH].mInit) ||
218                (0 > (index = class__->mMPH_to_index[MPH]))) {
219            result = SL_RESULT_PRECONDITIONS_VIOLATED;
220        } else {
221            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
222
223            // check interface state
224            object_lock_exclusive(thisObject);
225            switch (*interfaceStateP) {
226
227            case INTERFACE_ADDED:       // normal cases
228            case INTERFACE_SUSPENDED:
229                {
230                // Compute address of the interface
231                const struct iid_vtable *x = &class__->mInterfaces[index];
232                size_t offset = x->mOffset;
233                void *thisItf = (char *) thisObject + offset;
234
235                // Mark operation pending (not necessary; remove is synchronous with mutex locked)
236                *interfaceStateP = INTERFACE_REMOVING;
237
238                // Check if application ever called Object::GetInterface
239                unsigned mask = 1 << index;
240                if (thisObject->mGottenMask & mask) {
241                    thisObject->mGottenMask &= ~mask;
242                    // This trickery invalidates the v-table
243                    ((size_t *) thisItf)[0] ^= ~0;
244                }
245
246                // The remove hook is called with mutex locked
247                VoidHook remove = MPH_init_table[MPH].mRemove;
248                if (NULL != remove) {
249                    (*remove)(thisItf);
250                }
251                result = SL_RESULT_SUCCESS;
252
253                assert(INTERFACE_REMOVING == *interfaceStateP);
254                *interfaceStateP = INTERFACE_INITIALIZED;
255                }
256
257                // mutex is still locked
258                break;
259
260            default:
261                // disallow removal of non-dynamic interfaces, or interfaces which are
262                // currently being resumed (will not auto-cancel an asynchronous resume)
263                result = SL_RESULT_PRECONDITIONS_VIOLATED;
264                break;
265
266            }
267
268            object_unlock_exclusive(thisObject);
269        }
270    }
271#else
272    result = SL_RESULT_FEATURE_UNSUPPORTED;
273#endif
274
275    SL_LEAVE_INTERFACE
276}
277
278
279// Called by a worker thread to handle an asynchronous ResumeInterface.
280// Parameter self is the DynamicInterface, and MPH specifies which interface to resume.
281
282static void HandleResume(void *self, int MPH)
283{
284
285    // validate input parameters
286    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
287    assert(NULL != this);
288    IObject *thisObject = InterfaceToIObject(this);
289    assert(NULL != thisObject);
290    assert(0 <= MPH && MPH < MPH_MAX);
291    const ClassTable *class__ = thisObject->mClass;
292    assert(NULL != class__);
293    int index = class__->mMPH_to_index[MPH];
294    assert(0 <= index && index < (int) class__->mInterfaceCount);
295    SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
296    SLresult result;
297
298    // check interface state
299    object_lock_exclusive(thisObject);
300    SLuint8 state = *interfaceStateP;
301    switch (state) {
302
303    case INTERFACE_RESUMING_1:      // normal case
304        {
305        // change state to indicate we are now resuming the interface
306        *interfaceStateP = INTERFACE_RESUMING_2;
307        object_unlock_exclusive(thisObject);
308
309        // this section runs with mutex unlocked
310        const struct iid_vtable *x = &class__->mInterfaces[index];
311        size_t offset = x->mOffset;
312        void *thisItf = (char *) thisObject + offset;
313        VoidHook resume = MPH_init_table[MPH].mResume;
314        if (NULL != resume) {
315            (*resume)(thisItf);
316        }
317        result = SL_RESULT_SUCCESS;
318
319        // re-lock mutex to update state
320        object_lock_exclusive(thisObject);
321        assert(INTERFACE_RESUMING_2 == *interfaceStateP);
322        state = INTERFACE_ADDED;
323        }
324        break;
325
326    case INTERFACE_RESUMING_1A:     // operation was aborted while on work queue
327        result = SL_RESULT_OPERATION_ABORTED;
328        state = INTERFACE_SUSPENDED;
329        break;
330
331    default:                        // impossible
332        assert(SL_BOOLEAN_FALSE);
333        result = SL_RESULT_INTERNAL_ERROR;
334        break;
335
336    }
337
338    // mutex is locked, update state
339    *interfaceStateP = state;
340
341    // Make a copy of these, so we can call the callback with mutex unlocked
342    slDynamicInterfaceManagementCallback callback = this->mCallback;
343    void *context = this->mContext;
344    object_unlock_exclusive(thisObject);
345
346    // Note that the mutex is unlocked during the callback
347    if (NULL != callback) {
348        const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
349        (*callback)(&this->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
350    }
351}
352
353
354static SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
355    const SLInterfaceID iid, SLboolean async)
356{
357    SL_ENTER_INTERFACE
358
359    // validate input parameters
360    if (NULL == iid) {
361        result = SL_RESULT_PARAMETER_INVALID;
362    } else {
363        IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
364        IObject *thisObject = InterfaceToIObject(this);
365        const ClassTable *class__ = thisObject->mClass;
366        int MPH, index;
367        if ((0 > (MPH = IID_to_MPH(iid))) ||
368                // no need to check for an initialization hook
369                // (NULL == MPH_init_table[MPH].mInit) ||
370                (0 > (index = class__->mMPH_to_index[MPH]))) {
371            result = SL_RESULT_PRECONDITIONS_VIOLATED;
372        } else {
373            assert(index < (int) class__->mInterfaceCount);
374            SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
375
376            // check interface state
377            object_lock_exclusive(thisObject);
378            switch (*interfaceStateP) {
379
380            case INTERFACE_SUSPENDED:   // normal case
381                if (async) {
382                    // Asynchronous: mark operation pending and cancellable
383                    *interfaceStateP = INTERFACE_RESUMING_1;
384                    object_unlock_exclusive(thisObject);
385
386                    // this section runs with mutex unlocked
387                    result = ThreadPool_add(&thisObject->mEngine->mThreadPool, HandleResume, this,
388                        MPH);
389                    if (SL_RESULT_SUCCESS != result) {
390                        // Engine was destroyed during resume, or insufficient memory,
391                        // so restore mInterfaceStates state to prior value
392                        object_lock_exclusive(thisObject);
393                        switch (*interfaceStateP) {
394                        case INTERFACE_RESUMING_1:  // normal
395                        case INTERFACE_RESUMING_1A: // operation aborted while mutex unlocked
396                            *interfaceStateP = INTERFACE_SUSPENDED;
397                            break;
398                        default:                    // unexpected
399                            // leave state alone
400                            break;
401                        }
402                    }
403
404                } else {
405                    // Synchronous: mark operation pending to prevent duplication
406                    *interfaceStateP = INTERFACE_RESUMING_2;
407                    object_unlock_exclusive(thisObject);
408
409                    // this section runs with mutex unlocked
410                    const struct iid_vtable *x = &class__->mInterfaces[index];
411                    size_t offset = x->mOffset;
412                    void *thisItf = (char *) this + offset;
413                    VoidHook resume = MPH_init_table[MPH].mResume;
414                    if (NULL != resume) {
415                        (*resume)(thisItf);
416                    }
417                    result = SL_RESULT_SUCCESS;
418
419                    // re-lock mutex to update state
420                    object_lock_exclusive(thisObject);
421                    assert(INTERFACE_RESUMING_2 == *interfaceStateP);
422                    *interfaceStateP = INTERFACE_ADDED;
423                }
424
425                // mutex is now locked
426                break;
427
428            default:    // disallow resumption of non-suspended interfaces
429                result = SL_RESULT_PRECONDITIONS_VIOLATED;
430                break;
431            }
432
433            object_unlock_exclusive(thisObject);
434        }
435    }
436
437    SL_LEAVE_INTERFACE
438}
439
440
441static SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
442    slDynamicInterfaceManagementCallback callback, void *pContext)
443{
444    SL_ENTER_INTERFACE
445
446    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
447    IObject *thisObject = InterfaceToIObject(this);
448    object_lock_exclusive(thisObject);
449    this->mCallback = callback;
450    this->mContext = pContext;
451    object_unlock_exclusive(thisObject);
452    result = SL_RESULT_SUCCESS;
453
454    SL_LEAVE_INTERFACE
455}
456
457
458static const struct SLDynamicInterfaceManagementItf_ IDynamicInterfaceManagement_Itf = {
459    IDynamicInterfaceManagement_AddInterface,
460    IDynamicInterfaceManagement_RemoveInterface,
461    IDynamicInterfaceManagement_ResumeInterface,
462    IDynamicInterfaceManagement_RegisterCallback
463};
464
465void IDynamicInterfaceManagement_init(void *self)
466{
467    IDynamicInterfaceManagement *this = (IDynamicInterfaceManagement *) self;
468    this->mItf = &IDynamicInterfaceManagement_Itf;
469    this->mCallback = NULL;
470    this->mContext = NULL;
471}
472