locks.c revision 7e7826821d0e82c13a4f9f34525d0cdaf323f34a
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 35void init_time_spec(timespec* ts, long delta) { 36 clock_gettime(CLOCK_REALTIME, ts); 37 ts->tv_nsec += delta; 38 39 if (ts->tv_nsec >= 1000000000L) { 40 ts->tv_sec++; 41 ts->tv_nsec -= 1000000000L; 42 } 43} 44 45void object_lock_exclusive_(IObject *thiz, const char *file, int line) 46{ 47 int ok; 48 ok = pthread_mutex_trylock(&thiz->mMutex); 49 if (0 != ok) { 50 // not android_atomic_acquire_load because we don't care about relative load/load ordering 51 int32_t oldGeneration = thiz->mGeneration; 52 // wait up to a total of 250 ms 53 static const long nanoBackoffs[] = { 54 10 * 1000000, 20 * 1000000, 30 * 1000000, 40 * 1000000, 50 * 1000000, 100 * 1000000}; 55 unsigned i = 0; 56 timespec ts; 57 memset(&ts, 0, sizeof(timespec)); 58 for (;;) { 59 init_time_spec(&ts, nanoBackoffs[i]); 60 ok = pthread_mutex_timedlock(&thiz->mMutex, &ts); 61 if (0 == ok) { 62 break; 63 } 64 if (EBUSY == ok) { 65 // this is the expected return value for timeout, and will be handled below 66 } else if (EDEADLK == ok) { 67 // we don't use the kind of mutex that can return this error, but just in case 68 SL_LOGE("%s:%d: recursive lock detected", file, line); 69 } else { 70 // some other return value 71 SL_LOGE("%s:%d: pthread_mutex_lock_timeout_np returned %d", file, line, ok); 72 } 73 // is anyone else making forward progress? 74 int32_t newGeneration = thiz->mGeneration; 75 if (newGeneration != oldGeneration) { 76 // if we ever see forward progress then lock without timeout (more efficient) 77 goto forward_progress; 78 } 79 // no, then continue trying to lock but with increasing timeouts 80 if (++i >= (sizeof(nanoBackoffs) / sizeof(nanoBackoffs[0]))) { 81 // the extra block avoids a C++ compiler error about goto past initialization 82 { 83 pthread_t me = pthread_self(); 84 pthread_t owner = thiz->mOwner; 85 // unlikely, but this could result in a memory fault if owner is corrupt 86 pid_t ownerTid = LIKELY_VALID(owner) ? __pthread_gettid(owner) : -1; 87 SL_LOGW("%s:%d: pthread %p (tid %d) sees object %p was locked by pthread %p" 88 " (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz, 89 *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine); 90 } 91forward_progress: 92 // attempt one more time without timeout; maybe this time we will be successful 93 ok = pthread_mutex_lock(&thiz->mMutex); 94 assert(0 == ok); 95 break; 96 } 97 } 98 } 99 // here if mutex was successfully locked 100 pthread_t zero; 101 memset(&zero, 0, sizeof(pthread_t)); 102 if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) { 103 pthread_t me = pthread_self(); 104 pthread_t owner = thiz->mOwner; 105 pid_t ownerTid = LIKELY_VALID(owner) ? __pthread_gettid(owner) : -1; 106 if (pthread_equal(pthread_self(), owner)) { 107 SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was recursively locked by pthread" 108 " %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz, 109 *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine); 110 } else { 111 SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was left unlocked in unexpected" 112 " state by pthread %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), 113 thiz, *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine); 114 } 115 assert(false); 116 } 117 thiz->mOwner = pthread_self(); 118 thiz->mFile = file; 119 thiz->mLine = line; 120 // not android_atomic_inc because we are already holding a mutex 121 ++thiz->mGeneration; 122} 123#else 124void 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 136void 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 149void 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 163void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes, 164 const char *file, int line) 165#else 166void 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->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 289void 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 308void 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 319void 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 331void object_cond_broadcast(IObject *thiz) 332{ 333 int ok; 334 ok = pthread_cond_broadcast(&thiz->mCond); 335 assert(0 == ok); 336} 337