From: Giovanni Mascellani gmascellani@codeweavers.com
It is possible that a stream is destroyed while another thread is waiting on event_empty_cond or event_cond. The waiting thread should have the opportunity to be rescheduled and exit the critical section before the condition variables and the mutex are destroyed. --- dlls/winegstreamer/wg_parser.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 0573c99858b..feead069391 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -102,13 +102,15 @@ struct wg_parser_stream GstSegment segment; struct wg_format preferred_format, current_format;
- pthread_cond_t event_cond, event_empty_cond; + pthread_cond_t event_cond, event_empty_cond, free_cond; GstBuffer *buffer; GstMapInfo map_info;
- bool flushing, eos, enabled, has_caps; + bool flushing, eos, enabled, has_caps, freeing;
uint64_t duration; + + unsigned int waiters; };
static NTSTATUS wg_parser_get_stream_count(void *args) @@ -270,8 +272,15 @@ static NTSTATUS wg_parser_stream_get_buffer(void *args)
pthread_mutex_lock(&parser->mutex);
- while (!stream->eos && !stream->buffer) + while (!stream->eos && !stream->buffer && !stream->freeing) + { + stream->waiters++; pthread_cond_wait(&stream->event_cond, &parser->mutex); + stream->waiters--; + } + + if (stream->freeing && stream->waiters == 0) + pthread_cond_signal(&stream->free_cond);
/* Note that we can both have a buffer and stream->eos, in which case we * must return the buffer. */ @@ -547,7 +556,14 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu * implementing a queue object here. */
while (stream->enabled && !stream->flushing && stream->buffer) + { + stream->waiters++; pthread_cond_wait(&stream->event_empty_cond, &parser->mutex); + stream->waiters--; + } + + if (stream->freeing && stream->waiters == 0) + pthread_cond_signal(&stream->free_cond);
if (!stream->enabled) { @@ -694,6 +710,7 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN; pthread_cond_init(&stream->event_cond, NULL); pthread_cond_init(&stream->event_empty_cond, NULL); + pthread_cond_init(&stream->free_cond, NULL);
sprintf(pad_name, "qz_sink_%u", parser->stream_count); stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK); @@ -708,6 +725,13 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser)
static void free_stream(struct wg_parser_stream *stream) { + pthread_mutex_lock(&stream->parser->mutex); + stream->freeing = true; + pthread_cond_signal(&stream->event_cond); + while (stream->waiters != 0) + pthread_cond_wait(&stream->free_cond, &stream->parser->mutex); + pthread_mutex_unlock(&stream->parser->mutex); + if (stream->their_src) { if (stream->post_sink) @@ -722,6 +746,7 @@ static void free_stream(struct wg_parser_stream *stream)
pthread_cond_destroy(&stream->event_cond); pthread_cond_destroy(&stream->event_empty_cond); + pthread_cond_destroy(&stream->free_cond);
free(stream); }