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