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