locks.c revision ae1a5c8dc1fccf7c121eda830f8d23bd094c0f16
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 34void 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 } 77forward_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 110void 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 122void 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 135void 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 149void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes, 150 const char *file, int line) 151#else 152void 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 275void 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 294void 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 305void 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 317void object_cond_broadcast(IObject *thiz) 318{ 319 int ok; 320 ok = pthread_cond_broadcast(&thiz->mCond); 321 assert(0 == ok); 322} 323