xref: /aosp_15_r20/frameworks/wilhelm/src/locks.cpp (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker  * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker  *
4*bebae9c0SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker  *
8*bebae9c0SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker  *
10*bebae9c0SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker  * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker  */
16*bebae9c0SAndroid Build Coastguard Worker 
17*bebae9c0SAndroid Build Coastguard Worker #include "sles_allinclusive.h"
18*bebae9c0SAndroid Build Coastguard Worker 
19*bebae9c0SAndroid Build Coastguard Worker 
20*bebae9c0SAndroid Build Coastguard Worker // Use this macro to validate a pthread_t before passing it into pthread_gettid_np.
21*bebae9c0SAndroid Build Coastguard Worker // One of the common reasons for deadlock is trying to lock a mutex for an object
22*bebae9c0SAndroid Build Coastguard Worker // which has been destroyed (which does memset to 0x00 or 0x55 as the final step).
23*bebae9c0SAndroid Build Coastguard Worker // To avoid crashing with a SIGSEGV right before we're about to log a deadlock warning,
24*bebae9c0SAndroid Build Coastguard Worker // we check that the pthread_t is probably valid.  Note that it is theoretically
25*bebae9c0SAndroid Build Coastguard Worker // possible for something to look like a valid pthread_t but not actually be valid.
26*bebae9c0SAndroid Build Coastguard Worker // So we might still crash, but only in the case where a deadlock was imminent anyway.
27*bebae9c0SAndroid Build Coastguard Worker #define LIKELY_VALID(ptr) (((ptr) != (pthread_t) 0) && ((((size_t) (ptr)) & 3) == 0))
28*bebae9c0SAndroid Build Coastguard Worker 
29*bebae9c0SAndroid Build Coastguard Worker 
30*bebae9c0SAndroid Build Coastguard Worker /** \brief Exclusively lock an object */
31*bebae9c0SAndroid Build Coastguard Worker 
32*bebae9c0SAndroid Build Coastguard Worker #ifdef USE_DEBUG
33*bebae9c0SAndroid Build Coastguard Worker 
init_time_spec(timespec * ts,long delta)34*bebae9c0SAndroid Build Coastguard Worker void init_time_spec(timespec* ts, long delta) {
35*bebae9c0SAndroid Build Coastguard Worker     clock_gettime(CLOCK_REALTIME, ts);
36*bebae9c0SAndroid Build Coastguard Worker     ts->tv_nsec += delta;
37*bebae9c0SAndroid Build Coastguard Worker 
38*bebae9c0SAndroid Build Coastguard Worker     if (ts->tv_nsec >= 1000000000L) {
39*bebae9c0SAndroid Build Coastguard Worker         ts->tv_sec++;
40*bebae9c0SAndroid Build Coastguard Worker         ts->tv_nsec -= 1000000000L;
41*bebae9c0SAndroid Build Coastguard Worker     }
42*bebae9c0SAndroid Build Coastguard Worker }
43*bebae9c0SAndroid Build Coastguard Worker 
object_lock_exclusive_(IObject * thiz,const char * file,int line)44*bebae9c0SAndroid Build Coastguard Worker void object_lock_exclusive_(IObject *thiz, const char *file, int line)
45*bebae9c0SAndroid Build Coastguard Worker {
46*bebae9c0SAndroid Build Coastguard Worker     int ok;
47*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_trylock(&thiz->mMutex);
48*bebae9c0SAndroid Build Coastguard Worker     if (0 != ok) {
49*bebae9c0SAndroid Build Coastguard Worker         // not android_atomic_acquire_load because we don't care about relative load/load ordering
50*bebae9c0SAndroid Build Coastguard Worker         int32_t oldGeneration = thiz->mGeneration;
51*bebae9c0SAndroid Build Coastguard Worker         // wait up to a total of 250 ms
52*bebae9c0SAndroid Build Coastguard Worker         static const long nanoBackoffs[] = {
53*bebae9c0SAndroid Build Coastguard Worker             10 * 1000000, 20 * 1000000, 30 * 1000000, 40 * 1000000, 50 * 1000000, 100 * 1000000};
54*bebae9c0SAndroid Build Coastguard Worker         unsigned i = 0;
55*bebae9c0SAndroid Build Coastguard Worker         timespec ts;
56*bebae9c0SAndroid Build Coastguard Worker         memset(&ts, 0, sizeof(timespec));
57*bebae9c0SAndroid Build Coastguard Worker         for (;;) {
58*bebae9c0SAndroid Build Coastguard Worker             init_time_spec(&ts, nanoBackoffs[i]);
59*bebae9c0SAndroid Build Coastguard Worker             ok = pthread_mutex_timedlock(&thiz->mMutex, &ts);
60*bebae9c0SAndroid Build Coastguard Worker             if (0 == ok) {
61*bebae9c0SAndroid Build Coastguard Worker                 break;
62*bebae9c0SAndroid Build Coastguard Worker             }
63*bebae9c0SAndroid Build Coastguard Worker             if (EBUSY == ok) {
64*bebae9c0SAndroid Build Coastguard Worker                 // this is the expected return value for timeout, and will be handled below
65*bebae9c0SAndroid Build Coastguard Worker             } else if (EDEADLK == ok) {
66*bebae9c0SAndroid Build Coastguard Worker                 // we don't use the kind of mutex that can return this error, but just in case
67*bebae9c0SAndroid Build Coastguard Worker                 SL_LOGE("%s:%d: recursive lock detected", file, line);
68*bebae9c0SAndroid Build Coastguard Worker             } else {
69*bebae9c0SAndroid Build Coastguard Worker                 // some other return value
70*bebae9c0SAndroid Build Coastguard Worker                 SL_LOGE("%s:%d: pthread_mutex_lock_timeout_np returned %d", file, line, ok);
71*bebae9c0SAndroid Build Coastguard Worker             }
72*bebae9c0SAndroid Build Coastguard Worker             // is anyone else making forward progress?
73*bebae9c0SAndroid Build Coastguard Worker             int32_t newGeneration = thiz->mGeneration;
74*bebae9c0SAndroid Build Coastguard Worker             if (newGeneration != oldGeneration) {
75*bebae9c0SAndroid Build Coastguard Worker                 // if we ever see forward progress then lock without timeout (more efficient)
76*bebae9c0SAndroid Build Coastguard Worker                 goto forward_progress;
77*bebae9c0SAndroid Build Coastguard Worker             }
78*bebae9c0SAndroid Build Coastguard Worker             // no, then continue trying to lock but with increasing timeouts
79*bebae9c0SAndroid Build Coastguard Worker             if (++i >= (sizeof(nanoBackoffs) / sizeof(nanoBackoffs[0]))) {
80*bebae9c0SAndroid Build Coastguard Worker                 // the extra block avoids a C++ compiler error about goto past initialization
81*bebae9c0SAndroid Build Coastguard Worker                 {
82*bebae9c0SAndroid Build Coastguard Worker                     pthread_t me = pthread_self();
83*bebae9c0SAndroid Build Coastguard Worker                     pthread_t owner = thiz->mOwner;
84*bebae9c0SAndroid Build Coastguard Worker                     // unlikely, but this could result in a memory fault if owner is corrupt
85*bebae9c0SAndroid Build Coastguard Worker                     pid_t ownerTid = LIKELY_VALID(owner) ? pthread_gettid_np(owner) : -1;
86*bebae9c0SAndroid Build Coastguard Worker                     SL_LOGW("%s:%d: pthread %p (tid %d) sees object %p was locked by pthread %p"
87*bebae9c0SAndroid Build Coastguard Worker                             " (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
88*bebae9c0SAndroid Build Coastguard Worker                             *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
89*bebae9c0SAndroid Build Coastguard Worker                 }
90*bebae9c0SAndroid Build Coastguard Worker forward_progress:
91*bebae9c0SAndroid Build Coastguard Worker                 // attempt one more time without timeout; maybe this time we will be successful
92*bebae9c0SAndroid Build Coastguard Worker                 ok = pthread_mutex_lock(&thiz->mMutex);
93*bebae9c0SAndroid Build Coastguard Worker                 assert(0 == ok);
94*bebae9c0SAndroid Build Coastguard Worker                 break;
95*bebae9c0SAndroid Build Coastguard Worker             }
96*bebae9c0SAndroid Build Coastguard Worker         }
97*bebae9c0SAndroid Build Coastguard Worker     }
98*bebae9c0SAndroid Build Coastguard Worker     // here if mutex was successfully locked
99*bebae9c0SAndroid Build Coastguard Worker     pthread_t zero;
100*bebae9c0SAndroid Build Coastguard Worker     memset(&zero, 0, sizeof(pthread_t));
101*bebae9c0SAndroid Build Coastguard Worker     if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
102*bebae9c0SAndroid Build Coastguard Worker         pthread_t me = pthread_self();
103*bebae9c0SAndroid Build Coastguard Worker         pthread_t owner = thiz->mOwner;
104*bebae9c0SAndroid Build Coastguard Worker         pid_t ownerTid = LIKELY_VALID(owner) ? pthread_gettid_np(owner) : -1;
105*bebae9c0SAndroid Build Coastguard Worker         if (pthread_equal(pthread_self(), owner)) {
106*bebae9c0SAndroid Build Coastguard Worker             SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was recursively locked by pthread"
107*bebae9c0SAndroid Build Coastguard Worker                     " %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
108*bebae9c0SAndroid Build Coastguard Worker                     *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
109*bebae9c0SAndroid Build Coastguard Worker         } else {
110*bebae9c0SAndroid Build Coastguard Worker             SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was left unlocked in unexpected"
111*bebae9c0SAndroid Build Coastguard Worker                     " state by pthread %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(),
112*bebae9c0SAndroid Build Coastguard Worker                     thiz, *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
113*bebae9c0SAndroid Build Coastguard Worker         }
114*bebae9c0SAndroid Build Coastguard Worker         assert(false);
115*bebae9c0SAndroid Build Coastguard Worker     }
116*bebae9c0SAndroid Build Coastguard Worker     thiz->mOwner = pthread_self();
117*bebae9c0SAndroid Build Coastguard Worker     thiz->mFile = file;
118*bebae9c0SAndroid Build Coastguard Worker     thiz->mLine = line;
119*bebae9c0SAndroid Build Coastguard Worker     // not android_atomic_inc because we are already holding a mutex
120*bebae9c0SAndroid Build Coastguard Worker     // use explicit add as mGeneration is a volatile for which ++v and v += are deprecated.
121*bebae9c0SAndroid Build Coastguard Worker     thiz->mGeneration = thiz->mGeneration + 1;
122*bebae9c0SAndroid Build Coastguard Worker }
123*bebae9c0SAndroid Build Coastguard Worker #else
object_lock_exclusive(IObject * thiz)124*bebae9c0SAndroid Build Coastguard Worker void object_lock_exclusive(IObject *thiz)
125*bebae9c0SAndroid Build Coastguard Worker {
126*bebae9c0SAndroid Build Coastguard Worker     int ok;
127*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_lock(&thiz->mMutex);
128*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
129*bebae9c0SAndroid Build Coastguard Worker }
130*bebae9c0SAndroid Build Coastguard Worker #endif
131*bebae9c0SAndroid Build Coastguard Worker 
132*bebae9c0SAndroid Build Coastguard Worker 
133*bebae9c0SAndroid Build Coastguard Worker /** \brief Exclusively unlock an object and do not report any updates */
134*bebae9c0SAndroid Build Coastguard Worker 
135*bebae9c0SAndroid Build Coastguard Worker #ifdef USE_DEBUG
object_unlock_exclusive_(IObject * thiz,const char * file,int line)136*bebae9c0SAndroid Build Coastguard Worker void object_unlock_exclusive_(IObject *thiz, const char *file, int line)
137*bebae9c0SAndroid Build Coastguard Worker {
138*bebae9c0SAndroid Build Coastguard Worker     assert(pthread_equal(pthread_self(), thiz->mOwner));
139*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thiz->mFile);
140*bebae9c0SAndroid Build Coastguard Worker     assert(0 != thiz->mLine);
141*bebae9c0SAndroid Build Coastguard Worker     memset(&thiz->mOwner, 0, sizeof(pthread_t));
142*bebae9c0SAndroid Build Coastguard Worker     thiz->mFile = file;
143*bebae9c0SAndroid Build Coastguard Worker     thiz->mLine = line;
144*bebae9c0SAndroid Build Coastguard Worker     int ok;
145*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_unlock(&thiz->mMutex);
146*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
147*bebae9c0SAndroid Build Coastguard Worker }
148*bebae9c0SAndroid Build Coastguard Worker #else
object_unlock_exclusive(IObject * thiz)149*bebae9c0SAndroid Build Coastguard Worker void object_unlock_exclusive(IObject *thiz)
150*bebae9c0SAndroid Build Coastguard Worker {
151*bebae9c0SAndroid Build Coastguard Worker     int ok;
152*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_unlock(&thiz->mMutex);
153*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
154*bebae9c0SAndroid Build Coastguard Worker }
155*bebae9c0SAndroid Build Coastguard Worker #endif
156*bebae9c0SAndroid Build Coastguard Worker 
157*bebae9c0SAndroid Build Coastguard Worker 
158*bebae9c0SAndroid Build Coastguard Worker /** \brief Exclusively unlock an object and report updates to the specified bit-mask of
159*bebae9c0SAndroid Build Coastguard Worker  *  attributes
160*bebae9c0SAndroid Build Coastguard Worker  */
161*bebae9c0SAndroid Build Coastguard Worker 
162*bebae9c0SAndroid Build Coastguard Worker #ifdef USE_DEBUG
object_unlock_exclusive_attributes_(IObject * thiz,unsigned attributes,const char * file,int line)163*bebae9c0SAndroid Build Coastguard Worker void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
164*bebae9c0SAndroid Build Coastguard Worker     const char *file, int line)
165*bebae9c0SAndroid Build Coastguard Worker #else
166*bebae9c0SAndroid Build Coastguard Worker void object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes)
167*bebae9c0SAndroid Build Coastguard Worker #endif
168*bebae9c0SAndroid Build Coastguard Worker {
169*bebae9c0SAndroid Build Coastguard Worker 
170*bebae9c0SAndroid Build Coastguard Worker #ifdef USE_DEBUG
171*bebae9c0SAndroid Build Coastguard Worker     assert(pthread_equal(pthread_self(), thiz->mOwner));
172*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thiz->mFile);
173*bebae9c0SAndroid Build Coastguard Worker     assert(0 != thiz->mLine);
174*bebae9c0SAndroid Build Coastguard Worker #endif
175*bebae9c0SAndroid Build Coastguard Worker 
176*bebae9c0SAndroid Build Coastguard Worker     int ok;
177*bebae9c0SAndroid Build Coastguard Worker 
178*bebae9c0SAndroid Build Coastguard Worker     // make SL object IDs be contiguous with XA object IDs
179*bebae9c0SAndroid Build Coastguard Worker     SLuint32 objectID = IObjectToObjectID(thiz);
180*bebae9c0SAndroid Build Coastguard Worker     SLuint32 index = objectID;
181*bebae9c0SAndroid Build Coastguard Worker     if ((XA_OBJECTID_ENGINE <= index) && (index <= XA_OBJECTID_CAMERADEVICE)) {
182*bebae9c0SAndroid Build Coastguard Worker         ;
183*bebae9c0SAndroid Build Coastguard Worker     } else if ((SL_OBJECTID_ENGINE <= index) && (index <= SL_OBJECTID_METADATAEXTRACTOR)) {
184*bebae9c0SAndroid Build Coastguard Worker         index -= SL_OBJECTID_ENGINE - XA_OBJECTID_CAMERADEVICE - 1;
185*bebae9c0SAndroid Build Coastguard Worker     } else {
186*bebae9c0SAndroid Build Coastguard Worker         assert(false);
187*bebae9c0SAndroid Build Coastguard Worker         index = 0;
188*bebae9c0SAndroid Build Coastguard Worker     }
189*bebae9c0SAndroid Build Coastguard Worker 
190*bebae9c0SAndroid Build Coastguard Worker     // first synchronously handle updates to attributes here, while object is still locked.
191*bebae9c0SAndroid Build Coastguard Worker     // This appears to be a loop, but actually typically runs through the loop only once.
192*bebae9c0SAndroid Build Coastguard Worker     unsigned asynchronous = attributes;
193*bebae9c0SAndroid Build Coastguard Worker     while (attributes) {
194*bebae9c0SAndroid Build Coastguard Worker         // this sequence is carefully crafted to be O(1); tread carefully when making changes
195*bebae9c0SAndroid Build Coastguard Worker         unsigned bit = ctz(attributes);
196*bebae9c0SAndroid Build Coastguard Worker         // ATTR_INDEX_MAX == next bit position after the last attribute
197*bebae9c0SAndroid Build Coastguard Worker         assert(ATTR_INDEX_MAX > bit);
198*bebae9c0SAndroid Build Coastguard Worker         // compute the entry in the handler table using object ID and bit number
199*bebae9c0SAndroid Build Coastguard Worker         AttributeHandler handler = handlerTable[index][bit];
200*bebae9c0SAndroid Build Coastguard Worker         if (NULL != handler) {
201*bebae9c0SAndroid Build Coastguard Worker             asynchronous &= ~(*handler)(thiz);
202*bebae9c0SAndroid Build Coastguard Worker         }
203*bebae9c0SAndroid Build Coastguard Worker         attributes &= ~(1 << bit);
204*bebae9c0SAndroid Build Coastguard Worker     }
205*bebae9c0SAndroid Build Coastguard Worker 
206*bebae9c0SAndroid Build Coastguard Worker     // any remaining attributes are handled asynchronously in the sync thread
207*bebae9c0SAndroid Build Coastguard Worker     if (asynchronous) {
208*bebae9c0SAndroid Build Coastguard Worker         unsigned oldAttributesMask = thiz->mAttributesMask;
209*bebae9c0SAndroid Build Coastguard Worker         thiz->mAttributesMask = oldAttributesMask | asynchronous;
210*bebae9c0SAndroid Build Coastguard Worker         if (oldAttributesMask) {
211*bebae9c0SAndroid Build Coastguard Worker             asynchronous = ATTR_NONE;
212*bebae9c0SAndroid Build Coastguard Worker         }
213*bebae9c0SAndroid Build Coastguard Worker     }
214*bebae9c0SAndroid Build Coastguard Worker 
215*bebae9c0SAndroid Build Coastguard Worker #ifdef ANDROID
216*bebae9c0SAndroid Build Coastguard Worker     // FIXME hack to safely handle a post-unlock PrefetchStatus callback and/or AudioTrack::start()
217*bebae9c0SAndroid Build Coastguard Worker     slPrefetchCallback prefetchCallback = NULL;
218*bebae9c0SAndroid Build Coastguard Worker     void *prefetchContext = NULL;
219*bebae9c0SAndroid Build Coastguard Worker     SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
220*bebae9c0SAndroid Build Coastguard Worker     android::sp<android::AudioTrack> audioTrack;
221*bebae9c0SAndroid Build Coastguard Worker     if (SL_OBJECTID_AUDIOPLAYER == objectID) {
222*bebae9c0SAndroid Build Coastguard Worker         CAudioPlayer *ap = (CAudioPlayer *) thiz;
223*bebae9c0SAndroid Build Coastguard Worker         prefetchCallback = ap->mPrefetchStatus.mDeferredPrefetchCallback;
224*bebae9c0SAndroid Build Coastguard Worker         prefetchContext  = ap->mPrefetchStatus.mDeferredPrefetchContext;
225*bebae9c0SAndroid Build Coastguard Worker         prefetchEvents   = ap->mPrefetchStatus.mDeferredPrefetchEvents;
226*bebae9c0SAndroid Build Coastguard Worker         ap->mPrefetchStatus.mDeferredPrefetchCallback = NULL;
227*bebae9c0SAndroid Build Coastguard Worker         // clearing these next two fields is not required, but avoids stale data during debugging
228*bebae9c0SAndroid Build Coastguard Worker         ap->mPrefetchStatus.mDeferredPrefetchContext  = NULL;
229*bebae9c0SAndroid Build Coastguard Worker         ap->mPrefetchStatus.mDeferredPrefetchEvents   = SL_PREFETCHEVENT_NONE;
230*bebae9c0SAndroid Build Coastguard Worker         if (ap->mDeferredStart) {
231*bebae9c0SAndroid Build Coastguard Worker             audioTrack = ap->mTrackPlayer->getAudioTrack();
232*bebae9c0SAndroid Build Coastguard Worker             ap->mDeferredStart = false;
233*bebae9c0SAndroid Build Coastguard Worker         }
234*bebae9c0SAndroid Build Coastguard Worker     }
235*bebae9c0SAndroid Build Coastguard Worker #endif
236*bebae9c0SAndroid Build Coastguard Worker 
237*bebae9c0SAndroid Build Coastguard Worker #ifdef USE_DEBUG
238*bebae9c0SAndroid Build Coastguard Worker     memset(&thiz->mOwner, 0, sizeof(pthread_t));
239*bebae9c0SAndroid Build Coastguard Worker     thiz->mFile = file;
240*bebae9c0SAndroid Build Coastguard Worker     thiz->mLine = line;
241*bebae9c0SAndroid Build Coastguard Worker #endif
242*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_mutex_unlock(&thiz->mMutex);
243*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
244*bebae9c0SAndroid Build Coastguard Worker 
245*bebae9c0SAndroid Build Coastguard Worker #ifdef ANDROID
246*bebae9c0SAndroid Build Coastguard Worker     // FIXME call the prefetch status callback while not holding the mutex on AudioPlayer
247*bebae9c0SAndroid Build Coastguard Worker     if (NULL != prefetchCallback) {
248*bebae9c0SAndroid Build Coastguard Worker         // note these are synchronous by the application's thread as it is about to return from API
249*bebae9c0SAndroid Build Coastguard Worker         assert(prefetchEvents != SL_PREFETCHEVENT_NONE);
250*bebae9c0SAndroid Build Coastguard Worker         CAudioPlayer *ap = (CAudioPlayer *) thiz;
251*bebae9c0SAndroid Build Coastguard Worker         // spec requires separate callbacks for each event
252*bebae9c0SAndroid Build Coastguard Worker         if (SL_PREFETCHEVENT_STATUSCHANGE & prefetchEvents) {
253*bebae9c0SAndroid Build Coastguard Worker             (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
254*bebae9c0SAndroid Build Coastguard Worker                     SL_PREFETCHEVENT_STATUSCHANGE);
255*bebae9c0SAndroid Build Coastguard Worker         }
256*bebae9c0SAndroid Build Coastguard Worker         if (SL_PREFETCHEVENT_FILLLEVELCHANGE & prefetchEvents) {
257*bebae9c0SAndroid Build Coastguard Worker             (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
258*bebae9c0SAndroid Build Coastguard Worker                     SL_PREFETCHEVENT_FILLLEVELCHANGE);
259*bebae9c0SAndroid Build Coastguard Worker         }
260*bebae9c0SAndroid Build Coastguard Worker     }
261*bebae9c0SAndroid Build Coastguard Worker 
262*bebae9c0SAndroid Build Coastguard Worker     // call AudioTrack::start() while not holding the mutex on AudioPlayer
263*bebae9c0SAndroid Build Coastguard Worker     if (audioTrack != 0) {
264*bebae9c0SAndroid Build Coastguard Worker         audioTrack->start();
265*bebae9c0SAndroid Build Coastguard Worker         audioTrack.clear();
266*bebae9c0SAndroid Build Coastguard Worker     }
267*bebae9c0SAndroid Build Coastguard Worker #endif
268*bebae9c0SAndroid Build Coastguard Worker 
269*bebae9c0SAndroid Build Coastguard Worker     // first update to this interface since previous sync
270*bebae9c0SAndroid Build Coastguard Worker     if (ATTR_NONE != asynchronous) {
271*bebae9c0SAndroid Build Coastguard Worker         unsigned id = thiz->mInstanceID;
272*bebae9c0SAndroid Build Coastguard Worker         if (0 != id) {
273*bebae9c0SAndroid Build Coastguard Worker             --id;
274*bebae9c0SAndroid Build Coastguard Worker             assert(MAX_INSTANCE > id);
275*bebae9c0SAndroid Build Coastguard Worker             IEngine *thisEngine = &thiz->mEngine->mEngine;
276*bebae9c0SAndroid Build Coastguard Worker             // FIXME atomic or here
277*bebae9c0SAndroid Build Coastguard Worker             interface_lock_exclusive(thisEngine);
278*bebae9c0SAndroid Build Coastguard Worker             thisEngine->mChangedMask |= 1 << id;
279*bebae9c0SAndroid Build Coastguard Worker             interface_unlock_exclusive(thisEngine);
280*bebae9c0SAndroid Build Coastguard Worker         }
281*bebae9c0SAndroid Build Coastguard Worker     }
282*bebae9c0SAndroid Build Coastguard Worker 
283*bebae9c0SAndroid Build Coastguard Worker }
284*bebae9c0SAndroid Build Coastguard Worker 
285*bebae9c0SAndroid Build Coastguard Worker 
286*bebae9c0SAndroid Build Coastguard Worker /** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
287*bebae9c0SAndroid Build Coastguard Worker 
288*bebae9c0SAndroid Build Coastguard Worker #ifdef USE_DEBUG
object_cond_wait_(IObject * thiz,const char * file,int line)289*bebae9c0SAndroid Build Coastguard Worker void object_cond_wait_(IObject *thiz, const char *file, int line)
290*bebae9c0SAndroid Build Coastguard Worker {
291*bebae9c0SAndroid Build Coastguard Worker     // note that this will unlock the mutex, so we have to clear the owner
292*bebae9c0SAndroid Build Coastguard Worker     assert(pthread_equal(pthread_self(), thiz->mOwner));
293*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thiz->mFile);
294*bebae9c0SAndroid Build Coastguard Worker     assert(0 != thiz->mLine);
295*bebae9c0SAndroid Build Coastguard Worker     memset(&thiz->mOwner, 0, sizeof(pthread_t));
296*bebae9c0SAndroid Build Coastguard Worker     thiz->mFile = file;
297*bebae9c0SAndroid Build Coastguard Worker     thiz->mLine = line;
298*bebae9c0SAndroid Build Coastguard Worker     // alas we don't know the new owner's identity
299*bebae9c0SAndroid Build Coastguard Worker     int ok;
300*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
301*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
302*bebae9c0SAndroid Build Coastguard Worker     // restore my ownership
303*bebae9c0SAndroid Build Coastguard Worker     thiz->mOwner = pthread_self();
304*bebae9c0SAndroid Build Coastguard Worker     thiz->mFile = file;
305*bebae9c0SAndroid Build Coastguard Worker     thiz->mLine = line;
306*bebae9c0SAndroid Build Coastguard Worker }
307*bebae9c0SAndroid Build Coastguard Worker #else
object_cond_wait(IObject * thiz)308*bebae9c0SAndroid Build Coastguard Worker void object_cond_wait(IObject *thiz)
309*bebae9c0SAndroid Build Coastguard Worker {
310*bebae9c0SAndroid Build Coastguard Worker     int ok;
311*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
312*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
313*bebae9c0SAndroid Build Coastguard Worker }
314*bebae9c0SAndroid Build Coastguard Worker #endif
315*bebae9c0SAndroid Build Coastguard Worker 
316*bebae9c0SAndroid Build Coastguard Worker 
317*bebae9c0SAndroid Build Coastguard Worker /** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
318*bebae9c0SAndroid Build Coastguard Worker 
object_cond_signal(IObject * thiz)319*bebae9c0SAndroid Build Coastguard Worker void object_cond_signal(IObject *thiz)
320*bebae9c0SAndroid Build Coastguard Worker {
321*bebae9c0SAndroid Build Coastguard Worker     int ok;
322*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_cond_signal(&thiz->mCond);
323*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
324*bebae9c0SAndroid Build Coastguard Worker }
325*bebae9c0SAndroid Build Coastguard Worker 
326*bebae9c0SAndroid Build Coastguard Worker 
327*bebae9c0SAndroid Build Coastguard Worker /** \brief Broadcast the condition variable associated with the object;
328*bebae9c0SAndroid Build Coastguard Worker  *  see pthread_cond_broadcast
329*bebae9c0SAndroid Build Coastguard Worker  */
330*bebae9c0SAndroid Build Coastguard Worker 
object_cond_broadcast(IObject * thiz)331*bebae9c0SAndroid Build Coastguard Worker void object_cond_broadcast(IObject *thiz)
332*bebae9c0SAndroid Build Coastguard Worker {
333*bebae9c0SAndroid Build Coastguard Worker     int ok;
334*bebae9c0SAndroid Build Coastguard Worker     ok = pthread_cond_broadcast(&thiz->mCond);
335*bebae9c0SAndroid Build Coastguard Worker     assert(0 == ok);
336*bebae9c0SAndroid Build Coastguard Worker }
337