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