locks.c revision fcc996296bdbf6c3949ad4312991fdde4ae2e157
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 SLuint32 objectID = IObjectToObjectID(thiz); 117 CAudioPlayer *ap; 118 119 // FIXME The endless if statements are getting ugly, should use bit search 120 121 // Android likes to see certain updates synchronously 122 123 if (attributes & ATTR_GAIN) { 124 switch (objectID) { 125 case SL_OBJECTID_AUDIOPLAYER: 126 attributes &= ~ATTR_GAIN; // no need to process asynchronously also 127 ap = (CAudioPlayer *) thiz; 128#ifdef ANDROID 129 android_audioPlayer_volumeUpdate(ap); 130#else 131 audioPlayerGainUpdate(ap); 132#endif 133 break; 134 case SL_OBJECTID_OUTPUTMIX: 135 // FIXME update gains on all players attached to this outputmix 136 SL_LOGD("[ FIXME: gain update on an SL_OBJECTID_OUTPUTMIX to be implemented ]"); 137 break; 138 case SL_OBJECTID_MIDIPLAYER: 139 // MIDI 140 SL_LOGD("[ FIXME: gain update on an SL_OBJECTID_MIDIPLAYER to be implemented ]"); 141 break; 142 case XA_OBJECTID_MEDIAPLAYER: { 143#ifdef ANDROID 144 attributes &= ~ATTR_GAIN; // no need to process asynchronously also 145 CMediaPlayer *mp = (CMediaPlayer *) thiz; 146 android::GenericPlayer* avp = mp->mAVPlayer.get(); 147 if (avp != NULL) { 148 android_Player_volumeUpdate(avp, &mp->mVolume); 149 } 150#endif 151 break; 152 } 153 default: 154 break; 155 } 156 } 157 158 if (attributes & ATTR_POSITION) { 159 switch (objectID) { 160 case SL_OBJECTID_AUDIOPLAYER: 161#ifdef ANDROID 162 ap = (CAudioPlayer *) thiz; 163 attributes &= ~ATTR_POSITION; // no need to process asynchronously also 164 android_audioPlayer_seek(ap, ap->mSeek.mPos); 165#else 166 //audioPlayerTransportUpdate(ap); 167#endif 168 break; 169 case SL_OBJECTID_MIDIPLAYER: 170 // MIDI 171 SL_LOGD("[ FIXME: position update on an SL_OBJECTID_MIDIPLAYER to be implemented ]"); 172 break; 173 default: 174 break; 175 } 176 } 177 178 if (attributes & ATTR_TRANSPORT) { 179 switch (objectID) { 180 case SL_OBJECTID_AUDIOPLAYER: 181#ifdef ANDROID 182 attributes &= ~ATTR_TRANSPORT; // no need to process asynchronously also 183 ap = (CAudioPlayer *) thiz; 184 // FIXME should only call when state changes 185 android_audioPlayer_setPlayState(ap, false /*lockAP*/); 186 // FIXME ditto, but for either eventflags or marker position 187 android_audioPlayer_useEventMask(ap); 188#else 189 //audioPlayerTransportUpdate(ap); 190#endif 191 break; 192 case SL_OBJECTID_AUDIORECORDER: 193#ifdef ANDROID 194 { 195 attributes &= ~ATTR_TRANSPORT; // no need to process asynchronously also 196 CAudioRecorder* ar = (CAudioRecorder *) thiz; 197 android_audioRecorder_useEventMask(ar); 198 } 199#endif 200 break; 201 case XA_OBJECTID_MEDIAPLAYER: 202#ifdef ANDROID 203 { 204 attributes &= ~ATTR_TRANSPORT; // no need to process asynchronously also 205 CMediaPlayer *mp = (CMediaPlayer *) thiz; 206 android::GenericPlayer* avp = mp->mAVPlayer.get(); 207 if (avp != NULL) { 208 android_Player_setPlayState(avp, mp->mPlay.mState, &(mp->mAndroidObjState)); 209 } 210 } 211#endif 212 break; 213 default: 214 break; 215 } 216 } 217 218 if (attributes & ATTR_BQ_ENQUEUE) { 219 // ( buffer queue count is non-empty and play state == PLAYING ) became true 220 if (SL_OBJECTID_AUDIOPLAYER == objectID) { 221 attributes &= ~ATTR_BQ_ENQUEUE; 222 ap = (CAudioPlayer *) thiz; 223 if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) { 224#ifdef ANDROID 225 android_audioPlayer_bufferQueue_onRefilled_l(ap); 226#endif 227 } 228 } 229#ifndef ANDROID 230 } 231#else 232 } else if (attributes & ATTR_ABQ_ENQUEUE) { 233 // (Android buffer queue count is non-empty and play state == PLAYING ) became true 234 if (SL_OBJECTID_AUDIOPLAYER == objectID) { 235 attributes &= ~ATTR_ABQ_ENQUEUE; 236 ap = (CAudioPlayer *) thiz; 237 if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) { 238 android_audioPlayer_androidBufferQueue_onRefilled_l(ap); 239 } 240 } else if (XA_OBJECTID_MEDIAPLAYER == objectID) { 241 attributes &= ~ATTR_ABQ_ENQUEUE; 242 CMediaPlayer* mp = (CMediaPlayer *)thiz; 243 if (SL_PLAYSTATE_PLAYING == mp->mPlay.mState) { 244 android_Player_androidBufferQueue_onRefilled_l(mp); 245 } 246 } 247 } 248#endif 249 250 if (attributes) { 251 unsigned oldAttributesMask = thiz->mAttributesMask; 252 thiz->mAttributesMask = oldAttributesMask | attributes; 253 if (oldAttributesMask) 254 attributes = ATTR_NONE; 255 } 256#ifdef USE_DEBUG 257 memset(&thiz->mOwner, 0, sizeof(pthread_t)); 258 thiz->mFile = file; 259 thiz->mLine = line; 260#endif 261 ok = pthread_mutex_unlock(&thiz->mMutex); 262 assert(0 == ok); 263 // first update to this interface since previous sync 264 if (attributes) { 265 unsigned id = thiz->mInstanceID; 266 if (0 != id) { 267 --id; 268 assert(MAX_INSTANCE > id); 269 IEngine *thisEngine = &thiz->mEngine->mEngine; 270 interface_lock_exclusive(thisEngine); 271 thisEngine->mChangedMask |= 1 << id; 272 interface_unlock_exclusive(thisEngine); 273 } 274 } 275} 276 277 278/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */ 279 280#ifdef USE_DEBUG 281void object_cond_wait_(IObject *thiz, const char *file, int line) 282{ 283 // note that this will unlock the mutex, so we have to clear the owner 284 assert(pthread_equal(pthread_self(), thiz->mOwner)); 285 assert(NULL != thiz->mFile); 286 assert(0 != thiz->mLine); 287 memset(&thiz->mOwner, 0, sizeof(pthread_t)); 288 thiz->mFile = file; 289 thiz->mLine = line; 290 // alas we don't know the new owner's identity 291 int ok; 292 ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex); 293 assert(0 == ok); 294 // restore my ownership 295 thiz->mOwner = pthread_self(); 296 thiz->mFile = file; 297 thiz->mLine = line; 298} 299#else 300void object_cond_wait(IObject *thiz) 301{ 302 int ok; 303 ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex); 304 assert(0 == ok); 305} 306#endif 307 308 309/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */ 310 311void object_cond_signal(IObject *thiz) 312{ 313 int ok; 314 ok = pthread_cond_signal(&thiz->mCond); 315 assert(0 == ok); 316} 317 318 319/** \brief Broadcast the condition variable associated with the object; 320 * see pthread_cond_broadcast 321 */ 322 323void object_cond_broadcast(IObject *thiz) 324{ 325 int ok; 326 ok = pthread_cond_broadcast(&thiz->mCond); 327 assert(0 == ok); 328} 329