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