locks.c revision a60dbf554549d10780f473b6e1373aa07aec3a28
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/** \brief Exclusively lock an object */
21
22#ifdef USE_DEBUG
23void object_lock_exclusive_(IObject *thiz, const char *file, int line)
24{
25    int ok;
26    ok = pthread_mutex_trylock(&thiz->mMutex);
27    if (0 != ok) {
28        // pthread_mutex_timedlock_np is not available, but wait up to 100 ms
29        static const useconds_t backoffs[] = {1, 10000, 20000, 30000, 40000};
30        unsigned i = 0;
31        for (;;) {
32            usleep(backoffs[i]);
33            ok = pthread_mutex_trylock(&thiz->mMutex);
34            if (0 == ok)
35                break;
36            if (++i >= (sizeof(backoffs) / sizeof(backoffs[0]))) {
37                SL_LOGW("%s:%d: object %p was locked by %p at %s:%d\n",
38                    file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine);
39                // attempt one more time; maybe this time we will be successful
40                ok = pthread_mutex_lock(&thiz->mMutex);
41                assert(0 == ok);
42                break;
43            }
44        }
45    }
46    pthread_t zero;
47    memset(&zero, 0, sizeof(pthread_t));
48    if (0 != memcmp(&zero, &thiz->mOwner, sizeof(pthread_t))) {
49        if (pthread_equal(pthread_self(), thiz->mOwner)) {
50            SL_LOGE("%s:%d: object %p was recursively locked by %p at %s:%d\n",
51                file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine);
52        } else {
53            SL_LOGE("%s:%d: object %p was left unlocked in unexpected state by %p at %s:%d\n",
54                file, line, thiz, *(void **)&thiz->mOwner, thiz->mFile, thiz->mLine);
55        }
56        assert(false);
57    }
58    thiz->mOwner = pthread_self();
59    thiz->mFile = file;
60    thiz->mLine = line;
61}
62#else
63void object_lock_exclusive(IObject *thiz)
64{
65    int ok;
66    ok = pthread_mutex_lock(&thiz->mMutex);
67    assert(0 == ok);
68}
69#endif
70
71
72/** \brief Exclusively unlock an object and do not report any updates */
73
74#ifdef USE_DEBUG
75void object_unlock_exclusive_(IObject *thiz, const char *file, int line)
76{
77    assert(pthread_equal(pthread_self(), thiz->mOwner));
78    assert(NULL != thiz->mFile);
79    assert(0 != thiz->mLine);
80    memset(&thiz->mOwner, 0, sizeof(pthread_t));
81    thiz->mFile = file;
82    thiz->mLine = line;
83    int ok;
84    ok = pthread_mutex_unlock(&thiz->mMutex);
85    assert(0 == ok);
86}
87#else
88void object_unlock_exclusive(IObject *thiz)
89{
90    int ok;
91    ok = pthread_mutex_unlock(&thiz->mMutex);
92    assert(0 == ok);
93}
94#endif
95
96
97/** \brief Exclusively unlock an object and report updates to the specified bit-mask of
98 *  attributes
99 */
100
101#ifdef USE_DEBUG
102void object_unlock_exclusive_attributes_(IObject *thiz, unsigned attributes,
103    const char *file, int line)
104#else
105void object_unlock_exclusive_attributes(IObject *thiz, unsigned attributes)
106#endif
107{
108
109#ifdef USE_DEBUG
110    assert(pthread_equal(pthread_self(), thiz->mOwner));
111    assert(NULL != thiz->mFile);
112    assert(0 != thiz->mLine);
113#endif
114
115    int ok;
116
117    // make SL object IDs be contiguous with XA object IDs
118    SLuint32 objectID = IObjectToObjectID(thiz);
119    SLuint32 index = objectID;
120    if ((XA_OBJECTID_ENGINE <= index) && (index <= XA_OBJECTID_CAMERADEVICE)) {
121        ;
122    } else if ((SL_OBJECTID_ENGINE <= index) && (index <= SL_OBJECTID_METADATAEXTRACTOR)) {
123        index -= SL_OBJECTID_ENGINE - XA_OBJECTID_CAMERADEVICE - 1;
124    } else {
125        assert(false);
126        index = 0;
127    }
128
129    // first synchronously handle updates to attributes here, while object is still locked.
130    // This appears to be a loop, but actually typically runs through the loop only once.
131    unsigned asynchronous = attributes;
132    while (attributes) {
133        // this sequence is carefully crafted to be O(1); tread carefully when making changes
134        unsigned bit = ctz(attributes);
135        // ATTR_INDEX_MAX == next bit position after the last attribute
136        assert(ATTR_INDEX_MAX > bit);
137        // compute the entry in the handler table using object ID and bit number
138        AttributeHandler handler = handlerTable[index][bit];
139        if (NULL != handler) {
140            asynchronous &= ~(*handler)(thiz);
141        }
142        attributes &= ~(1 << bit);
143    }
144
145    // any remaining attributes are handled asynchronously in the sync thread
146    if (asynchronous) {
147        unsigned oldAttributesMask = thiz->mAttributesMask;
148        thiz->mAttributesMask = oldAttributesMask | asynchronous;
149        if (oldAttributesMask) {
150            asynchronous = ATTR_NONE;
151        }
152    }
153
154#ifdef ANDROID
155    // FIXME hack to safely handle a post-unlock PrefetchStatus callback and/or AudioTrack::start()
156    slPrefetchCallback prefetchCallback = NULL;
157    void *prefetchContext = NULL;
158    SLuint32 prefetchEvents = SL_PREFETCHEVENT_NONE;
159    android::sp<android::AudioTrackProxy> audioTrack;
160    if (SL_OBJECTID_AUDIOPLAYER == objectID) {
161        CAudioPlayer *ap = (CAudioPlayer *) thiz;
162        prefetchCallback = ap->mPrefetchStatus.mDeferredPrefetchCallback;
163        prefetchContext  = ap->mPrefetchStatus.mDeferredPrefetchContext;
164        prefetchEvents   = ap->mPrefetchStatus.mDeferredPrefetchEvents;
165        ap->mPrefetchStatus.mDeferredPrefetchCallback = NULL;
166        // clearing these next two fields is not required, but avoids stale data during debugging
167        ap->mPrefetchStatus.mDeferredPrefetchContext  = NULL;
168        ap->mPrefetchStatus.mDeferredPrefetchEvents   = SL_PREFETCHEVENT_NONE;
169        if (ap->mDeferredStart) {
170            audioTrack = ap->mAudioTrack;
171            ap->mDeferredStart = false;
172        }
173    }
174#endif
175
176#ifdef USE_DEBUG
177    memset(&thiz->mOwner, 0, sizeof(pthread_t));
178    thiz->mFile = file;
179    thiz->mLine = line;
180#endif
181    ok = pthread_mutex_unlock(&thiz->mMutex);
182    assert(0 == ok);
183
184#ifdef ANDROID
185    // FIXME call the prefetch status callback while not holding the mutex on AudioPlayer
186    if (NULL != prefetchCallback) {
187        // note these are synchronous by the application's thread as it is about to return from API
188        assert(prefetchEvents != SL_PREFETCHEVENT_NONE);
189        CAudioPlayer *ap = (CAudioPlayer *) thiz;
190        // spec requires separate callbacks for each event
191        if (SL_PREFETCHEVENT_STATUSCHANGE & prefetchEvents) {
192            (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
193                    SL_PREFETCHEVENT_STATUSCHANGE);
194        }
195        if (SL_PREFETCHEVENT_FILLLEVELCHANGE & prefetchEvents) {
196            (*prefetchCallback)(&ap->mPrefetchStatus.mItf, prefetchContext,
197                    SL_PREFETCHEVENT_FILLLEVELCHANGE);
198        }
199    }
200
201    // call AudioTrack::start() while not holding the mutex on AudioPlayer
202    if (audioTrack != 0) {
203        audioTrack->start();
204        audioTrack.clear();
205    }
206#endif
207
208    // first update to this interface since previous sync
209    if (ATTR_NONE != asynchronous) {
210        unsigned id = thiz->mInstanceID;
211        if (0 != id) {
212            --id;
213            assert(MAX_INSTANCE > id);
214            IEngine *thisEngine = &thiz->mEngine->mEngine;
215            // FIXME atomic or here
216            interface_lock_exclusive(thisEngine);
217            thisEngine->mChangedMask |= 1 << id;
218            interface_unlock_exclusive(thisEngine);
219        }
220    }
221
222}
223
224
225/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
226
227#ifdef USE_DEBUG
228void object_cond_wait_(IObject *thiz, const char *file, int line)
229{
230    // note that this will unlock the mutex, so we have to clear the owner
231    assert(pthread_equal(pthread_self(), thiz->mOwner));
232    assert(NULL != thiz->mFile);
233    assert(0 != thiz->mLine);
234    memset(&thiz->mOwner, 0, sizeof(pthread_t));
235    thiz->mFile = file;
236    thiz->mLine = line;
237    // alas we don't know the new owner's identity
238    int ok;
239    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
240    assert(0 == ok);
241    // restore my ownership
242    thiz->mOwner = pthread_self();
243    thiz->mFile = file;
244    thiz->mLine = line;
245}
246#else
247void object_cond_wait(IObject *thiz)
248{
249    int ok;
250    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
251    assert(0 == ok);
252}
253#endif
254
255
256/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
257
258void object_cond_signal(IObject *thiz)
259{
260    int ok;
261    ok = pthread_cond_signal(&thiz->mCond);
262    assert(0 == ok);
263}
264
265
266/** \brief Broadcast the condition variable associated with the object;
267 *  see pthread_cond_broadcast
268 */
269
270void object_cond_broadcast(IObject *thiz)
271{
272    int ok;
273    ok = pthread_cond_broadcast(&thiz->mCond);
274    assert(0 == ok);
275}
276