From 2241baa294539a33d8bc6137e633bb4c93c22b4e Mon Sep 17 00:00:00 2001 From: Ian Rae Date: Mon, 14 Sep 2009 10:01:43 -0700 Subject: Protected access to stream->demux_action_pending The deadlock was caused by the unprotected use of stream->demux_action_pending internal variable from play_internal() and from within the demuxer loop. Direct access to demux_action_pending is replaced with _x_action_raise() and _x_action_lower(), which use a mutex for thread safety. --- include/xine/xine_internal.h | 4 ++++ src/xine-engine/demux.c | 32 ++++++++++++++++++++++++-------- src/xine-engine/io_helper.c | 4 ++-- src/xine-engine/video_decoder.c | 2 +- src/xine-engine/xine.c | 6 ++++-- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/include/xine/xine_internal.h b/include/xine/xine_internal.h index b12d20880..ac8e6cabf 100644 --- a/include/xine/xine_internal.h +++ b/include/xine/xine_internal.h @@ -334,6 +334,7 @@ struct xine_stream_s { /* demux thread stuff */ pthread_t demux_thread; pthread_mutex_t demux_lock; + pthread_mutex_t demux_action_lock; pthread_cond_t demux_resume; pthread_mutex_t demux_mutex; /* used in _x_demux_... functions to synchronize order of pairwise A/V buffer operations */ @@ -421,6 +422,9 @@ off_t _x_read_abort (xine_stream_t *stream, int fd, char *buf, off_t todo) XINE_ int _x_action_pending (xine_stream_t *stream) XINE_PROTECTED; +void _x_action_raise (xine_stream_t *stream) XINE_PROTECTED; +void _x_action_lower (xine_stream_t *stream) XINE_PROTECTED; + void _x_demux_send_data(fifo_buffer_t *fifo, uint8_t *data, int size, int64_t pts, uint32_t type, uint32_t decoder_flags, int input_normpos, int input_time, int total_time, diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c index f7db28e2b..0321d7404 100644 --- a/src/xine-engine/demux.c +++ b/src/xine-engine/demux.c @@ -200,7 +200,7 @@ void _x_demux_control_headers_done (xine_stream_t *stream) { buf_element_t *buf_video, *buf_audio; /* we use demux_action_pending to wake up sleeping spu decoders */ - stream->demux_action_pending = 1; + _x_action_raise(stream); /* allocate the buffers before grabbing the lock to prevent cyclic wait situations */ buf_video = stream->video_fifo->buffer_pool_alloc (stream->video_fifo); @@ -252,7 +252,7 @@ void _x_demux_control_headers_done (xine_stream_t *stream) { } } - stream->demux_action_pending = 0; + _x_action_lower(stream); pthread_cond_signal(&stream->demux_resume); lprintf ("headers processed.\n"); @@ -342,7 +342,7 @@ static void *demux_loop (void *stream_gen) { status = stream->demux_plugin->send_chunk(stream->demux_plugin); /* someone may want to interrupt us */ - if( stream->demux_action_pending ) { + if (_x_action_pending(stream)) { struct timeval tv; struct timespec ts; @@ -434,9 +434,9 @@ int _x_demux_start_thread (xine_stream_t *stream) { lprintf ("start thread called\n"); - stream->demux_action_pending = 1; + _x_action_raise(stream); pthread_mutex_lock( &stream->demux_lock ); - stream->demux_action_pending = 0; + _x_action_lower(stream); pthread_cond_signal(&stream->demux_resume); if( !stream->demux_thread_running ) { @@ -465,10 +465,10 @@ int _x_demux_stop_thread (xine_stream_t *stream) { lprintf ("stop thread called\n"); - stream->demux_action_pending = 1; + _x_action_raise(stream); pthread_mutex_lock( &stream->demux_lock ); stream->demux_thread_running = 0; - stream->demux_action_pending = 0; + _x_action_lower(stream); pthread_cond_signal(&stream->demux_resume); /* At that point, the demuxer has sent the last audio/video buffer, @@ -585,7 +585,7 @@ off_t _x_read_abort (xine_stream_t *stream, int fd, char *buf, off_t todo) { /* aborts current read if action pending. otherwise xine * cannot be stopped when no more data is available. */ - if( stream->demux_action_pending ) + if (_x_action_pending(stream)) return total; } else { break; @@ -626,6 +626,22 @@ int _x_action_pending (xine_stream_t *stream) { return stream->demux_action_pending; } +/* set demux_action_pending in a thread-safe way */ +void _x_action_raise (xine_stream_t *stream) +{ + pthread_mutex_lock(&stream->demux_action_lock); + stream->demux_action_pending++; + pthread_mutex_unlock(&stream->demux_action_lock); +} + +/* reset demux_action_pending in a thread-safe way */ +void _x_action_lower (xine_stream_t *stream) +{ + pthread_mutex_lock(&stream->demux_action_lock); + stream->demux_action_pending--; + pthread_mutex_unlock(&stream->demux_action_lock); +} + /* * demuxer helper function to send data to fifo, breaking into smaller * pieces (bufs) as needed. diff --git a/src/xine-engine/io_helper.c b/src/xine-engine/io_helper.c index 34540a208..d331b675a 100644 --- a/src/xine-engine/io_helper.c +++ b/src/xine-engine/io_helper.c @@ -244,7 +244,7 @@ int _x_io_select (xine_stream_t *stream, int fd, int state, int timeout_msec) { * aborts current read if action pending. otherwise xine * cannot be stopped when no more data is available. */ - if (stream && stream->demux_action_pending) + if (stream && _x_action_pending(stream)) return XIO_ABORTED; break; case WAIT_ABANDONED: @@ -288,7 +288,7 @@ int _x_io_select (xine_stream_t *stream, int fd, int state, int timeout_msec) { * aborts current read if action pending. otherwise xine * cannot be stopped when no more data is available. */ - if (stream && stream->demux_action_pending) + if (stream && _x_action_pending(stream)) return XIO_ABORTED; total_time_usec += XIO_POLLING_INTERVAL; diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index ed2e41ef3..c548d12ef 100644 --- a/src/xine-engine/video_decoder.c +++ b/src/xine-engine/video_decoder.c @@ -92,7 +92,7 @@ int _x_spu_decoder_sleep(xine_stream_t *stream, int64_t next_spu_vpts) thread_vacant = (stream->video_fifo->first->type != BUF_CONTROL_FLUSH_DECODER); /* we have to return if the demuxer needs us to release a buffer */ if (thread_vacant) - thread_vacant = !stream->demux_action_pending; + thread_vacant = !_x_action_pending(stream); } while (wait == SPU_SLEEP_INTERVAL && thread_vacant); diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 29b4b3543..31b1f254d 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -679,6 +679,7 @@ xine_stream_t *xine_stream_new (xine_t *this, pthread_mutex_init (&stream->info_mutex, NULL); pthread_mutex_init (&stream->meta_mutex, NULL); pthread_mutex_init (&stream->demux_lock, NULL); + pthread_mutex_init (&stream->demux_action_lock, NULL); pthread_mutex_init (&stream->demux_mutex, NULL); pthread_cond_init (&stream->demux_resume, NULL); pthread_mutex_init (&stream->event_queues_lock, NULL); @@ -1378,7 +1379,7 @@ static int play_internal (xine_stream_t *stream, int start_pos, int start_time) } /* hint demuxer thread we want to interrupt it */ - stream->demux_action_pending = 1; + _x_action_raise(stream); /* set normal speed */ if (_x_get_speed(stream) != XINE_SPEED_NORMAL) @@ -1397,7 +1398,7 @@ static int play_internal (xine_stream_t *stream, int start_pos, int start_time) pthread_mutex_lock( &stream->demux_lock ); /* demux_lock taken. now demuxer is suspended */ - stream->demux_action_pending = 0; + _x_action_lower(stream); pthread_cond_signal(&stream->demux_resume); /* set normal speed again (now that demuxer/input pair is suspended) @@ -1526,6 +1527,7 @@ static void xine_dispose_internal (xine_stream_t *stream) { pthread_cond_destroy (&stream->counter_changed); pthread_mutex_destroy (&stream->demux_mutex); pthread_cond_destroy (&stream->demux_resume); + pthread_mutex_destroy (&stream->demux_action_lock); pthread_mutex_destroy (&stream->demux_lock); pthread_mutex_destroy (&stream->first_frame_lock); pthread_cond_destroy (&stream->first_frame_reached); -- cgit v1.2.3