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 
     35 void 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 
     45 void 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                 }
     91 forward_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
    124 void 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
    136 void 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
    149 void 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
    163 void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
    164     const char *file, int line)
    165 #else
    166 void 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
    289 void 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
    308 void 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 
    319 void 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 
    331 void object_cond_broadcast(IObject *thiz)
    332 {
    333     int ok;
    334     ok = pthread_cond_broadcast(&thiz->mCond);
    335     assert(0 == ok);
    336 }
    337