IDynamicInterfaceManagement.c revision bcc5c7225e3b7a1dbf2e9e830987f69167acf06f
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 *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 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 *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(&thisObject->mEngine->mThreadPool, HandleAdd, thiz, 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 = &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 ((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 *thiz = (IDynamicInterfaceManagement *) self; 212 IObject *thisObject = InterfaceToIObject(thiz); 213 const ClassTable *clazz = 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 = clazz->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 = &clazz->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 *thiz = (IDynamicInterfaceManagement *) self; 287 assert(NULL != thiz); 288 IObject *thisObject = InterfaceToIObject(thiz); 289 assert(NULL != thisObject); 290 assert(0 <= MPH && MPH < MPH_MAX); 291 const ClassTable *clazz = thisObject->mClass; 292 assert(NULL != clazz); 293 int index = clazz->mMPH_to_index[MPH]; 294 assert(0 <= index && index < (int) clazz->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 = &clazz->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 = thiz->mCallback; 343 void *context = thiz->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)(&thiz->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 *thiz = (IDynamicInterfaceManagement *) self; 364 IObject *thisObject = InterfaceToIObject(thiz); 365 const ClassTable *clazz = 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 = clazz->mMPH_to_index[MPH]))) { 371 result = SL_RESULT_PRECONDITIONS_VIOLATED; 372 } else { 373 assert(index < (int) clazz->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, thiz, 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 = &clazz->mInterfaces[index]; 411 size_t offset = x->mOffset; 412 void *thisItf = (char *) thiz + 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 *thiz = (IDynamicInterfaceManagement *) self; 447 IObject *thisObject = InterfaceToIObject(thiz); 448 object_lock_exclusive(thisObject); 449 thiz->mCallback = callback; 450 thiz->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 *thiz = (IDynamicInterfaceManagement *) self; 468 thiz->mItf = &IDynamicInterfaceManagement_Itf; 469 thiz->mCallback = NULL; 470 thiz->mContext = NULL; 471} 472