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 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 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 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 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 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::AudioTrackProxy> 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 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 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 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 317 void object_cond_broadcast(IObject *thiz) 318 { 319 int ok; 320 ok = pthread_cond_broadcast(&thiz->mCond); 321 assert(0 == ok); 322 } 323