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 
     19 
     20 // Use this macro to validate a pthread_t before passing it into pthread_gettid_np.
     21 // One of the common reasons for deadlock is trying to lock a mutex for an object
     22 // which has been destroyed (which does memset to 0x00 or 0x55 as the final step).
     23 // To avoid crashing with a SIGSEGV right before we're about to log a deadlock warning,
     24 // we check that the pthread_t is probably valid.  Note that it is theoretically
     25 // possible for something to look like a valid pthread_t but not actually be valid.
     26 // So we might still crash, but only in the case where a deadlock was imminent anyway.
     27 #define LIKELY_VALID(ptr) (((ptr) != (pthread_t) 0) && ((((size_t) (ptr)) & 3) == 0))
     28 
     29 
     30 /** \brief Exclusively lock an object */
     31 
     32 #ifdef USE_DEBUG
     33 
     34 void init_time_spec(timespec* ts, long delta) {
     35     clock_gettime(CLOCK_REALTIME, ts);
     36     ts->tv_nsec += delta;
     37 
     38     if (ts->tv_nsec >= 1000000000L) {
     39         ts->tv_sec++;
     40         ts->tv_nsec -= 1000000000L;
     41     }
     42 }
     43 
     44 void object_lock_exclusive_(IObject *thiz, const char *file, int line)
     45 {
     46     int ok;
     47     ok = pthread_mutex_trylock(&thiz->mMutex);
     48     if (0 != ok) {
     49         // not android_atomic_acquire_load because we don't care about relative load/load ordering
     50         int32_t oldGeneration = thiz->mGeneration;
     51         // wait up to a total of 250 ms
     52         static const long nanoBackoffs[] = {
     53             10 * 1000000, 20 * 1000000, 30 * 1000000, 40 * 1000000, 50 * 1000000, 100 * 1000000};
     54         unsigned i = 0;
     55         timespec ts;
     56         memset(&ts, 0, sizeof(timespec));
     57         for (;;) {
     58             init_time_spec(&ts, nanoBackoffs[i]);
     59             ok = pthread_mutex_timedlock(&thiz->mMutex, &ts);
     60             if (0 == ok) {
     61                 break;
     62             }
     63             if (EBUSY == ok) {
     64                 // this is the expected return value for timeout, and will be handled below
     65             } else if (EDEADLK == ok) {
     66                 // we don't use the kind of mutex that can return this error, but just in case
     67                 SL_LOGE("%s:%d: recursive lock detected", file, line);
     68             } else {
     69                 // some other return value
     70                 SL_LOGE("%s:%d: pthread_mutex_lock_timeout_np returned %d", file, line, ok);
     71             }
     72             // is anyone else making forward progress?
     73             int32_t newGeneration = thiz->mGeneration;
     74             if (newGeneration != oldGeneration) {
     75                 // if we ever see forward progress then lock without timeout (more efficient)
     76                 goto forward_progress;
     77             }
     78             // no, then continue trying to lock but with increasing timeouts
     79             if (++i >= (sizeof(nanoBackoffs) / sizeof(nanoBackoffs[0]))) {
     80                 // the extra block avoids a C++ compiler error about goto past initialization
     81                 {
     82                     pthread_t me = pthread_self();
     83                     pthread_t owner = thiz->mOwner;
     84                     // unlikely, but this could result in a memory fault if owner is corrupt
     85                     pid_t ownerTid = LIKELY_VALID(owner) ? pthread_gettid_np(owner) : -1;
     86                     SL_LOGW("%s:%d: pthread %p (tid %d) sees object %p was locked by pthread %p"
     87                             " (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
     88                             *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
     89                 }
     90 forward_progress:
     91                 // attempt one more time without timeout; maybe this time we will be successful
     92                 ok = pthread_mutex_lock(&thiz->mMutex);
     93                 assert(0 == ok);
     94                 break;
     95             }
     96         }
     97     }
     98     // here if mutex was successfully locked
     99     pthread_t zero;
    100     memset(&zero, 0, sizeof(pthread_t));
    101     if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
    102         pthread_t me = pthread_self();
    103         pthread_t owner = thiz->mOwner;
    104         pid_t ownerTid = LIKELY_VALID(owner) ? pthread_gettid_np(owner) : -1;
    105         if (pthread_equal(pthread_self(), owner)) {
    106             SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was recursively locked by pthread"
    107                     " %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
    108                     *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
    109         } else {
    110             SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was left unlocked in unexpected"
    111                     " state by pthread %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(),
    112                     thiz, *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
    113         }
    114         assert(false);
    115     }
    116     thiz->mOwner = pthread_self();
    117     thiz->mFile = file;
    118     thiz->mLine = line;
    119     // not android_atomic_inc because we are already holding a mutex
    120     ++thiz->mGeneration;
    121 }
    122 #else
    123 void object_lock_exclusive(IObject *thiz)
    124 {
    125     int ok;
    126     ok = pthread_mutex_lock(&thiz->mMutex);
    127     assert(0 == ok);
    128 }
    129 #endif
    130 
    131 
    132 /** \brief Exclusively unlock an object and do not report any updates */
    133 
    134 #ifdef USE_DEBUG
    135 void object_unlock_exclusive_(IObject *thiz, const char *file, int line)
    136 {
    137     assert(pthread_equal(pthread_self(), thiz->mOwner));
    138     assert(NULL != thiz->mFile);
    139     assert(0 != thiz->mLine);
    140     memset(&thiz->mOwner, 0, sizeof(pthread_t));
    141     thiz->mFile = file;
    142     thiz->mLine = line;
    143     int ok;
    144     ok = pthread_mutex_unlock(&thiz->mMutex);
    145     assert(0 == ok);
    146 }
    147 #else
    148 void object_unlock_exclusive(IObject *thiz)
    149 {
    150     int ok;
    151     ok = pthread_mutex_unlock(&thiz->mMutex);
    152     assert(0 == ok);
    153 }
    154 #endif
    155 
    156 
    157 /** \brief Exclusively unlock an object and report updates to the specified bit-mask of
    158  *  attributes
    159  */
    160 
    161 #ifdef USE_DEBUG
    162 void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
    163     const char *file, int line)
    164 #else
    165 void object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes)
    166 #endif
    167 {
    168 
    169 #ifdef USE_DEBUG
    170     assert(pthread_equal(pthread_self(), thiz->mOwner));
    171     assert(NULL != thiz->mFile);
    172     assert(0 != thiz->mLine);
    173 #endif
    174 
    175     int ok;
    176 
    177     // make SL object IDs be contiguous with XA object IDs
    178     SLuint32 objectID = IObjectToObjectID(thiz);
    179     SLuint32 index = objectID;
    180     if ((XA_OBJECTID_ENGINE <= index) && (index <= XA_OBJECTID_CAMERADEVICE)) {
    181         ;
    182     } else if ((SL_OBJECTID_ENGINE <= index) && (index <= SL_OBJECTID_METADATAEXTRACTOR)) {
    183         index -= SL_OBJECTID_ENGINE - XA_OBJECTID_CAMERADEVICE - 1;
    184     } else {
    185         assert(false);
    186         index = 0;
    187     }
    188 
    189     // first synchronously handle updates to attributes here, while object is still locked.
    190     // This appears to be a loop, but actually typically runs through the loop only once.
    191     unsigned asynchronous = attributes;
    192     while (attributes) {
    193         // this sequence is carefully crafted to be O(1); tread carefully when making changes
    194         unsigned bit = ctz(attributes);
    195         // ATTR_INDEX_MAX == next bit position after the last attribute
    196         assert(ATTR_INDEX_MAX > bit);
    197         // compute the entry in the handler table using object ID and bit number
    198         AttributeHandler handler = handlerTable[index][bit];
    199         if (NULL != handler) {
    200             asynchronous &= ~(*handler)(thiz);
    201         }
    202         attributes &= ~(1 << bit);
    203     }
    204 
    205     // any remaining attributes are handled asynchronously in the sync thread
    206     if (asynchronous) {
    207         unsigned oldAttributesMask = thiz->mAttributesMask;
    208         thiz->mAttributesMask = oldAttributesMask | asynchronous;
    209         if (oldAttributesMask) {
    210             asynchronous = ATTR_NONE;
    211         }
    212     }
    213 
    214 #ifdef ANDROID
    215     // FIXME hack to safely handle a post-unlock PrefetchStatus callback and/or AudioTrack::start()
    216     slPrefetchCallback prefetchCallback = NULL;
    217     void *prefetchContext = NULL;
    218     SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
    219     android::sp<android::AudioTrack> audioTrack;
    220     if (SL_OBJECTID_AUDIOPLAYER == objectID) {
    221         CAudioPlayer *ap = (CAudioPlayer *) thiz;
    222         prefetchCallback = ap->mPrefetchStatus.mDeferredPrefetchCallback;
    223         prefetchContext  = ap->mPrefetchStatus.mDeferredPrefetchContext;
    224         prefetchEvents   = ap->mPrefetchStatus.mDeferredPrefetchEvents;
    225         ap->mPrefetchStatus.mDeferredPrefetchCallback = NULL;
    226         // clearing these next two fields is not required, but avoids stale data during debugging
    227         ap->mPrefetchStatus.mDeferredPrefetchContext  = NULL;
    228         ap->mPrefetchStatus.mDeferredPrefetchEvents   = SL_PREFETCHEVENT_NONE;
    229         if (ap->mDeferredStart) {
    230             audioTrack = ap->mTrackPlayer->mAudioTrack;
    231             ap->mDeferredStart = false;
    232         }
    233     }
    234 #endif
    235 
    236 #ifdef USE_DEBUG
    237     memset(&thiz->mOwner, 0, sizeof(pthread_t));
    238     thiz->mFile = file;
    239     thiz->mLine = line;
    240 #endif
    241     ok = pthread_mutex_unlock(&thiz->mMutex);
    242     assert(0 == ok);
    243 
    244 #ifdef ANDROID
    245     // FIXME call the prefetch status callback while not holding the mutex on AudioPlayer
    246     if (NULL != prefetchCallback) {
    247         // note these are synchronous by the application's thread as it is about to return from API
    248         assert(prefetchEvents != SL_PREFETCHEVENT_NONE);
    249         CAudioPlayer *ap = (CAudioPlayer *) thiz;
    250         // spec requires separate callbacks for each event
    251         if (SL_PREFETCHEVENT_STATUSCHANGE & prefetchEvents) {
    252             (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
    253                     SL_PREFETCHEVENT_STATUSCHANGE);
    254         }
    255         if (SL_PREFETCHEVENT_FILLLEVELCHANGE & prefetchEvents) {
    256             (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
    257                     SL_PREFETCHEVENT_FILLLEVELCHANGE);
    258         }
    259     }
    260 
    261     // call AudioTrack::start() while not holding the mutex on AudioPlayer
    262     if (audioTrack != 0) {
    263         audioTrack->start();
    264         audioTrack.clear();
    265     }
    266 #endif
    267 
    268     // first update to this interface since previous sync
    269     if (ATTR_NONE != asynchronous) {
    270         unsigned id = thiz->mInstanceID;
    271         if (0 != id) {
    272             --id;
    273             assert(MAX_INSTANCE > id);
    274             IEngine *thisEngine = &thiz->mEngine->mEngine;
    275             // FIXME atomic or here
    276             interface_lock_exclusive(thisEngine);
    277             thisEngine->mChangedMask |= 1 << id;
    278             interface_unlock_exclusive(thisEngine);
    279         }
    280     }
    281 
    282 }
    283 
    284 
    285 /** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
    286 
    287 #ifdef USE_DEBUG
    288 void object_cond_wait_(IObject *thiz, const char *file, int line)
    289 {
    290     // note that this will unlock the mutex, so we have to clear the owner
    291     assert(pthread_equal(pthread_self(), thiz->mOwner));
    292     assert(NULL != thiz->mFile);
    293     assert(0 != thiz->mLine);
    294     memset(&thiz->mOwner, 0, sizeof(pthread_t));
    295     thiz->mFile = file;
    296     thiz->mLine = line;
    297     // alas we don't know the new owner's identity
    298     int ok;
    299     ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
    300     assert(0 == ok);
    301     // restore my ownership
    302     thiz->mOwner = pthread_self();
    303     thiz->mFile = file;
    304     thiz->mLine = line;
    305 }
    306 #else
    307 void object_cond_wait(IObject *thiz)
    308 {
    309     int ok;
    310     ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
    311     assert(0 == ok);
    312 }
    313 #endif
    314 
    315 
    316 /** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
    317 
    318 void object_cond_signal(IObject *thiz)
    319 {
    320     int ok;
    321     ok = pthread_cond_signal(&thiz->mCond);
    322     assert(0 == ok);
    323 }
    324 
    325 
    326 /** \brief Broadcast the condition variable associated with the object;
    327  *  see pthread_cond_broadcast
    328  */
    329 
    330 void object_cond_broadcast(IObject *thiz)
    331 {
    332     int ok;
    333     ok = pthread_cond_broadcast(&thiz->mCond);
    334     assert(0 == ok);
    335 }
    336