gst/gstthread.c: Do not try to grab the iterate lock in the state change method when we are in the same thread as the...

Original commit message from CVS:
* gst/gstthread.c: (gst_thread_dispose), (gst_thread_sync),
(gst_thread_change_state), (gst_thread_child_state_change):
Do not try to grab the iterate lock in the state change method
when we are in the same thread as the iterate or else we
could deadlock. Some other cleanups.
This commit is contained in:
Wim Taymans 2004-10-07 17:41:40 +00:00
parent aae255f97a
commit c43a7670f0
2 changed files with 36 additions and 10 deletions

View file

@ -1,3 +1,11 @@
2004-10-07 Wim Taymans <wim at fluendo dot com>
* gst/gstthread.c: (gst_thread_dispose), (gst_thread_sync),
(gst_thread_change_state), (gst_thread_child_state_change):
Do not try to grab the iterate lock in the state change method
when we are in the same thread as the iterate or else we
could deadlock. Some other cleanups.
2004-10-06 Thomas Vander Stichele <thomas at apestaart dot org>
* configure.ac:

View file

@ -36,7 +36,8 @@ GST_ELEMENT_DETAILS ("Threaded container",
"Generic/Bin",
"Container that creates/manages a thread",
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Benjamin Otte <in7y118@informatik.uni-hamburg.de");
"Benjamin Otte <in7y118@informatik.uni-hamburg.de"
"Wim Taymans <wim@fluendo.com");
/* Thread signals and args */
enum
@ -74,7 +75,7 @@ static GstElementStateReturn gst_thread_change_state (GstElement * element);
static void gst_thread_child_state_change (GstBin * bin,
GstElementState oldstate, GstElementState newstate, GstElement * element);
static void gst_thread_sync (GstThread * thread);
static void gst_thread_sync (GstThread * thread, gboolean is_self);
#ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr gst_thread_save_thyself (GstObject * object,
@ -248,6 +249,7 @@ gst_thread_dispose (GObject * object)
g_mutex_free (thread->lock);
g_cond_free (thread->cond);
g_mutex_free (thread->iterate_lock);
gst_object_replace ((GstObject **) & GST_ELEMENT_SCHED (thread), NULL);
}
@ -390,7 +392,7 @@ gst_thread_release_children_locks (GstThread * thread)
* This function should be called with the thread lock held.
*/
static void
gst_thread_sync (GstThread * thread)
gst_thread_sync (GstThread * thread, gboolean is_self)
{
if (thread->thread_id == NULL)
return;
@ -398,7 +400,7 @@ gst_thread_sync (GstThread * thread)
/* need to stop spinning in any case */
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
if (thread == gst_thread_get_current ()) {
if (is_self) {
/* we're trying to sync ourself. Not much we can do here but hope
* that the thread will stop spinning and end up in the waiting
* state */
@ -435,6 +437,7 @@ gst_thread_change_state (GstElement * element)
GstThread *thread;
GstElementStateReturn ret;
gint transition;
gboolean is_self;
g_return_val_if_fail (GST_IS_THREAD (element), GST_STATE_FAILURE);
@ -446,10 +449,14 @@ gst_thread_change_state (GstElement * element)
thread = GST_THREAD (element);
/* boolean to check if we called the state change in the same thread as
* the iterate thread */
is_self = (thread == gst_thread_get_current ());
GST_LOG_OBJECT (thread, "grabbing lock");
g_mutex_lock (thread->lock);
gst_thread_sync (thread);
gst_thread_sync (thread, is_self);
/* FIXME: (or GStreamers ideas about "threading"): the element variables are
commonly accessed by multiple threads at the same time (see bug #111146
@ -517,7 +524,7 @@ gst_thread_change_state (GstElement * element)
/* thread was already gone */
if (thread->thread_id != NULL) {
thread->thread_id = NULL;
if (thread == gst_thread_get_current ()) {
if (is_self) {
/* or should we continue? */
GST_LOG_OBJECT (thread,
"Thread %s is destroying itself. Function call will not return!",
@ -553,13 +560,18 @@ gst_thread_change_state (GstElement * element)
GST_LOG_OBJECT (thread, "unlocking lock");
g_mutex_unlock (thread->lock);
g_mutex_lock (thread->iterate_lock);
/* do not try to grab the lock if this method is called from the
* same thread as the iterate thread, the lock might be held and we
* might deadlock */
if (!is_self)
g_mutex_lock (thread->iterate_lock);
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
ret = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (thread));
} else {
ret = GST_STATE_SUCCESS;
}
g_mutex_unlock (thread->iterate_lock);
if (!is_self)
g_mutex_unlock (thread->iterate_lock);
return ret;
@ -586,9 +598,15 @@ gst_thread_child_state_change (GstBin * bin, GstElementState oldstate,
GstElementState newstate, GstElement * element)
{
GstThread *thread = GST_THREAD (bin);
gboolean is_self;
GstThread *current;
current = gst_thread_get_current ();
is_self = (current == thread);
GST_LOG_OBJECT (bin, "(from thread %s) child %s changed state from %s to %s",
gst_thread_get_current ()? GST_ELEMENT_NAME (gst_thread_get_current ()) :
current ? GST_ELEMENT_NAME (current) :
"(none)", GST_ELEMENT_NAME (element),
gst_element_state_get_name (oldstate),
gst_element_state_get_name (newstate));
@ -597,7 +615,7 @@ gst_thread_child_state_change (GstBin * bin, GstElementState oldstate,
parent_class->child_state_change (bin, oldstate, newstate, element);
/* see if we have to wake up the thread now. */
if (thread == gst_thread_get_current ()) {
if (is_self) {
GST_LOG_OBJECT (element, "we are in the thread context");
/* we are the thread, set the spinning flag so that we start spinning
* next time */