locks.c revision ae1a5c8dc1fccf7c121eda830f8d23bd094c0f16
1a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten/*
2a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
3a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten *
4a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * you may not use this file except in compliance with the License.
6a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * You may obtain a copy of the License at
7a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten *
8a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten *
10a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * See the License for the specific language governing permissions and
14a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten * limitations under the License.
15a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten */
16a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
17a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten#include "sles_allinclusive.h"
184ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten#include <bionic_pthread.h>
194ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten
204ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten
214ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// Use this macro to validate a pthread_t before passing it into __pthread_gettid.
224ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// One of the common reasons for deadlock is trying to lock a mutex for an object
234ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// which has been destroyed (which does memset to 0x00 or 0x55 as the final step).
244ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// To avoid crashing with a SIGSEGV right before we're about to log a deadlock warning,
254ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// we check that the pthread_t is probably valid.  Note that it is theoretically
264ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// possible for something to look like a valid pthread_t but not actually be valid.
274ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// So we might still crash, but only in the case where a deadlock was imminent anyway.
284ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten#define LIKELY_VALID(ptr) (((ptr) != (pthread_t) 0) && ((((size_t) (ptr)) & 3) == 0))
29a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
300b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
31928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Exclusively lock an object */
320b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
33fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
34bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_lock_exclusive_(IObject *thiz, const char *file, int line)
35fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten{
36fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    int ok;
37bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_trylock(&thiz->mMutex);
38fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    if (0 != ok) {
394ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        // not android_atomic_acquire_load because we don't care about relative load/load ordering
404ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        int32_t oldGeneration = thiz->mGeneration;
414ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        // wait up to a total of 250 ms
424ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        static const unsigned backoffs[] = {10, 20, 30, 40, 50, 100};
434f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        unsigned i = 0;
444f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        for (;;) {
454ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            // the Android version is in ms not timespec, and isn't named pthread_mutex_timedlock_np
464ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            ok = pthread_mutex_lock_timeout_np(&thiz->mMutex, backoffs[i]);
474ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            if (0 == ok) {
484f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten                break;
494ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            }
504ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            if (EBUSY == ok) {
514ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // this is the expected return value for timeout, and will be handled below
524ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            } else if (EDEADLK == ok) {
534ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // we don't use the kind of mutex that can return this error, but just in case
544ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                SL_LOGE("%s:%d: recursive lock detected", file, line);
554ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            } else {
564ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // some other return value
574ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                SL_LOGE("%s:%d: pthread_mutex_lock_timeout_np returned %d", file, line, ok);
584ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            }
594ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            // is anyone else making forward progress?
604ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            int32_t newGeneration = thiz->mGeneration;
614ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            if (newGeneration != oldGeneration) {
624ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // if we ever see forward progress then lock without timeout (more efficient)
634ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                goto forward_progress;
644ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            }
654ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            // no, then continue trying to lock but with increasing timeouts
664f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten            if (++i >= (sizeof(backoffs) / sizeof(backoffs[0]))) {
674ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // the extra block avoids a C++ compiler error about goto past initialization
684ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                {
694ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    pthread_t me = pthread_self();
704ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    pthread_t owner = thiz->mOwner;
714ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    // unlikely, but this could result in a memory fault if owner is corrupt
724ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    pid_t ownerTid = LIKELY_VALID(owner) ? __pthread_gettid(owner) : -1;
734ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    SL_LOGW("%s:%d: pthread %p (tid %d) sees object %p was locked by pthread %p"
744ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                            " (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
754ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                            *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
764ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                }
774ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kastenforward_progress:
784ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // attempt one more time without timeout; maybe this time we will be successful
79bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                ok = pthread_mutex_lock(&thiz->mMutex);
804f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten                assert(0 == ok);
814f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten                break;
824f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten            }
834f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        }
84fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    }
854ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    // here if mutex was successfully locked
86fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    pthread_t zero;
87fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    memset(&zero, 0, sizeof(pthread_t));
88bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
894ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        pthread_t me = pthread_self();
904ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        pthread_t owner = thiz->mOwner;
914ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        pid_t ownerTid = LIKELY_VALID(owner) ? __pthread_gettid(owner) : -1;
924ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        if (pthread_equal(pthread_self(), owner)) {
934ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was recursively locked by pthread"
944ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    " %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
954ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
964f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        } else {
974ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was left unlocked in unexpected"
984ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    " state by pthread %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(),
994ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    thiz, *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
1004f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        }
1014f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        assert(false);
1024f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    }
103bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mOwner = pthread_self();
104bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
105bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
1064ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    // not android_atomic_inc because we are already holding a mutex
1074ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    ++thiz->mGeneration;
108fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten}
109fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#else
110bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_lock_exclusive(IObject *thiz)
111a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten{
112a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
113bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_lock(&thiz->mMutex);
114a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
115a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
116fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
117a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
1180b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
119928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Exclusively unlock an object and do not report any updates */
1200b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
121fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
122bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive_(IObject *thiz, const char *file, int line)
1234597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten{
124bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(pthread_equal(pthread_self(), thiz->mOwner));
125bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz->mFile);
126bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 != thiz->mLine);
127bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
128bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
129bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
130a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
131bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_unlock(&thiz->mMutex);
132a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
133a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
1344597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#else
135bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive(IObject *thiz)
1364597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten{
1374597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    int ok;
138bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_unlock(&thiz->mMutex);
1394597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    assert(0 == ok);
1404597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten}
1414597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#endif
142a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
1430b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
144928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Exclusively unlock an object and report updates to the specified bit-mask of
145928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten *  attributes
146928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */
1470b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
1484597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#ifdef USE_DEBUG
149bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
1504597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    const char *file, int line)
1514597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#else
152bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes)
1534597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#endif
154e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{
155fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten
156fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
157bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(pthread_equal(pthread_self(), thiz->mOwner));
158bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz->mFile);
159bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 != thiz->mLine);
160fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
161fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten
162e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    int ok;
1633c170255cc71942f310b676d968cf73328aa5d70Jean-Michel Trivi
1647b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // make SL object IDs be contiguous with XA object IDs
1657b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    SLuint32 objectID = IObjectToObjectID(thiz);
16647550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    SLuint32 index = objectID;
16747550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    if ((XA_OBJECTID_ENGINE <= index) && (index <= XA_OBJECTID_CAMERADEVICE)) {
1687b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        ;
16947550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    } else if ((SL_OBJECTID_ENGINE <= index) && (index <= SL_OBJECTID_METADATAEXTRACTOR)) {
17047550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        index -= SL_OBJECTID_ENGINE - XA_OBJECTID_CAMERADEVICE - 1;
1717b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    } else {
1727b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        assert(false);
17347550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        index = 0;
1743c170255cc71942f310b676d968cf73328aa5d70Jean-Michel Trivi    }
1753c170255cc71942f310b676d968cf73328aa5d70Jean-Michel Trivi
1767b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // first synchronously handle updates to attributes here, while object is still locked.
1777b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // This appears to be a loop, but actually typically runs through the loop only once.
1787b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    unsigned asynchronous = attributes;
1797b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    while (attributes) {
1807b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        // this sequence is carefully crafted to be O(1); tread carefully when making changes
1817b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        unsigned bit = ctz(attributes);
1827b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        // ATTR_INDEX_MAX == next bit position after the last attribute
1837b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        assert(ATTR_INDEX_MAX > bit);
1847b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        // compute the entry in the handler table using object ID and bit number
18547550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        AttributeHandler handler = handlerTable[index][bit];
1867b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        if (NULL != handler) {
1877b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten            asynchronous &= ~(*handler)(thiz);
188e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        }
1897b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        attributes &= ~(1 << bit);
190e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
1914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1927b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // any remaining attributes are handled asynchronously in the sync thread
1937b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    if (asynchronous) {
1947b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        unsigned oldAttributesMask = thiz->mAttributesMask;
1957b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        thiz->mAttributesMask = oldAttributesMask | asynchronous;
1967b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        if (oldAttributesMask) {
1977b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten            asynchronous = ATTR_NONE;
198d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        }
199d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
2004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
20147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#ifdef ANDROID
202a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    // FIXME hack to safely handle a post-unlock PrefetchStatus callback and/or AudioTrack::start()
203a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    slPrefetchCallback prefetchCallback = NULL;
204a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    void *prefetchContext = NULL;
205a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
206ae1a5c8dc1fccf7c121eda830f8d23bd094c0f16Glenn Kasten    android::sp<android::AudioTrack> audioTrack;
20747550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    if (SL_OBJECTID_AUDIOPLAYER == objectID) {
20847550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        CAudioPlayer *ap = (CAudioPlayer *) thiz;
209a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        prefetchCallback = ap->mPrefetchStatus.mDeferredPrefetchCallback;
210a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        prefetchContext  = ap->mPrefetchStatus.mDeferredPrefetchContext;
211a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        prefetchEvents   = ap->mPrefetchStatus.mDeferredPrefetchEvents;
212a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        ap->mPrefetchStatus.mDeferredPrefetchCallback = NULL;
213a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        // clearing these next two fields is not required, but avoids stale data during debugging
214a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        ap->mPrefetchStatus.mDeferredPrefetchContext  = NULL;
215a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        ap->mPrefetchStatus.mDeferredPrefetchEvents   = SL_PREFETCHEVENT_NONE;
21647550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        if (ap->mDeferredStart) {
21747550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten            audioTrack = ap->mAudioTrack;
21847550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten            ap->mDeferredStart = false;
21947550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        }
22047550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    }
22147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#endif
22247550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten
223fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
224bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
225bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
226bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
227fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
228bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_unlock(&thiz->mMutex);
229e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    assert(0 == ok);
2307b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten
23147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#ifdef ANDROID
232a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    // FIXME call the prefetch status callback while not holding the mutex on AudioPlayer
233a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    if (NULL != prefetchCallback) {
234a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        // note these are synchronous by the application's thread as it is about to return from API
235a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        assert(prefetchEvents != SL_PREFETCHEVENT_NONE);
236a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        CAudioPlayer *ap = (CAudioPlayer *) thiz;
237a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        // spec requires separate callbacks for each event
238a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        if (SL_PREFETCHEVENT_STATUSCHANGE & prefetchEvents) {
239a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten            (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
240a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten                    SL_PREFETCHEVENT_STATUSCHANGE);
241a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        }
242a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        if (SL_PREFETCHEVENT_FILLLEVELCHANGE & prefetchEvents) {
243a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten            (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
244a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten                    SL_PREFETCHEVENT_FILLLEVELCHANGE);
245a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        }
246a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    }
247a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten
24847550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    // call AudioTrack::start() while not holding the mutex on AudioPlayer
24947550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    if (audioTrack != 0) {
25047550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        audioTrack->start();
25147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        audioTrack.clear();
25247550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    }
25347550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#endif
25447550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten
255f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // first update to this interface since previous sync
2567b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    if (ATTR_NONE != asynchronous) {
257bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        unsigned id = thiz->mInstanceID;
258f51dba65751107c930759938775b75531ec1f330Glenn Kasten        if (0 != id) {
259f51dba65751107c930759938775b75531ec1f330Glenn Kasten            --id;
260f51dba65751107c930759938775b75531ec1f330Glenn Kasten            assert(MAX_INSTANCE > id);
261bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            IEngine *thisEngine = &thiz->mEngine->mEngine;
2627b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten            // FIXME atomic or here
263f51dba65751107c930759938775b75531ec1f330Glenn Kasten            interface_lock_exclusive(thisEngine);
264f51dba65751107c930759938775b75531ec1f330Glenn Kasten            thisEngine->mChangedMask |= 1 << id;
265f51dba65751107c930759938775b75531ec1f330Glenn Kasten            interface_unlock_exclusive(thisEngine);
266f51dba65751107c930759938775b75531ec1f330Glenn Kasten        }
267e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
2687b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten
269e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten}
270e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
2710b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
272928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
2730b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
2744f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten#ifdef USE_DEBUG
275bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_wait_(IObject *thiz, const char *file, int line)
2764f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten{
2774f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    // note that this will unlock the mutex, so we have to clear the owner
278bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(pthread_equal(pthread_self(), thiz->mOwner));
279bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz->mFile);
280bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 != thiz->mLine);
281bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
282bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
283bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
2844f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    // alas we don't know the new owner's identity
2854f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    int ok;
286bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
2874f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    assert(0 == ok);
2884f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    // restore my ownership
289bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mOwner = pthread_self();
290bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
291bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
2924f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten}
2934f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten#else
294bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_wait(IObject *thiz)
295a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten{
296a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
297bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
298a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
299a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
3004f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten#endif
301a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
3020b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
303928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
3040b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
305bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_signal(IObject *thiz)
306a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten{
307a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
308bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_signal(&thiz->mCond);
309a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
310a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
311a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten
3120b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
313928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Broadcast the condition variable associated with the object;
314928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten *  see pthread_cond_broadcast
315928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */
3160b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
317bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_broadcast(IObject *thiz)
318a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten{
319a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten    int ok;
320bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_broadcast(&thiz->mCond);
321a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten    assert(0 == ok);
322a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten}
323