Home | History | Annotate | Download | only in itf
      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 
     25 static void HandleAdd(void *self, void *ignored, int MPH)
     26 {
     27 
     28     // validate input parameters
     29     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
     30     assert(NULL != thiz);
     31     IObject *thisObject = InterfaceToIObject(thiz);
     32     assert(NULL != thisObject);
     33     assert(0 <= MPH && MPH < MPH_MAX);
     34     const ClassTable *clazz = thisObject->mClass;
     35     assert(NULL != clazz);
     36     int index = clazz->mMPH_to_index[MPH];
     37     assert(0 <= index && index < (int) clazz->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 = &clazz->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 = thiz->mCallback;
     93     void *context = thiz->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)(&thiz->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
    100     }
    101 
    102 }
    103 
    104 
    105 static 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 *thiz = (IDynamicInterfaceManagement *) self;
    115         IObject *thisObject = InterfaceToIObject(thiz);
    116         const ClassTable *clazz = 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 = clazz->mMPH_to_index[MPH]))) {
    122             result = SL_RESULT_FEATURE_UNSUPPORTED;
    123         } else {
    124             assert(index < (int) clazz->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_ppi(&thisObject->mEngine->mThreadPool, HandleAdd, thiz,
    139                         NULL, 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 = &clazz->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                         *interfaceStateP = INTERFACE_ADDED;
    177                     } else {
    178                         *interfaceStateP = INTERFACE_INITIALIZED;
    179                     }
    180                 }
    181 
    182                 // mutex is still locked
    183                 break;
    184 
    185             default:    // disallow adding of (partially) initialized interfaces
    186                 result = SL_RESULT_PRECONDITIONS_VIOLATED;
    187                 break;
    188 
    189             }
    190 
    191             object_unlock_exclusive(thisObject);
    192 
    193         }
    194     }
    195 
    196     SL_LEAVE_INTERFACE
    197 }
    198 
    199 
    200 static SLresult IDynamicInterfaceManagement_RemoveInterface(
    201     SLDynamicInterfaceManagementItf self, const SLInterfaceID iid)
    202 {
    203     SL_ENTER_INTERFACE
    204 
    205 #if USE_PROFILES & USE_PROFILES_BASE
    206     // validate input parameters
    207     if (NULL == iid) {
    208         result = SL_RESULT_PARAMETER_INVALID;
    209     } else {
    210         IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
    211         IObject *thisObject = InterfaceToIObject(thiz);
    212         const ClassTable *clazz = thisObject->mClass;
    213         int MPH, index;
    214         if ((0 > (MPH = IID_to_MPH(iid))) ||
    215                 // no need to check for an initialization hook
    216                 // (NULL == MPH_init_table[MPH].mInit) ||
    217                 (0 > (index = clazz->mMPH_to_index[MPH]))) {
    218             result = SL_RESULT_PRECONDITIONS_VIOLATED;
    219         } else {
    220             SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
    221 
    222             // check interface state
    223             object_lock_exclusive(thisObject);
    224             switch (*interfaceStateP) {
    225 
    226             case INTERFACE_ADDED:       // normal cases
    227             case INTERFACE_SUSPENDED:
    228                 {
    229                 // Compute address of the interface
    230                 const struct iid_vtable *x = &clazz->mInterfaces[index];
    231                 size_t offset = x->mOffset;
    232                 void *thisItf = (char *) thisObject + offset;
    233 
    234                 // Mark operation pending (not necessary; remove is synchronous with mutex locked)
    235                 *interfaceStateP = INTERFACE_REMOVING;
    236 
    237                 // Check if application ever called Object::GetInterface
    238                 unsigned mask = 1 << index;
    239                 if (thisObject->mGottenMask & mask) {
    240                     thisObject->mGottenMask &= ~mask;
    241                     // This trickery invalidates the v-table
    242                     ((size_t *) thisItf)[0] ^= ~0;
    243                 }
    244 
    245                 // The remove hook is called with mutex locked
    246                 VoidHook remove = MPH_init_table[MPH].mRemove;
    247                 if (NULL != remove) {
    248                     (*remove)(thisItf);
    249                 }
    250                 result = SL_RESULT_SUCCESS;
    251 
    252                 assert(INTERFACE_REMOVING == *interfaceStateP);
    253                 *interfaceStateP = INTERFACE_INITIALIZED;
    254                 }
    255 
    256                 // mutex is still locked
    257                 break;
    258 
    259             default:
    260                 // disallow removal of non-dynamic interfaces, or interfaces which are
    261                 // currently being resumed (will not auto-cancel an asynchronous resume)
    262                 result = SL_RESULT_PRECONDITIONS_VIOLATED;
    263                 break;
    264 
    265             }
    266 
    267             object_unlock_exclusive(thisObject);
    268         }
    269     }
    270 #else
    271     result = SL_RESULT_FEATURE_UNSUPPORTED;
    272 #endif
    273 
    274     SL_LEAVE_INTERFACE
    275 }
    276 
    277 
    278 // Called by a worker thread to handle an asynchronous ResumeInterface.
    279 // Parameter self is the DynamicInterface, and MPH specifies which interface to resume.
    280 
    281 static void HandleResume(void *self, void *ignored, int MPH)
    282 {
    283 
    284     // validate input parameters
    285     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
    286     assert(NULL != thiz);
    287     IObject *thisObject = InterfaceToIObject(thiz);
    288     assert(NULL != thisObject);
    289     assert(0 <= MPH && MPH < MPH_MAX);
    290     const ClassTable *clazz = thisObject->mClass;
    291     assert(NULL != clazz);
    292     int index = clazz->mMPH_to_index[MPH];
    293     assert(0 <= index && index < (int) clazz->mInterfaceCount);
    294     SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
    295     SLresult result;
    296 
    297     // check interface state
    298     object_lock_exclusive(thisObject);
    299     SLuint8 state = *interfaceStateP;
    300     switch (state) {
    301 
    302     case INTERFACE_RESUMING_1:      // normal case
    303         {
    304         // change state to indicate we are now resuming the interface
    305         *interfaceStateP = INTERFACE_RESUMING_2;
    306         object_unlock_exclusive(thisObject);
    307 
    308         // this section runs with mutex unlocked
    309         const struct iid_vtable *x = &clazz->mInterfaces[index];
    310         size_t offset = x->mOffset;
    311         void *thisItf = (char *) thisObject + offset;
    312         VoidHook resume = MPH_init_table[MPH].mResume;
    313         if (NULL != resume) {
    314             (*resume)(thisItf);
    315         }
    316         result = SL_RESULT_SUCCESS;
    317 
    318         // re-lock mutex to update state
    319         object_lock_exclusive(thisObject);
    320         assert(INTERFACE_RESUMING_2 == *interfaceStateP);
    321         state = INTERFACE_ADDED;
    322         }
    323         break;
    324 
    325     case INTERFACE_RESUMING_1A:     // operation was aborted while on work queue
    326         result = SL_RESULT_OPERATION_ABORTED;
    327         state = INTERFACE_SUSPENDED;
    328         break;
    329 
    330     default:                        // impossible
    331         assert(SL_BOOLEAN_FALSE);
    332         result = SL_RESULT_INTERNAL_ERROR;
    333         break;
    334 
    335     }
    336 
    337     // mutex is locked, update state
    338     *interfaceStateP = state;
    339 
    340     // Make a copy of these, so we can call the callback with mutex unlocked
    341     slDynamicInterfaceManagementCallback callback = thiz->mCallback;
    342     void *context = thiz->mContext;
    343     object_unlock_exclusive(thisObject);
    344 
    345     // Note that the mutex is unlocked during the callback
    346     if (NULL != callback) {
    347         const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
    348         (*callback)(&thiz->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
    349     }
    350 }
    351 
    352 
    353 static SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
    354     const SLInterfaceID iid, SLboolean async)
    355 {
    356     SL_ENTER_INTERFACE
    357 
    358     // validate input parameters
    359     if (NULL == iid) {
    360         result = SL_RESULT_PARAMETER_INVALID;
    361     } else {
    362         IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
    363         IObject *thisObject = InterfaceToIObject(thiz);
    364         const ClassTable *clazz = thisObject->mClass;
    365         int MPH, index;
    366         if ((0 > (MPH = IID_to_MPH(iid))) ||
    367                 // no need to check for an initialization hook
    368                 // (NULL == MPH_init_table[MPH].mInit) ||
    369                 (0 > (index = clazz->mMPH_to_index[MPH]))) {
    370             result = SL_RESULT_PRECONDITIONS_VIOLATED;
    371         } else {
    372             assert(index < (int) clazz->mInterfaceCount);
    373             SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
    374 
    375             // check interface state
    376             object_lock_exclusive(thisObject);
    377             switch (*interfaceStateP) {
    378 
    379             case INTERFACE_SUSPENDED:   // normal case
    380                 if (async) {
    381                     // Asynchronous: mark operation pending and cancellable
    382                     *interfaceStateP = INTERFACE_RESUMING_1;
    383                     object_unlock_exclusive(thisObject);
    384 
    385                     // this section runs with mutex unlocked
    386                     result = ThreadPool_add_ppi(&thisObject->mEngine->mThreadPool, HandleResume,
    387                         thiz, NULL, MPH);
    388                     if (SL_RESULT_SUCCESS != result) {
    389                         // Engine was destroyed during resume, or insufficient memory,
    390                         // so restore mInterfaceStates state to prior value
    391                         object_lock_exclusive(thisObject);
    392                         switch (*interfaceStateP) {
    393                         case INTERFACE_RESUMING_1:  // normal
    394                         case INTERFACE_RESUMING_1A: // operation aborted while mutex unlocked
    395                             *interfaceStateP = INTERFACE_SUSPENDED;
    396                             break;
    397                         default:                    // unexpected
    398                             // leave state alone
    399                             break;
    400                         }
    401                     }
    402 
    403                 } else {
    404                     // Synchronous: mark operation pending to prevent duplication
    405                     *interfaceStateP = INTERFACE_RESUMING_2;
    406                     object_unlock_exclusive(thisObject);
    407 
    408                     // this section runs with mutex unlocked
    409                     const struct iid_vtable *x = &clazz->mInterfaces[index];
    410                     size_t offset = x->mOffset;
    411                     void *thisItf = (char *) thiz + offset;
    412                     VoidHook resume = MPH_init_table[MPH].mResume;
    413                     if (NULL != resume) {
    414                         (*resume)(thisItf);
    415                     }
    416                     result = SL_RESULT_SUCCESS;
    417 
    418                     // re-lock mutex to update state
    419                     object_lock_exclusive(thisObject);
    420                     assert(INTERFACE_RESUMING_2 == *interfaceStateP);
    421                     *interfaceStateP = INTERFACE_ADDED;
    422                 }
    423 
    424                 // mutex is now locked
    425                 break;
    426 
    427             default:    // disallow resumption of non-suspended interfaces
    428                 result = SL_RESULT_PRECONDITIONS_VIOLATED;
    429                 break;
    430             }
    431 
    432             object_unlock_exclusive(thisObject);
    433         }
    434     }
    435 
    436     SL_LEAVE_INTERFACE
    437 }
    438 
    439 
    440 static SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
    441     slDynamicInterfaceManagementCallback callback, void *pContext)
    442 {
    443     SL_ENTER_INTERFACE
    444 
    445     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
    446     IObject *thisObject = InterfaceToIObject(thiz);
    447     object_lock_exclusive(thisObject);
    448     thiz->mCallback = callback;
    449     thiz->mContext = pContext;
    450     object_unlock_exclusive(thisObject);
    451     result = SL_RESULT_SUCCESS;
    452 
    453     SL_LEAVE_INTERFACE
    454 }
    455 
    456 
    457 static const struct SLDynamicInterfaceManagementItf_ IDynamicInterfaceManagement_Itf = {
    458     IDynamicInterfaceManagement_AddInterface,
    459     IDynamicInterfaceManagement_RemoveInterface,
    460     IDynamicInterfaceManagement_ResumeInterface,
    461     IDynamicInterfaceManagement_RegisterCallback
    462 };
    463 
    464 void IDynamicInterfaceManagement_init(void *self)
    465 {
    466     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
    467     thiz->mItf = &IDynamicInterfaceManagement_Itf;
    468     thiz->mCallback = NULL;
    469     thiz->mContext = NULL;
    470 }
    471