locks.c revision 68d56b8ebaf60184a3aef988e3d2b09ed8b88c05
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    SLuint32 objectID = IObjectToObjectID(thiz);
117    CAudioPlayer *ap;
118
119    // FIXME The endless if statements are getting ugly, should use bit search
120
121    // Android likes to see certain updates synchronously
122
123    if (attributes & ATTR_GAIN) {
124        switch (objectID) {
125        case SL_OBJECTID_AUDIOPLAYER:
126            attributes &= ~ATTR_GAIN;   // no need to process asynchronously also
127            ap = (CAudioPlayer *) thiz;
128#ifdef ANDROID
129            android_audioPlayer_volumeUpdate(ap);
130#else
131            audioPlayerGainUpdate(ap);
132#endif
133            break;
134        case SL_OBJECTID_OUTPUTMIX:
135            // FIXME update gains on all players attached to this outputmix
136            SL_LOGD("[ FIXME: gain update on an SL_OBJECTID_OUTPUTMIX to be implemented ]");
137            break;
138        case SL_OBJECTID_MIDIPLAYER:
139            // MIDI
140            SL_LOGD("[ FIXME: gain update on an SL_OBJECTID_MIDIPLAYER to be implemented ]");
141            break;
142        default:
143            break;
144        }
145    }
146
147    if (attributes & ATTR_POSITION) {
148        switch (objectID) {
149        case SL_OBJECTID_AUDIOPLAYER:
150#ifdef ANDROID
151            ap = (CAudioPlayer *) thiz;
152            attributes &= ~ATTR_POSITION;   // no need to process asynchronously also
153            android_audioPlayer_seek(ap, ap->mSeek.mPos);
154#else
155            //audioPlayerTransportUpdate(ap);
156#endif
157            break;
158        case SL_OBJECTID_MIDIPLAYER:
159            // MIDI
160            SL_LOGD("[ FIXME: position update on an SL_OBJECTID_MIDIPLAYER to be implemented ]");
161            break;
162        default:
163            break;
164        }
165    }
166
167    if (attributes & ATTR_TRANSPORT) {
168        switch (objectID) {
169        case SL_OBJECTID_AUDIOPLAYER:
170#ifdef ANDROID
171            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
172            ap = (CAudioPlayer *) thiz;
173            // FIXME should only call when state changes
174            android_audioPlayer_setPlayState(ap, false /*lockAP*/);
175            // FIXME ditto, but for either eventflags or marker position
176            android_audioPlayer_useEventMask(ap);
177#else
178            //audioPlayerTransportUpdate(ap);
179#endif
180            break;
181        case SL_OBJECTID_AUDIORECORDER:
182#ifdef ANDROID
183            {
184            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
185            CAudioRecorder* ar = (CAudioRecorder *) thiz;
186            android_audioRecorder_useEventMask(ar);
187            }
188#endif
189            break;
190        case XA_OBJECTID_MEDIAPLAYER:
191#ifdef ANDROID
192            {
193            attributes &= ~ATTR_TRANSPORT;   // no need to process asynchronously also
194            CMediaPlayer *mp = (CMediaPlayer *) thiz;
195            android::GenericPlayer* avp = mp->mAVPlayer.get();
196            if (avp != NULL) {
197                android_Player_setPlayState(avp, mp->mPlay.mState, &(mp->mAndroidObjState));
198            }
199            }
200#endif
201            break;
202        default:
203            break;
204        }
205    }
206
207    // ( buffer queue count is non-empty and play state == PLAYING ) became true
208    if (attributes & ATTR_ENQUEUE) {
209        if (SL_OBJECTID_AUDIOPLAYER == objectID) {
210            attributes &= ~ATTR_ENQUEUE;
211            ap = (CAudioPlayer *) thiz;
212            if (SL_PLAYSTATE_PLAYING == ap->mPlay.mState) {
213#ifdef ANDROID
214                android_audioPlayer_bufferQueue_onRefilled(ap);
215#endif
216            }
217        }
218    }
219
220    if (attributes) {
221        unsigned oldAttributesMask = thiz->mAttributesMask;
222        thiz->mAttributesMask = oldAttributesMask | attributes;
223        if (oldAttributesMask)
224            attributes = ATTR_NONE;
225    }
226#ifdef USE_DEBUG
227    memset(&thiz->mOwner, 0, sizeof(pthread_t));
228    thiz->mFile = file;
229    thiz->mLine = line;
230#endif
231    ok = pthread_mutex_unlock(&thiz->mMutex);
232    assert(0 == ok);
233    // first update to this interface since previous sync
234    if (attributes) {
235        unsigned id = thiz->mInstanceID;
236        if (0 != id) {
237            --id;
238            assert(MAX_INSTANCE > id);
239            IEngine *thisEngine = &thiz->mEngine->mEngine;
240            interface_lock_exclusive(thisEngine);
241            thisEngine->mChangedMask |= 1 << id;
242            interface_unlock_exclusive(thisEngine);
243        }
244    }
245}
246
247
248/** \brief Wait on the condition variable associated with the object; see pthread_cond_wait */
249
250#ifdef USE_DEBUG
251void object_cond_wait_(IObject *thiz, const char *file, int line)
252{
253    // note that this will unlock the mutex, so we have to clear the owner
254    assert(pthread_equal(pthread_self(), thiz->mOwner));
255    assert(NULL != thiz->mFile);
256    assert(0 != thiz->mLine);
257    memset(&thiz->mOwner, 0, sizeof(pthread_t));
258    thiz->mFile = file;
259    thiz->mLine = line;
260    // alas we don't know the new owner's identity
261    int ok;
262    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
263    assert(0 == ok);
264    // restore my ownership
265    thiz->mOwner = pthread_self();
266    thiz->mFile = file;
267    thiz->mLine = line;
268}
269#else
270void object_cond_wait(IObject *thiz)
271{
272    int ok;
273    ok = pthread_cond_wait(&thiz->mCond, &thiz->mMutex);
274    assert(0 == ok);
275}
276#endif
277
278
279/** \brief Signal the condition variable associated with the object; see pthread_cond_signal */
280
281void object_cond_signal(IObject *thiz)
282{
283    int ok;
284    ok = pthread_cond_signal(&thiz->mCond);
285    assert(0 == ok);
286}
287
288
289/** \brief Broadcast the condition variable associated with the object;
290 *  see pthread_cond_broadcast
291 */
292
293void object_cond_broadcast(IObject *thiz)
294{
295    int ok;
296    ok = pthread_cond_broadcast(&thiz->mCond);
297    assert(0 == ok);
298}
299