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 // use explicit add as mGeneration is a volatile for which ++v and v += are deprecated.
121 thiz->mGeneration = thiz->mGeneration + 1;
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->mTrackPlayer->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