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 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 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 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 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 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 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->mTrackPlayer->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 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 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 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 330 void object_cond_broadcast(IObject *thiz) 331 { 332 int ok; 333 ok = pthread_cond_broadcast(&thiz->mCond); 334 assert(0 == ok); 335 } 336