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