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
194ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten
20d3adefc646c15be3f6ba73b6afaaa610f4538246Elliott Hughes// Use this macro to validate a pthread_t before passing it into pthread_gettid_np.
214ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// One of the common reasons for deadlock is trying to lock a mutex for an object
224ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// which has been destroyed (which does memset to 0x00 or 0x55 as the final step).
234ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// To avoid crashing with a SIGSEGV right before we're about to log a deadlock warning,
244ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// we check that the pthread_t is probably valid.  Note that it is theoretically
254ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// possible for something to look like a valid pthread_t but not actually be valid.
264ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten// So we might still crash, but only in the case where a deadlock was imminent anyway.
274ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten#define LIKELY_VALID(ptr) (((ptr) != (pthread_t) 0) && ((((size_t) (ptr)) & 3) == 0))
28a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
290b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
30928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Exclusively lock an object */
310b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
32fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
337e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath
347e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamathvoid init_time_spec(timespec* ts, long delta) {
357e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath    clock_gettime(CLOCK_REALTIME, ts);
367e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath    ts->tv_nsec += delta;
377e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath
387e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath    if (ts->tv_nsec >= 1000000000L) {
397e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath        ts->tv_sec++;
407e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath        ts->tv_nsec -= 1000000000L;
417e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath    }
427e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath}
437e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath
44bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_lock_exclusive_(IObject *thiz, const char *file, int line)
45fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten{
46fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    int ok;
47bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_trylock(&thiz->mMutex);
48fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    if (0 != ok) {
494ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        // not android_atomic_acquire_load because we don't care about relative load/load ordering
504ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        int32_t oldGeneration = thiz->mGeneration;
514ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        // wait up to a total of 250 ms
527e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath        static const long nanoBackoffs[] = {
537e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath            10 * 1000000, 20 * 1000000, 30 * 1000000, 40 * 1000000, 50 * 1000000, 100 * 1000000};
544f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        unsigned i = 0;
557e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath        timespec ts;
567e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath        memset(&ts, 0, sizeof(timespec));
574f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        for (;;) {
587e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath            init_time_spec(&ts, nanoBackoffs[i]);
597e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath            ok = pthread_mutex_timedlock(&thiz->mMutex, &ts);
604ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            if (0 == ok) {
614f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten                break;
624ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            }
634ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            if (EBUSY == ok) {
644ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // this is the expected return value for timeout, and will be handled below
654ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            } else if (EDEADLK == ok) {
664ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // we don't use the kind of mutex that can return this error, but just in case
674ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                SL_LOGE("%s:%d: recursive lock detected", file, line);
684ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            } else {
694ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // some other return value
704ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                SL_LOGE("%s:%d: pthread_mutex_lock_timeout_np returned %d", file, line, ok);
714ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            }
724ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            // is anyone else making forward progress?
734ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            int32_t newGeneration = thiz->mGeneration;
744ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            if (newGeneration != oldGeneration) {
754ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // if we ever see forward progress then lock without timeout (more efficient)
764ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                goto forward_progress;
774ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            }
784ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            // no, then continue trying to lock but with increasing timeouts
797e7826821d0e82c13a4f9f34525d0cdaf323f34aNarayan Kamath            if (++i >= (sizeof(nanoBackoffs) / sizeof(nanoBackoffs[0]))) {
804ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // the extra block avoids a C++ compiler error about goto past initialization
814ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                {
824ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    pthread_t me = pthread_self();
834ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    pthread_t owner = thiz->mOwner;
844ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    // unlikely, but this could result in a memory fault if owner is corrupt
85d3adefc646c15be3f6ba73b6afaaa610f4538246Elliott Hughes                    pid_t ownerTid = LIKELY_VALID(owner) ? pthread_gettid_np(owner) : -1;
864ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    SL_LOGW("%s:%d: pthread %p (tid %d) sees object %p was locked by pthread %p"
874ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                            " (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
884ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                            *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
894ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                }
904ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kastenforward_progress:
914ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                // attempt one more time without timeout; maybe this time we will be successful
92bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten                ok = pthread_mutex_lock(&thiz->mMutex);
934f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten                assert(0 == ok);
944f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten                break;
954f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten            }
964f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        }
97fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    }
984ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    // here if mutex was successfully locked
99fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    pthread_t zero;
100fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten    memset(&zero, 0, sizeof(pthread_t));
101bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
1024ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        pthread_t me = pthread_self();
1034ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        pthread_t owner = thiz->mOwner;
104d3adefc646c15be3f6ba73b6afaaa610f4538246Elliott Hughes        pid_t ownerTid = LIKELY_VALID(owner) ? pthread_gettid_np(owner) : -1;
1054ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten        if (pthread_equal(pthread_self(), owner)) {
1064ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was recursively locked by pthread"
1074ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    " %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(), thiz,
1084ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
1094f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        } else {
1104ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten            SL_LOGE("%s:%d: pthread %p (tid %d) sees object %p was left unlocked in unexpected"
1114ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    " state by pthread %p (tid %d) at %s:%d\n", file, line, *(void **)&me, gettid(),
1124ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten                    thiz, *(void **)&owner, ownerTid, thiz->mFile, thiz->mLine);
1134f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        }
1144f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten        assert(false);
1154f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    }
116bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mOwner = pthread_self();
117bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
118bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
1194ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    // not android_atomic_inc because we are already holding a mutex
1204ce38604afa7e4f629d568f400b0634504e60a2eGlenn Kasten    ++thiz->mGeneration;
121fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten}
122fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#else
123bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_lock_exclusive(IObject *thiz)
124a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten{
125a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
126bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_lock(&thiz->mMutex);
127a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
128a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
129fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
130a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
1310b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
132928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Exclusively unlock an object and do not report any updates */
1330b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
134fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
135bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive_(IObject *thiz, const char *file, int line)
1364597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten{
137bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(pthread_equal(pthread_self(), thiz->mOwner));
138bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz->mFile);
139bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 != thiz->mLine);
140bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
141bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
142bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
143a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
144bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_unlock(&thiz->mMutex);
145a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
146a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
1474597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#else
148bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive(IObject *thiz)
1494597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten{
1504597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    int ok;
151bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_unlock(&thiz->mMutex);
1524597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    assert(0 == ok);
1534597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten}
1544597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#endif
155a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
1560b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
157928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Exclusively unlock an object and report updates to the specified bit-mask of
158928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten *  attributes
159928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */
1600b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
1614597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#ifdef USE_DEBUG
162bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
1634597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten    const char *file, int line)
1644597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#else
165bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes)
1664597a7427b697df31d0bbf4c2040806d0c27b6e0Glenn Kasten#endif
167e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{
168fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten
169fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
170bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(pthread_equal(pthread_self(), thiz->mOwner));
171bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz->mFile);
172bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 != thiz->mLine);
173fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
174fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten
175e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    int ok;
1763c170255cc71942f310b676d968cf73328aa5d70Jean-Michel Trivi
1777b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // make SL object IDs be contiguous with XA object IDs
1787b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    SLuint32 objectID = IObjectToObjectID(thiz);
17947550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    SLuint32 index = objectID;
18047550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    if ((XA_OBJECTID_ENGINE <= index) && (index <= XA_OBJECTID_CAMERADEVICE)) {
1817b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        ;
18247550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    } else if ((SL_OBJECTID_ENGINE <= index) && (index <= SL_OBJECTID_METADATAEXTRACTOR)) {
18347550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        index -= SL_OBJECTID_ENGINE - XA_OBJECTID_CAMERADEVICE - 1;
1847b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    } else {
1857b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        assert(false);
18647550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        index = 0;
1873c170255cc71942f310b676d968cf73328aa5d70Jean-Michel Trivi    }
1883c170255cc71942f310b676d968cf73328aa5d70Jean-Michel Trivi
1897b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // first synchronously handle updates to attributes here, while object is still locked.
1907b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // This appears to be a loop, but actually typically runs through the loop only once.
1917b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    unsigned asynchronous = attributes;
1927b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    while (attributes) {
1937b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        // this sequence is carefully crafted to be O(1); tread carefully when making changes
1947b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        unsigned bit = ctz(attributes);
1957b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        // ATTR_INDEX_MAX == next bit position after the last attribute
1967b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        assert(ATTR_INDEX_MAX > bit);
1977b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        // compute the entry in the handler table using object ID and bit number
19847550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        AttributeHandler handler = handlerTable[index][bit];
1997b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        if (NULL != handler) {
2007b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten            asynchronous &= ~(*handler)(thiz);
201e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        }
2027b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        attributes &= ~(1 << bit);
203e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
2044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2057b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    // any remaining attributes are handled asynchronously in the sync thread
2067b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    if (asynchronous) {
2077b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        unsigned oldAttributesMask = thiz->mAttributesMask;
2087b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        thiz->mAttributesMask = oldAttributesMask | asynchronous;
2097b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten        if (oldAttributesMask) {
2107b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten            asynchronous = ATTR_NONE;
211d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi        }
212d158d31a6bbb06426b71c3d097b7768bc3fb79a3Jean-Michel Trivi    }
2134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
21447550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#ifdef ANDROID
215a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    // FIXME hack to safely handle a post-unlock PrefetchStatus callback and/or AudioTrack::start()
216a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    slPrefetchCallback prefetchCallback = NULL;
217a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    void *prefetchContext = NULL;
218a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
219ae1a5c8dc1fccf7c121eda830f8d23bd094c0f16Glenn Kasten    android::sp<android::AudioTrack> audioTrack;
22047550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    if (SL_OBJECTID_AUDIOPLAYER == objectID) {
22147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        CAudioPlayer *ap = (CAudioPlayer *) thiz;
222a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        prefetchCallback = ap->mPrefetchStatus.mDeferredPrefetchCallback;
223a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        prefetchContext  = ap->mPrefetchStatus.mDeferredPrefetchContext;
224a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        prefetchEvents   = ap->mPrefetchStatus.mDeferredPrefetchEvents;
225a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        ap->mPrefetchStatus.mDeferredPrefetchCallback = NULL;
226a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        // clearing these next two fields is not required, but avoids stale data during debugging
227a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        ap->mPrefetchStatus.mDeferredPrefetchContext  = NULL;
228a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        ap->mPrefetchStatus.mDeferredPrefetchEvents   = SL_PREFETCHEVENT_NONE;
22947550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        if (ap->mDeferredStart) {
23047550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten            audioTrack = ap->mAudioTrack;
23147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten            ap->mDeferredStart = false;
23247550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        }
23347550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    }
23447550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#endif
23547550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten
236fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#ifdef USE_DEBUG
237bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
238bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
239bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
240fe96fa06360516c60490c7a697e1148017b4c1b2Glenn Kasten#endif
241bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_mutex_unlock(&thiz->mMutex);
242e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    assert(0 == ok);
2437b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten
24447550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#ifdef ANDROID
245a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    // FIXME call the prefetch status callback while not holding the mutex on AudioPlayer
246a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    if (NULL != prefetchCallback) {
247a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        // note these are synchronous by the application's thread as it is about to return from API
248a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        assert(prefetchEvents != SL_PREFETCHEVENT_NONE);
249a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        CAudioPlayer *ap = (CAudioPlayer *) thiz;
250a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        // spec requires separate callbacks for each event
251a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        if (SL_PREFETCHEVENT_STATUSCHANGE & prefetchEvents) {
252a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten            (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
253a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten                    SL_PREFETCHEVENT_STATUSCHANGE);
254a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        }
255a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        if (SL_PREFETCHEVENT_FILLLEVELCHANGE & prefetchEvents) {
256a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten            (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
257a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten                    SL_PREFETCHEVENT_FILLLEVELCHANGE);
258a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten        }
259a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten    }
260a60dbf554549d10780f473b6e1373aa07aec3a28Glenn Kasten
26147550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    // call AudioTrack::start() while not holding the mutex on AudioPlayer
26247550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    if (audioTrack != 0) {
26347550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        audioTrack->start();
26447550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten        audioTrack.clear();
26547550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten    }
26647550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten#endif
26747550bf6cf5cf08a402a54b1589f4b64582a5120Glenn Kasten
268f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // first update to this interface since previous sync
2697b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten    if (ATTR_NONE != asynchronous) {
270bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        unsigned id = thiz->mInstanceID;
271f51dba65751107c930759938775b75531ec1f330Glenn Kasten        if (0 != id) {
272f51dba65751107c930759938775b75531ec1f330Glenn Kasten            --id;
273f51dba65751107c930759938775b75531ec1f330Glenn Kasten            assert(MAX_INSTANCE > id);
274bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            IEngine *thisEngine = &thiz->mEngine->mEngine;
2757b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten            // FIXME atomic or here
276f51dba65751107c930759938775b75531ec1f330Glenn Kasten            interface_lock_exclusive(thisEngine);
277f51dba65751107c930759938775b75531ec1f330Glenn Kasten            thisEngine->mChangedMask |= 1 << id;
278f51dba65751107c930759938775b75531ec1f330Glenn Kasten            interface_unlock_exclusive(thisEngine);
279f51dba65751107c930759938775b75531ec1f330Glenn Kasten        }
280e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
2817b726bdcd996f1cab3a584c04ce1afc07bc8fbe7Glenn Kasten
282e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten}
283e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
2840b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
285928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
2860b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
2874f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten#ifdef USE_DEBUG
288bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_wait_(IObject *thiz, const char *file, int line)
2894f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten{
2904f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    // note that this will unlock the mutex, so we have to clear the owner
291bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(pthread_equal(pthread_self(), thiz->mOwner));
292bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(NULL != thiz->mFile);
293bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    assert(0 != thiz->mLine);
294bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    memset(&thiz->mOwner, 0, sizeof(pthread_t));
295bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
296bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
2974f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    // alas we don't know the new owner's identity
2984f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    int ok;
299bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
3004f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    assert(0 == ok);
3014f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten    // restore my ownership
302bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mOwner = pthread_self();
303bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mFile = file;
304bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mLine = line;
3054f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten}
3064f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten#else
307bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_wait(IObject *thiz)
308a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten{
309a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
310bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
311a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
312a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
3134f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten#endif
314a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten
3150b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
316928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
3170b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
318bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_signal(IObject *thiz)
319a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten{
320a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    int ok;
321bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_signal(&thiz->mCond);
322a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten    assert(0 == ok);
323a6d984c32855a239f7f79a3d3b7f2ddfb8cb9697Glenn Kasten}
324a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten
3250b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
326928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief Broadcast the condition variable associated with the object;
327928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten *  see pthread_cond_broadcast
328928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten */
3290b595cc18d82e41dfab0c686e9e63c30a86e8c80Glenn Kasten
330bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kastenvoid object_cond_broadcast(IObject *thiz)
331a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten{
332a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten    int ok;
333bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    ok = pthread_cond_broadcast(&thiz->mCond);
334a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten    assert(0 == ok);
335a438eb1cf1ae602afab00336528dd230bd929206Glenn Kasten}
336