fix an awful race condition when handling data requests

git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1671 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2007-08-15 22:47:59 +00:00
parent 1ff47862c4
commit c0d668431b

View file

@ -537,13 +537,23 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata,
switch (code) { switch (code) {
case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: { case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
pa_tagstruct *t; pa_tagstruct *t;
int32_t l; int32_t l = 0;
if ((l = pa_atomic_load(&s->missing)) <= 0) for (;;) {
int32_t k;
if ((k = pa_atomic_load(&s->missing)) <= 0)
break;
l += k;
if (pa_atomic_sub(&s->missing, k) <= k)
break;
}
if (l <= 0)
break; break;
pa_assert_se(pa_atomic_sub(&s->missing, l) >= l);
t = pa_tagstruct_new(NULL, 0); t = pa_tagstruct_new(NULL, 0);
pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
@ -551,7 +561,7 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata,
pa_tagstruct_putu32(t, l); pa_tagstruct_putu32(t, l);
pa_pstream_send_tagstruct(s->connection->pstream, t); pa_pstream_send_tagstruct(s->connection->pstream, t);
/* pa_log("Requesting %u bytes", l); */ /* pa_log("Requesting %u bytes", l); */
break; break;
} }
@ -770,24 +780,22 @@ static void connection_free(pa_object *o) {
/* Called from thread context */ /* Called from thread context */
static void request_bytes(playback_stream *s) { static void request_bytes(playback_stream *s) {
size_t new_missing, delta, previous_missing; size_t new_missing, delta, previous_missing;
size_t minreq;
/* pa_log("request_bytes()"); */
playback_stream_assert_ref(s); playback_stream_assert_ref(s);
new_missing = pa_memblockq_missing(s->memblockq); new_missing = pa_memblockq_missing(s->memblockq);
delta = new_missing > s->last_missing ? new_missing - s->last_missing : 0;
if (new_missing <= s->last_missing) {
s->last_missing = new_missing;
return;
}
delta = new_missing - s->last_missing;
s->last_missing = new_missing; s->last_missing = new_missing;
if (delta <= 0)
return;
/* pa_log("request_bytes(%u)", delta); */ /* pa_log("request_bytes(%u)", delta); */
minreq = pa_memblockq_get_minreq(s->memblockq);
previous_missing = pa_atomic_add(&s->missing, delta); previous_missing = pa_atomic_add(&s->missing, delta);
if (previous_missing < pa_memblockq_get_minreq(s->memblockq) && previous_missing+delta >= pa_memblockq_get_minreq(s->memblockq)) if (previous_missing < minreq && previous_missing+delta >= minreq)
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
} }