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