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