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