locks.c revision a60dbf554549d10780f473b6e1373aa07aec3a28
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/** \brief Exclusively lock an object */ 21 22#ifdef USE_DEBUG 23void object_lock_exclusive_(IObject *thiz, const char *file, int line) 24{ 25 int ok; 26 ok = pthread_mutex_trylock(&thiz->mMutex); 27 if (0 != ok) { 28 // pthread_mutex_timedlock_np is not available, but wait up to 100 ms 29 static const useconds_t backoffs[] = {1, 10000, 20000, 30000, 40000}; 30 unsigned i = 0; 31 for (;;) { 32 usleep(backoffs[i]); 33 ok = pthread_mutex_trylock(&thiz->mMutex); 34 if (0 == ok) 35 break; 36 if (++i >= (sizeof(backoffs) / sizeof(backoffs[0]))) { 37 SL_LOGW("%s:%d: object %p was locked by %p at %s:%d\n", 38 file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine); 39 // attempt one more time; maybe this time we will be successful 40 ok = pthread_mutex_lock(&thiz->mMutex); 41 assert(0 == ok); 42 break; 43 } 44 } 45 } 46 pthread_t zero; 47 memset(&zero, 0, sizeof(pthread_t)); 48 if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) { 49 if (pthread_equal(pthread_self(), thiz->mOwner)) { 50 SL_LOGE("%s:%d: object %p was recursively locked by %p at %s:%d\n", 51 file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine); 52 } else { 53 SL_LOGE("%s:%d: object %p was left unlocked in unexpected state by %p at %s:%d\n", 54 file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine); 55 } 56 assert(false); 57 } 58 thiz->mOwner = pthread_self(); 59 thiz->mFile = file; 60 thiz->mLine = line; 61} 62#else 63void object_lock_exclusive(IObject *thiz) 64{ 65 int ok; 66 ok = pthread_mutex_lock(&thiz->mMutex); 67 assert(0 == ok); 68} 69#endif 70 71 72/** \brief Exclusively unlock an object and do not report any updates */ 73 74#ifdef USE_DEBUG 75void object_unlock_exclusive_(IObject *thiz, const char *file, int line) 76{ 77 assert(pthread_equal(pthread_self(), thiz->mOwner)); 78 assert(NULL != thiz->mFile); 79 assert(0 != thiz->mLine); 80 memset(&thiz->mOwner, 0, sizeof(pthread_t)); 81 thiz->mFile = file; 82 thiz->mLine = line; 83 int ok; 84 ok = pthread_mutex_unlock(&thiz->mMutex); 85 assert(0 == ok); 86} 87#else 88void object_unlock_exclusive(IObject *thiz) 89{ 90 int ok; 91 ok = pthread_mutex_unlock(&thiz->mMutex); 92 assert(0 == ok); 93} 94#endif 95 96 97/** \brief Exclusively unlock an object and report updates to the specified bit-mask of 98 * attributes 99 */ 100 101#ifdef USE_DEBUG 102void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes, 103 const char *file, int line) 104#else 105void object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes) 106#endif 107{ 108 109#ifdef USE_DEBUG 110 assert(pthread_equal(pthread_self(), thiz->mOwner)); 111 assert(NULL != thiz->mFile); 112 assert(0 != thiz->mLine); 113#endif 114 115 int ok; 116 117 // make SL object IDs be contiguous with XA object IDs 118 SLuint32 objectID = IObjectToObjectID(thiz); 119 SLuint32 index = objectID; 120 if ((XA_OBJECTID_ENGINE <= index) && (index <= XA_OBJECTID_CAMERADEVICE)) { 121 ; 122 } else if ((SL_OBJECTID_ENGINE <= index) && (index <= SL_OBJECTID_METADATAEXTRACTOR)) { 123 index -= SL_OBJECTID_ENGINE - XA_OBJECTID_CAMERADEVICE - 1; 124 } else { 125 assert(false); 126 index = 0; 127 } 128 129 // first synchronously handle updates to attributes here, while object is still locked. 130 // This appears to be a loop, but actually typically runs through the loop only once. 131 unsigned asynchronous = attributes; 132 while (attributes) { 133 // this sequence is carefully crafted to be O(1); tread carefully when making changes 134 unsigned bit = ctz(attributes); 135 // ATTR_INDEX_MAX == next bit position after the last attribute 136 assert(ATTR_INDEX_MAX > bit); 137 // compute the entry in the handler table using object ID and bit number 138 AttributeHandler handler = handlerTable[index][bit]; 139 if (NULL != handler) { 140 asynchronous &= ~(*handler)(thiz); 141 } 142 attributes &= ~(1 << bit); 143 } 144 145 // any remaining attributes are handled asynchronously in the sync thread 146 if (asynchronous) { 147 unsigned oldAttributesMask = thiz->mAttributesMask; 148 thiz->mAttributesMask = oldAttributesMask | asynchronous; 149 if (oldAttributesMask) { 150 asynchronous = ATTR_NONE; 151 } 152 } 153 154#ifdef ANDROID 155 // FIXME hack to safely handle a post-unlock PrefetchStatus callback and/or AudioTrack::start() 156 slPrefetchCallback prefetchCallback = NULL; 157 void *prefetchContext = NULL; 158 SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE; 159 android::sp<android::AudioTrackProxy> audioTrack; 160 if (SL_OBJECTID_AUDIOPLAYER == objectID) { 161 CAudioPlayer *ap = (CAudioPlayer *) thiz; 162 prefetchCallback = ap->mPrefetchStatus.mDeferredPrefetchCallback; 163 prefetchContext = ap->mPrefetchStatus.mDeferredPrefetchContext; 164 prefetchEvents = ap->mPrefetchStatus.mDeferredPrefetchEvents; 165 ap->mPrefetchStatus.mDeferredPrefetchCallback = NULL; 166 // clearing these next two fields is not required, but avoids stale data during debugging 167 ap->mPrefetchStatus.mDeferredPrefetchContext = NULL; 168 ap->mPrefetchStatus.mDeferredPrefetchEvents = SL_PREFETCHEVENT_NONE; 169 if (ap->mDeferredStart) { 170 audioTrack = ap->mAudioTrack; 171 ap->mDeferredStart = false; 172 } 173 } 174#endif 175 176#ifdef USE_DEBUG 177 memset(&thiz->mOwner, 0, sizeof(pthread_t)); 178 thiz->mFile = file; 179 thiz->mLine = line; 180#endif 181 ok = pthread_mutex_unlock(&thiz->mMutex); 182 assert(0 == ok); 183 184#ifdef ANDROID 185 // FIXME call the prefetch status callback while not holding the mutex on AudioPlayer 186 if (NULL != prefetchCallback) { 187 // note these are synchronous by the application's thread as it is about to return from API 188 assert(prefetchEvents != SL_PREFETCHEVENT_NONE); 189 CAudioPlayer *ap = (CAudioPlayer *) thiz; 190 // spec requires separate callbacks for each event 191 if (SL_PREFETCHEVENT_STATUSCHANGE & prefetchEvents) { 192 (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext, 193 SL_PREFETCHEVENT_STATUSCHANGE); 194 } 195 if (SL_PREFETCHEVENT_FILLLEVELCHANGE & prefetchEvents) { 196 (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext, 197 SL_PREFETCHEVENT_FILLLEVELCHANGE); 198 } 199 } 200 201 // call AudioTrack::start() while not holding the mutex on AudioPlayer 202 if (audioTrack != 0) { 203 audioTrack->start(); 204 audioTrack.clear(); 205 } 206#endif 207 208 // first update to this interface since previous sync 209 if (ATTR_NONE != asynchronous) { 210 unsigned id = thiz->mInstanceID; 211 if (0 != id) { 212 --id; 213 assert(MAX_INSTANCE > id); 214 IEngine *thisEngine = &thiz->mEngine->mEngine; 215 // FIXME atomic or here 216 interface_lock_exclusive(thisEngine); 217 thisEngine->mChangedMask |= 1 << id; 218 interface_unlock_exclusive(thisEngine); 219 } 220 } 221 222} 223 224 225/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */ 226 227#ifdef USE_DEBUG 228void object_cond_wait_(IObject *thiz, const char *file, int line) 229{ 230 // note that this will unlock the mutex, so we have to clear the owner 231 assert(pthread_equal(pthread_self(), thiz->mOwner)); 232 assert(NULL != thiz->mFile); 233 assert(0 != thiz->mLine); 234 memset(&thiz->mOwner, 0, sizeof(pthread_t)); 235 thiz->mFile = file; 236 thiz->mLine = line; 237 // alas we don't know the new owner's identity 238 int ok; 239 ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex); 240 assert(0 == ok); 241 // restore my ownership 242 thiz->mOwner = pthread_self(); 243 thiz->mFile = file; 244 thiz->mLine = line; 245} 246#else 247void object_cond_wait(IObject *thiz) 248{ 249 int ok; 250 ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex); 251 assert(0 == ok); 252} 253#endif 254 255 256/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */ 257 258void object_cond_signal(IObject *thiz) 259{ 260 int ok; 261 ok = pthread_cond_signal(&thiz->mCond); 262 assert(0 == ok); 263} 264 265 266/** \brief Broadcast the condition variable associated with the object; 267 * see pthread_cond_broadcast 268 */ 269 270void object_cond_broadcast(IObject *thiz) 271{ 272 int ok; 273 ok = pthread_cond_broadcast(&thiz->mCond); 274 assert(0 == ok); 275} 276