diff options
author | Lennart Poettering <lennart@poettering.net> | 2010-02-20 00:18:31 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-02-20 00:18:31 +0100 |
commit | a558bbefae4e0a9f4d2b9aa539b94ae0344f6aed (patch) | |
tree | 6f7a76deebc4a8471e305d4da33f89ad703ba8bf /src/pulse.c | |
parent | 70b59780bf23f0adc71a4cff8d87883472190ef0 (diff) |
pulse: fix a minor race with sound cancellation
If we call pa_stream_drain() and immediately afterwards destroy the
stream it might happen that the pa_stream_drain() callback is called
after the destruction finished pointing to an invalid out structure.
To fix this we need to terminate the _drain() callback to make sure the
reference to the not existing structure is dropped.
Diffstat (limited to 'src/pulse.c')
-rw-r--r-- | src/pulse.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/src/pulse.c b/src/pulse.c index 8dd2021..4d0d428 100644 --- a/src/pulse.c +++ b/src/pulse.c @@ -57,6 +57,7 @@ struct outstanding { uint32_t id; uint32_t sink_input; pa_stream *stream; + pa_operation *drain_operation; ca_finish_callback_t callback; void *userdata; ca_sound_file *file; @@ -85,6 +86,12 @@ static void outstanding_disconnect(struct outstanding *o) { ca_assert(o); if (o->stream) { + if (o->drain_operation) { + pa_operation_cancel(o->drain_operation); + pa_operation_unref(o->drain_operation); + o->drain_operation = NULL; + } + pa_stream_set_write_callback(o->stream, NULL, NULL); pa_stream_set_state_callback(o->stream, NULL, NULL); pa_stream_disconnect(o->stream); @@ -645,6 +652,11 @@ static void stream_drain_cb(pa_stream *s, int success, void *userdata) { out->finished = TRUE; } + if (out->drain_operation) { + pa_operation_unref(out->drain_operation); + out->drain_operation = NULL; + } + pa_threaded_mainloop_signal(p->mainloop, FALSE); } @@ -704,15 +716,17 @@ static void stream_write_cb(pa_stream *s, size_t bytes, void *userdata) { pa_threaded_mainloop_signal(p->mainloop, FALSE); } else { - pa_operation *o; ca_assert(out->type == OUTSTANDING_STREAM); - if (!(o = pa_stream_drain(s, stream_drain_cb, out))) { + if (out->drain_operation) { + pa_operation_cancel(out->drain_operation); + pa_operation_unref(out->drain_operation); + } + + if (!(out->drain_operation = pa_stream_drain(s, stream_drain_cb, out))) { ret = translate_error(pa_context_errno(p->context)); goto finish; } - - pa_operation_unref(o); } pa_stream_set_write_callback(s, NULL, NULL); |