• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /* Object implementation */
18 
19 #include "sles_allinclusive.h"
20 
21 
22 // Called by a worker thread to handle an asynchronous Object.Realize.
23 // Parameter self is the Object.
24 
HandleRealize(void * self,void * ignored,int unused)25 static void HandleRealize(void *self, void *ignored, int unused)
26 {
27 
28     // validate input parameters
29     IObject *thiz = (IObject *) self;
30     assert(NULL != thiz);
31     const ClassTable *clazz = thiz->mClass;
32     assert(NULL != clazz);
33     AsyncHook realize = clazz->mRealize;
34     SLresult result;
35     SLuint8 state;
36 
37     // check object state
38     object_lock_exclusive(thiz);
39     state = thiz->mState;
40     switch (state) {
41 
42     case SL_OBJECT_STATE_REALIZING_1:   // normal case
43         if (NULL != realize) {
44             thiz->mState = SL_OBJECT_STATE_REALIZING_2;
45             // Note that the mutex is locked on entry to and exit from the realize hook,
46             // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
47             result = (*realize)(thiz, SL_BOOLEAN_TRUE);
48             assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState);
49             state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
50                 SL_OBJECT_STATE_UNREALIZED;
51         } else {
52             result = SL_RESULT_SUCCESS;
53             state = SL_OBJECT_STATE_REALIZED;
54         }
55         break;
56 
57     case SL_OBJECT_STATE_REALIZING_1A:  // operation was aborted while on work queue
58         result = SL_RESULT_OPERATION_ABORTED;
59         state = SL_OBJECT_STATE_UNREALIZED;
60         break;
61 
62     default:                            // impossible
63         assert(SL_BOOLEAN_FALSE);
64         result = SL_RESULT_INTERNAL_ERROR;
65         break;
66 
67     }
68 
69     // mutex is locked, update state
70     thiz->mState = state;
71 
72     // Make a copy of these, so we can call the callback with mutex unlocked
73     slObjectCallback callback = thiz->mCallback;
74     void *context = thiz->mContext;
75     object_unlock_exclusive(thiz);
76 
77     // Note that the mutex is unlocked during the callback
78     if (NULL != callback) {
79         (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
80     }
81 }
82 
83 
IObject_Realize(SLObjectItf self,SLboolean async)84 static SLresult IObject_Realize(SLObjectItf self, SLboolean async)
85 {
86     SL_ENTER_INTERFACE
87 
88     IObject *thiz = (IObject *) self;
89     SLuint8 state;
90     const ClassTable *clazz = thiz->mClass;
91     bool isSharedEngine = false;
92     object_lock_exclusive(thiz);
93     // note that SL_OBJECTID_ENGINE and XA_OBJECTID_ENGINE map to same class
94     if (clazz == objectIDtoClass(SL_OBJECTID_ENGINE)) {
95         // important: the lock order is engine followed by theOneTrueMutex
96         int ok = pthread_mutex_lock(&theOneTrueMutex);
97         assert(0 == ok);
98         isSharedEngine = 1 < theOneTrueRefCount;
99         ok = pthread_mutex_unlock(&theOneTrueMutex);
100         assert(0 == ok);
101     }
102     state = thiz->mState;
103     // Reject redundant calls to Realize, except on a shared engine
104     if (SL_OBJECT_STATE_UNREALIZED != state) {
105         object_unlock_exclusive(thiz);
106         // redundant realize on the shared engine is permitted
107         if (isSharedEngine && (SL_OBJECT_STATE_REALIZED == state)) {
108             result = SL_RESULT_SUCCESS;
109         } else {
110             result = SL_RESULT_PRECONDITIONS_VIOLATED;
111         }
112     } else {
113         // Asynchronous: mark operation pending and cancellable
114         if (async && (SL_OBJECTID_ENGINE != clazz->mSLObjectID)) {
115             state = SL_OBJECT_STATE_REALIZING_1;
116         // Synchronous: mark operation pending and non-cancellable
117         } else {
118             state = SL_OBJECT_STATE_REALIZING_2;
119         }
120         thiz->mState = state;
121         switch (state) {
122         case SL_OBJECT_STATE_REALIZING_1: // asynchronous on non-Engine
123             object_unlock_exclusive(thiz);
124             assert(async);
125             result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleRealize, thiz, NULL, 0);
126             if (SL_RESULT_SUCCESS != result) {
127                 // Engine was destroyed during realize, or insufficient memory
128                 object_lock_exclusive(thiz);
129                 thiz->mState = SL_OBJECT_STATE_UNREALIZED;
130                 object_unlock_exclusive(thiz);
131             }
132             break;
133         case SL_OBJECT_STATE_REALIZING_2: // synchronous, or asynchronous on Engine
134             {
135             AsyncHook realize = clazz->mRealize;
136             // Note that the mutex is locked on entry to and exit from the realize hook,
137             // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
138             result = (NULL != realize) ? (*realize)(thiz, async) : SL_RESULT_SUCCESS;
139             assert(SL_OBJECT_STATE_REALIZING_2 == thiz->mState);
140             state = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
141                 SL_OBJECT_STATE_UNREALIZED;
142             thiz->mState = state;
143             slObjectCallback callback = thiz->mCallback;
144             void *context = thiz->mContext;
145             object_unlock_exclusive(thiz);
146             // asynchronous Realize on an Engine is actually done synchronously, but still has
147             // callback because there is no thread pool yet to do it asynchronously.
148             if (async && (NULL != callback)) {
149                 (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state,
150                     NULL);
151             }
152             }
153             break;
154         default:                          // impossible
155             object_unlock_exclusive(thiz);
156             assert(SL_BOOLEAN_FALSE);
157             break;
158         }
159     }
160 
161     SL_LEAVE_INTERFACE
162 }
163 
164 
165 // Called by a worker thread to handle an asynchronous Object.Resume.
166 // Parameter self is the Object.
167 
HandleResume(void * self,void * ignored,int unused)168 static void HandleResume(void *self, void *ignored, int unused)
169 {
170 
171     // valid input parameters
172     IObject *thiz = (IObject *) self;
173     assert(NULL != thiz);
174     const ClassTable *clazz = thiz->mClass;
175     assert(NULL != clazz);
176     AsyncHook resume = clazz->mResume;
177     SLresult result;
178     SLuint8 state;
179 
180     // check object state
181     object_lock_exclusive(thiz);
182     state = thiz->mState;
183     switch (state) {
184 
185     case SL_OBJECT_STATE_RESUMING_1:    // normal case
186         if (NULL != resume) {
187             thiz->mState = SL_OBJECT_STATE_RESUMING_2;
188             // Note that the mutex is locked on entry to and exit from the resume hook,
189             // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
190             result = (*resume)(thiz, SL_BOOLEAN_TRUE);
191             assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState);
192             state = SL_RESULT_SUCCESS == result ? SL_OBJECT_STATE_REALIZED :
193                 SL_OBJECT_STATE_SUSPENDED;
194         } else {
195             result = SL_RESULT_SUCCESS;
196             state = SL_OBJECT_STATE_REALIZED;
197         }
198         break;
199 
200     case SL_OBJECT_STATE_RESUMING_1A:   // operation was aborted while on work queue
201         result = SL_RESULT_OPERATION_ABORTED;
202         state = SL_OBJECT_STATE_SUSPENDED;
203         break;
204 
205     default:                            // impossible
206         assert(SL_BOOLEAN_FALSE);
207         result = SL_RESULT_INTERNAL_ERROR;
208         break;
209 
210     }
211 
212     // mutex is unlocked, update state
213     thiz->mState = state;
214 
215     // Make a copy of these, so we can call the callback with mutex unlocked
216     slObjectCallback callback = thiz->mCallback;
217     void *context = thiz->mContext;
218     object_unlock_exclusive(thiz);
219 
220     // Note that the mutex is unlocked during the callback
221     if (NULL != callback) {
222         (*callback)(&thiz->mItf, context, SL_OBJECT_EVENT_ASYNC_TERMINATION, result, state, NULL);
223     }
224 }
225 
226 
IObject_Resume(SLObjectItf self,SLboolean async)227 static SLresult IObject_Resume(SLObjectItf self, SLboolean async)
228 {
229     SL_ENTER_INTERFACE
230 
231     IObject *thiz = (IObject *) self;
232     const ClassTable *clazz = thiz->mClass;
233     SLuint8 state;
234     object_lock_exclusive(thiz);
235     state = thiz->mState;
236     // Reject redundant calls to Resume
237     if (SL_OBJECT_STATE_SUSPENDED != state) {
238         object_unlock_exclusive(thiz);
239         result = SL_RESULT_PRECONDITIONS_VIOLATED;
240     } else {
241         // Asynchronous: mark operation pending and cancellable
242         if (async) {
243             state = SL_OBJECT_STATE_RESUMING_1;
244         // Synchronous: mark operatio pending and non-cancellable
245         } else {
246             state = SL_OBJECT_STATE_RESUMING_2;
247         }
248         thiz->mState = state;
249         switch (state) {
250         case SL_OBJECT_STATE_RESUMING_1: // asynchronous
251             object_unlock_exclusive(thiz);
252             assert(async);
253             result = ThreadPool_add_ppi(&thiz->mEngine->mThreadPool, HandleResume, thiz, NULL, 0);
254             if (SL_RESULT_SUCCESS != result) {
255                 // Engine was destroyed during resume, or insufficient memory
256                 object_lock_exclusive(thiz);
257                 thiz->mState = SL_OBJECT_STATE_SUSPENDED;
258                 object_unlock_exclusive(thiz);
259             }
260             break;
261         case SL_OBJECT_STATE_RESUMING_2: // synchronous
262             {
263             AsyncHook resume = clazz->mResume;
264             // Note that the mutex is locked on entry to and exit from the resume hook,
265             // but the hook is permitted to temporarily unlock the mutex (e.g. for async).
266             result = (NULL != resume) ? (*resume)(thiz, SL_BOOLEAN_FALSE) : SL_RESULT_SUCCESS;
267             assert(SL_OBJECT_STATE_RESUMING_2 == thiz->mState);
268             thiz->mState = (SL_RESULT_SUCCESS == result) ? SL_OBJECT_STATE_REALIZED :
269                 SL_OBJECT_STATE_SUSPENDED;
270             object_unlock_exclusive(thiz);
271             }
272             break;
273         default:                        // impossible
274             object_unlock_exclusive(thiz);
275             assert(SL_BOOLEAN_FALSE);
276             break;
277         }
278     }
279 
280     SL_LEAVE_INTERFACE
281 }
282 
283 
IObject_GetState(SLObjectItf self,SLuint32 * pState)284 static SLresult IObject_GetState(SLObjectItf self, SLuint32 *pState)
285 {
286     SL_ENTER_INTERFACE
287 
288     if (NULL == pState) {
289         result = SL_RESULT_PARAMETER_INVALID;
290     } else {
291         IObject *thiz = (IObject *) self;
292         object_lock_shared(thiz);
293         SLuint8 state = thiz->mState;
294         object_unlock_shared(thiz);
295         // Re-map the realizing, resuming, and suspending states
296         switch (state) {
297         case SL_OBJECT_STATE_REALIZING_1:
298         case SL_OBJECT_STATE_REALIZING_1A:
299         case SL_OBJECT_STATE_REALIZING_2:
300         case SL_OBJECT_STATE_DESTROYING:    // application shouldn't call GetState after Destroy
301             state = SL_OBJECT_STATE_UNREALIZED;
302             break;
303         case SL_OBJECT_STATE_RESUMING_1:
304         case SL_OBJECT_STATE_RESUMING_1A:
305         case SL_OBJECT_STATE_RESUMING_2:
306         case SL_OBJECT_STATE_SUSPENDING:
307             state = SL_OBJECT_STATE_SUSPENDED;
308             break;
309         case SL_OBJECT_STATE_UNREALIZED:
310         case SL_OBJECT_STATE_REALIZED:
311         case SL_OBJECT_STATE_SUSPENDED:
312             // These are the "official" object states, return them as is
313             break;
314         default:
315             assert(SL_BOOLEAN_FALSE);
316             break;
317         }
318         *pState = state;
319         result = SL_RESULT_SUCCESS;
320     }
321 
322     SL_LEAVE_INTERFACE
323 }
324 
IObject_GetInterface(SLObjectItf self,const SLInterfaceID iid,void * pInterface)325 static SLresult IObject_GetInterface(SLObjectItf self, const SLInterfaceID iid, void *pInterface)
326 {
327     SL_ENTER_INTERFACE
328 
329     if (NULL == pInterface) {
330         result = SL_RESULT_PARAMETER_INVALID;
331     } else {
332         void *interface = NULL;
333         if (NULL == iid) {
334             result = SL_RESULT_PARAMETER_INVALID;
335         } else {
336             IObject *thiz = (IObject *) self;
337             const ClassTable *clazz = thiz->mClass;
338             int MPH, index;
339             if ((0 > (MPH = IID_to_MPH(iid))) ||
340                     // no need to check for an initialization hook
341                     // (NULL == MPH_init_table[MPH].mInit) ||
342                     (0 > (index = clazz->mMPH_to_index[MPH]))) {
343                 result = SL_RESULT_FEATURE_UNSUPPORTED;
344             } else {
345                 unsigned mask = 1 << index;
346                 object_lock_exclusive(thiz);
347                 if ((SL_OBJECT_STATE_REALIZED != thiz->mState) &&
348                         !(INTERFACE_PREREALIZE & clazz->mInterfaces[index].mInterface)) {
349                     // Can't get interface on an unrealized object unless pre-realize is ok
350                     result = SL_RESULT_PRECONDITIONS_VIOLATED;
351                 } else if ((MPH_MUTESOLO == MPH) && (SL_OBJECTID_AUDIOPLAYER ==
352                         clazz->mSLObjectID) && (1 == ((CAudioPlayer *) thiz)->mNumChannels)) {
353                     // Can't get the MuteSolo interface of an audio player if the channel count is
354                     // mono, but _can_ get the MuteSolo interface if the channel count is unknown
355                     result = SL_RESULT_FEATURE_UNSUPPORTED;
356                 } else {
357                     switch (thiz->mInterfaceStates[index]) {
358                     case INTERFACE_EXPOSED:
359                     case INTERFACE_ADDED:
360                         interface = (char *) thiz + clazz->mInterfaces[index].mOffset;
361                         // Note that interface has been gotten,
362                         // for debugger and to detect incorrect use of interfaces
363                         if (!(thiz->mGottenMask & mask)) {
364                             thiz->mGottenMask |= mask;
365                             // This trickery validates the v-table
366                             ((size_t *) interface)[0] ^= ~0;
367                         }
368                         result = SL_RESULT_SUCCESS;
369                         break;
370                     // Can't get interface if uninitialized, initialized, suspended,
371                     // suspending, resuming, adding, or removing
372                     default:
373                         result = SL_RESULT_FEATURE_UNSUPPORTED;
374                         break;
375                     }
376                 }
377                 object_unlock_exclusive(thiz);
378             }
379         }
380         *(void **)pInterface = interface;
381     }
382 
383     SL_LEAVE_INTERFACE
384 }
385 
386 
IObject_RegisterCallback(SLObjectItf self,slObjectCallback callback,void * pContext)387 static SLresult IObject_RegisterCallback(SLObjectItf self,
388     slObjectCallback callback, void *pContext)
389 {
390     SL_ENTER_INTERFACE
391 
392     IObject *thiz = (IObject *) self;
393     object_lock_exclusive(thiz);
394     thiz->mCallback = callback;
395     thiz->mContext = pContext;
396     object_unlock_exclusive(thiz);
397     result = SL_RESULT_SUCCESS;
398 
399     SL_LEAVE_INTERFACE
400 }
401 
402 
403 /** \brief This is internal common code for Abort and Destroy.
404  *  Note: called with mutex unlocked, and returns with mutex locked.
405  */
406 
Abort_internal(IObject * thiz)407 static void Abort_internal(IObject *thiz)
408 {
409     const ClassTable *clazz = thiz->mClass;
410     bool anyAsync = false;
411     object_lock_exclusive(thiz);
412 
413     // Abort asynchronous operations on the object
414     switch (thiz->mState) {
415     case SL_OBJECT_STATE_REALIZING_1:   // Realize
416         thiz->mState = SL_OBJECT_STATE_REALIZING_1A;
417         anyAsync = true;
418         break;
419     case SL_OBJECT_STATE_RESUMING_1:    // Resume
420         thiz->mState = SL_OBJECT_STATE_RESUMING_1A;
421         anyAsync = true;
422         break;
423     case SL_OBJECT_STATE_REALIZING_1A:  // Realize
424     case SL_OBJECT_STATE_REALIZING_2:
425     case SL_OBJECT_STATE_RESUMING_1A:   // Resume
426     case SL_OBJECT_STATE_RESUMING_2:
427         anyAsync = true;
428         break;
429     case SL_OBJECT_STATE_DESTROYING:
430         assert(false);
431         break;
432     default:
433         break;
434     }
435 
436     // Abort asynchronous operations on interfaces
437     SLuint8 *interfaceStateP = thiz->mInterfaceStates;
438     unsigned index;
439     for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) {
440         switch (*interfaceStateP) {
441         case INTERFACE_ADDING_1:    // AddInterface
442             *interfaceStateP = INTERFACE_ADDING_1A;
443             anyAsync = true;
444             break;
445         case INTERFACE_RESUMING_1:  // ResumeInterface
446             *interfaceStateP = INTERFACE_RESUMING_1A;
447             anyAsync = true;
448             break;
449         case INTERFACE_ADDING_1A:   // AddInterface
450         case INTERFACE_ADDING_2:
451         case INTERFACE_RESUMING_1A: // ResumeInterface
452         case INTERFACE_RESUMING_2:
453         case INTERFACE_REMOVING:    // not observable: RemoveInterface is synchronous & mutex locked
454             anyAsync = true;
455             break;
456         default:
457             break;
458         }
459     }
460 
461     // Wait until all asynchronous operations either complete normally or recognize the abort
462     while (anyAsync) {
463         object_unlock_exclusive(thiz);
464         // FIXME should use condition variable instead of polling
465         usleep(20000);
466         anyAsync = false;
467         object_lock_exclusive(thiz);
468         switch (thiz->mState) {
469         case SL_OBJECT_STATE_REALIZING_1:   // state 1 means it cycled during the usleep window
470         case SL_OBJECT_STATE_RESUMING_1:
471         case SL_OBJECT_STATE_REALIZING_1A:
472         case SL_OBJECT_STATE_REALIZING_2:
473         case SL_OBJECT_STATE_RESUMING_1A:
474         case SL_OBJECT_STATE_RESUMING_2:
475             anyAsync = true;
476             break;
477         case SL_OBJECT_STATE_DESTROYING:
478             assert(false);
479             break;
480         default:
481             break;
482         }
483         interfaceStateP = thiz->mInterfaceStates;
484         for (index = 0; index < clazz->mInterfaceCount; ++index, ++interfaceStateP) {
485             switch (*interfaceStateP) {
486             case INTERFACE_ADDING_1:    // state 1 means it cycled during the usleep window
487             case INTERFACE_RESUMING_1:
488             case INTERFACE_ADDING_1A:
489             case INTERFACE_ADDING_2:
490             case INTERFACE_RESUMING_1A:
491             case INTERFACE_RESUMING_2:
492             case INTERFACE_REMOVING:
493                 anyAsync = true;
494                 break;
495             default:
496                 break;
497             }
498         }
499     }
500 
501     // At this point there are no pending asynchronous operations
502 }
503 
504 
IObject_AbortAsyncOperation(SLObjectItf self)505 static void IObject_AbortAsyncOperation(SLObjectItf self)
506 {
507     SL_ENTER_INTERFACE_VOID
508 
509     IObject *thiz = (IObject *) self;
510     Abort_internal(thiz);
511     object_unlock_exclusive(thiz);
512 
513     SL_LEAVE_INTERFACE_VOID
514 }
515 
516 
IObject_Destroy(SLObjectItf self)517 void IObject_Destroy(SLObjectItf self)
518 {
519     SL_ENTER_INTERFACE_VOID
520 
521     IObject *thiz = (IObject *) self;
522     // mutex is unlocked
523     Abort_internal(thiz);
524     // mutex is locked
525     const ClassTable *clazz = thiz->mClass;
526     PreDestroyHook preDestroy = clazz->mPreDestroy;
527     // The pre-destroy hook is called with mutex locked, and should block until it is safe to
528     // destroy.  It is OK to unlock the mutex temporarily, as it long as it re-locks the mutex
529     // before returning.
530     if (NULL != preDestroy) {
531         predestroy_t okToDestroy = (*preDestroy)(thiz);
532         switch (okToDestroy) {
533         case predestroy_ok:
534             break;
535         case predestroy_error:
536             SL_LOGE("Object::Destroy(%p) not allowed", thiz);
537             FALLTHROUGH_INTENDED;
538         case predestroy_again:
539             object_unlock_exclusive(thiz);
540             // unfortunately Destroy doesn't return a result
541             SL_LEAVE_INTERFACE_VOID
542             // unreachable
543         default:
544             assert(false);
545             break;
546         }
547     }
548     thiz->mState = SL_OBJECT_STATE_DESTROYING;
549     VoidHook destroy = clazz->mDestroy;
550     // const, no lock needed
551     IEngine *thisEngine = &thiz->mEngine->mEngine;
552     unsigned i = thiz->mInstanceID;
553     assert(MAX_INSTANCE >= i);
554     // avoid a recursive lock on the engine when destroying the engine itself
555     if (thisEngine->mThis != thiz) {
556         interface_lock_exclusive(thisEngine);
557     }
558     // An unpublished object has a slot reserved, but the ID hasn't been chosen yet
559     assert(0 < thisEngine->mInstanceCount);
560     --thisEngine->mInstanceCount;
561     // If object is published, then remove it from exposure to sync thread and debugger
562     if (0 != i) {
563         --i;
564         unsigned mask = 1 << i;
565         assert(thisEngine->mInstanceMask & mask);
566         thisEngine->mInstanceMask &= ~mask;
567         assert(thisEngine->mInstances[i] == thiz);
568         thisEngine->mInstances[i] = NULL;
569     }
570     // avoid a recursive unlock on the engine when destroying the engine itself
571     if (thisEngine->mThis != thiz) {
572         interface_unlock_exclusive(thisEngine);
573     }
574     // The destroy hook is called with mutex locked
575     if (NULL != destroy) {
576         (*destroy)(thiz);
577     }
578     // Call the deinitializer for each currently initialized interface,
579     // whether it is implicit, explicit, optional, or dynamically added.
580     // The deinitializers are called in the reverse order that the
581     // initializers were called, so that IObject_deinit is called last.
582     unsigned index = clazz->mInterfaceCount;
583     const struct iid_vtable *x = &clazz->mInterfaces[index];
584     SLuint8 *interfaceStateP = &thiz->mInterfaceStates[index];
585     for ( ; index > 0; --index) {
586         --x;
587         size_t offset = x->mOffset;
588         void *thisItf = (char *) thiz + offset;
589         SLuint32 state = *--interfaceStateP;
590         switch (state) {
591         case INTERFACE_UNINITIALIZED:
592             break;
593         case INTERFACE_EXPOSED:     // quiescent states
594         case INTERFACE_ADDED:
595         case INTERFACE_SUSPENDED:
596             // The remove hook is called with mutex locked
597             {
598             VoidHook remove = MPH_init_table[x->mMPH].mRemove;
599             if (NULL != remove) {
600                 (*remove)(thisItf);
601             }
602             *interfaceStateP = INTERFACE_INITIALIZED;
603             }
604             FALLTHROUGH_INTENDED;
605         case INTERFACE_INITIALIZED:
606             {
607             VoidHook deinit = MPH_init_table[x->mMPH].mDeinit;
608             if (NULL != deinit) {
609                 (*deinit)(thisItf);
610             }
611             *interfaceStateP = INTERFACE_UNINITIALIZED;
612             }
613             break;
614         case INTERFACE_ADDING_1:    // active states indicate incorrect use of API
615         case INTERFACE_ADDING_1A:
616         case INTERFACE_ADDING_2:
617         case INTERFACE_RESUMING_1:
618         case INTERFACE_RESUMING_1A:
619         case INTERFACE_RESUMING_2:
620         case INTERFACE_REMOVING:
621         case INTERFACE_SUSPENDING:
622             SL_LOGE("Object::Destroy(%p) while interface %u active", thiz, index);
623             break;
624         default:
625             assert(SL_BOOLEAN_FALSE);
626             break;
627         }
628     }
629     // The mutex is unlocked and destroyed by IObject_deinit, which is the last deinitializer
630     memset(thiz, 0x55, clazz->mSize); // catch broken applications that continue using interfaces
631                                         // was ifdef USE_DEBUG but safer to do this unconditionally
632     if (SL_OBJECTID_ENGINE == clazz->mSLObjectID) {
633         CEngine_Destroyed((CEngine *) thiz);
634     }
635     free(thiz);
636 
637     SL_LEAVE_INTERFACE_VOID
638 }
639 
640 
IObject_SetPriority(SLObjectItf self,SLint32 priority,SLboolean preemptable)641 static SLresult IObject_SetPriority(SLObjectItf self, SLint32 priority, SLboolean preemptable)
642 {
643     SL_ENTER_INTERFACE
644 
645 #if USE_PROFILES & USE_PROFILES_BASE
646     IObject *thiz = (IObject *) self;
647     object_lock_exclusive(thiz);
648     thiz->mPriority = priority;
649     thiz->mPreemptable = SL_BOOLEAN_FALSE != preemptable; // normalize
650     object_unlock_exclusive(thiz);
651     result = SL_RESULT_SUCCESS;
652 #else
653     result = SL_RESULT_FEATURE_UNSUPPORTED;
654 #endif
655 
656     SL_LEAVE_INTERFACE
657 }
658 
659 
IObject_GetPriority(SLObjectItf self,SLint32 * pPriority,SLboolean * pPreemptable)660 static SLresult IObject_GetPriority(SLObjectItf self, SLint32 *pPriority, SLboolean *pPreemptable)
661 {
662     SL_ENTER_INTERFACE
663 
664 #if USE_PROFILES & USE_PROFILES_BASE
665     if (NULL == pPriority || NULL == pPreemptable) {
666         result = SL_RESULT_PARAMETER_INVALID;
667     } else {
668         IObject *thiz = (IObject *) self;
669         object_lock_shared(thiz);
670         SLint32 priority = thiz->mPriority;
671         SLboolean preemptable = thiz->mPreemptable;
672         object_unlock_shared(thiz);
673         *pPriority = priority;
674         *pPreemptable = preemptable;
675         result = SL_RESULT_SUCCESS;
676     }
677 #else
678     result = SL_RESULT_FEATURE_UNSUPPORTED;
679 #endif
680 
681     SL_LEAVE_INTERFACE
682 }
683 
684 
IObject_SetLossOfControlInterfaces(SLObjectItf self,SLint16 numInterfaces,SLInterfaceID * pInterfaceIDs,SLboolean enabled)685 static SLresult IObject_SetLossOfControlInterfaces(SLObjectItf self,
686     SLint16 numInterfaces, SLInterfaceID *pInterfaceIDs, SLboolean enabled)
687 {
688     SL_ENTER_INTERFACE
689 
690 #if USE_PROFILES & USE_PROFILES_BASE
691     result = SL_RESULT_SUCCESS;
692     if (0 < numInterfaces) {
693         SLuint32 i;
694         if (NULL == pInterfaceIDs) {
695             result = SL_RESULT_PARAMETER_INVALID;
696         } else {
697             IObject *thiz = (IObject *) self;
698             const ClassTable *clazz = thiz->mClass;
699             unsigned lossOfControlMask = 0;
700             // The cast is due to a typo in the spec, bug 6482
701             for (i = 0; i < (SLuint32) numInterfaces; ++i) {
702                 SLInterfaceID iid = pInterfaceIDs[i];
703                 if (NULL == iid) {
704                     result = SL_RESULT_PARAMETER_INVALID;
705                     goto out;
706                 }
707                 int MPH, index;
708                 // We ignore without error any invalid MPH or index, but spec is unclear
709                 if ((0 <= (MPH = IID_to_MPH(iid))) &&
710                         // no need to check for an initialization hook
711                         // (NULL == MPH_init_table[MPH].mInit) ||
712                         (0 <= (index = clazz->mMPH_to_index[MPH]))) {
713                     lossOfControlMask |= (1 << index);
714                 }
715             }
716             object_lock_exclusive(thiz);
717             if (enabled) {
718                 thiz->mLossOfControlMask |= lossOfControlMask;
719             } else {
720                 thiz->mLossOfControlMask &= ~lossOfControlMask;
721             }
722             object_unlock_exclusive(thiz);
723         }
724     }
725 out:
726 #else
727     result = SL_RESULT_FEATURE_UNSUPPORTED;
728 #endif
729 
730     SL_LEAVE_INTERFACE
731 }
732 
733 
734 static const struct SLObjectItf_ IObject_Itf = {
735     IObject_Realize,
736     IObject_Resume,
737     IObject_GetState,
738     IObject_GetInterface,
739     IObject_RegisterCallback,
740     IObject_AbortAsyncOperation,
741     IObject_Destroy,
742     IObject_SetPriority,
743     IObject_GetPriority,
744     IObject_SetLossOfControlInterfaces
745 };
746 
747 
748 /** \brief This must be the first initializer called for an object */
749 
IObject_init(void * self)750 void IObject_init(void *self)
751 {
752     IObject *thiz = (IObject *) self;
753     thiz->mItf = &IObject_Itf;
754     // initialized in construct:
755     // mClass
756     // mInstanceID
757     // mLossOfControlMask
758     // mEngine
759     // mInterfaceStates
760     thiz->mState = SL_OBJECT_STATE_UNREALIZED;
761     thiz->mGottenMask = 1;  // IObject
762     thiz->mAttributesMask = 0;
763     thiz->mCallback = NULL;
764     thiz->mContext = NULL;
765 #if USE_PROFILES & USE_PROFILES_BASE
766     thiz->mPriority = SL_PRIORITY_NORMAL;
767     thiz->mPreemptable = SL_BOOLEAN_FALSE;
768 #endif
769     thiz->mStrongRefCount = 0;
770     int ok;
771     ok = pthread_mutex_init(&thiz->mMutex, (const pthread_mutexattr_t *) NULL);
772     assert(0 == ok);
773 #ifdef USE_DEBUG
774     memset(&thiz->mOwner, 0, sizeof(pthread_t));
775     thiz->mFile = NULL;
776     thiz->mLine = 0;
777     thiz->mGeneration = 0;
778 #endif
779     ok = pthread_cond_init(&thiz->mCond, (const pthread_condattr_t *) NULL);
780     assert(0 == ok);
781 }
782 
783 
784 /** \brief This must be the last deinitializer called for an object */
785 
IObject_deinit(void * self)786 void IObject_deinit(void *self)
787 {
788     IObject *thiz = (IObject *) self;
789 #ifdef USE_DEBUG
790     assert(pthread_equal(pthread_self(), thiz->mOwner));
791 #endif
792     int ok;
793     ok = pthread_cond_destroy(&thiz->mCond);
794     assert(0 == ok);
795     // equivalent to object_unlock_exclusive, but without the rigmarole
796     ok = pthread_mutex_unlock(&thiz->mMutex);
797     assert(0 == ok);
798     ok = pthread_mutex_destroy(&thiz->mMutex);
799     assert(0 == ok);
800     // redundant: thiz->mState = SL_OBJECT_STATE_UNREALIZED;
801 }
802 
803 
804 /** \brief Publish a new object after it is fully initialized.
805  *  Publishing will expose the object to sync thread and debugger,
806  *  and make it safe to return the SLObjectItf to the application.
807  */
808 
IObject_Publish(IObject * thiz)809 void IObject_Publish(IObject *thiz)
810 {
811     IEngine *thisEngine = &thiz->mEngine->mEngine;
812     interface_lock_exclusive(thisEngine);
813     // construct earlier reserved a pending slot, but did not choose the actual slot number
814     unsigned availMask = ~thisEngine->mInstanceMask;
815     assert(availMask);
816     unsigned i = ctz(availMask);
817     assert(MAX_INSTANCE > i);
818     assert(NULL == thisEngine->mInstances[i]);
819     thisEngine->mInstances[i] = thiz;
820     thisEngine->mInstanceMask |= 1 << i;
821     // avoid zero as a valid instance ID
822     thiz->mInstanceID = i + 1;
823     interface_unlock_exclusive(thisEngine);
824 }
825