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