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