mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-08 15:32:32 +00:00
gst/gstthread.c: Ref the thread object in the GThread mainloop. Break out of the thread mainloop if it holds the last...
Original commit message from CVS: * gst/gstthread.c: (gst_thread_dispose), (gst_thread_change_state), (gst_thread_child_state_change), (gst_thread_main_loop): Ref the thread object in the GThread mainloop. Break out of the thread mainloop if it holds the last ref. This properly exits the threads when disposing the thread from its own context. It also avoids possible deadlocks in the dispose function.
This commit is contained in:
parent
6c376ecbf5
commit
12a0211728
2 changed files with 37 additions and 33 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2004-11-25 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst/gstthread.c: (gst_thread_dispose), (gst_thread_change_state),
|
||||||
|
(gst_thread_child_state_change), (gst_thread_main_loop):
|
||||||
|
Ref the thread object in the GThread mainloop. Break out of the
|
||||||
|
thread mainloop if it holds the last ref. This properly exits
|
||||||
|
the threads when disposing the thread from its own context. It
|
||||||
|
also avoids possible deadlocks in the dispose function.
|
||||||
|
|
||||||
2004-11-24 Martin Soto <martinsoto@users.sourceforge.net>
|
2004-11-24 Martin Soto <martinsoto@users.sourceforge.net>
|
||||||
|
|
||||||
* gst/gstqueue.c (gst_queue_link_sink): Grab the lock only when
|
* gst/gstqueue.c (gst_queue_link_sink): Grab the lock only when
|
||||||
|
|
|
@ -220,33 +220,15 @@ gst_thread_dispose (GObject * object)
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose");
|
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose");
|
||||||
|
|
||||||
|
/* if we get here, the thread is really stopped as it has released
|
||||||
|
* the last refcount to the thread object, so we can safely free the
|
||||||
|
* mutex and cond vars */
|
||||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||||
|
|
||||||
g_assert (GST_STATE (thread) == GST_STATE_NULL);
|
g_assert (GST_STATE (thread) == GST_STATE_NULL);
|
||||||
|
|
||||||
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose, freeing locks");
|
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose, freeing locks");
|
||||||
|
|
||||||
if (thread->thread_id != NULL) {
|
|
||||||
/* thread is still alive */
|
|
||||||
g_mutex_lock (thread->lock);
|
|
||||||
/* thread can be spinning or waiting */
|
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
|
||||||
|
|
||||||
if (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
|
|
||||||
GST_DEBUG_OBJECT (thread, "wait");
|
|
||||||
g_cond_wait (thread->cond, thread->lock);
|
|
||||||
GST_DEBUG_OBJECT (thread, "done");
|
|
||||||
}
|
|
||||||
/* now wait for the thread to destroy itself */
|
|
||||||
GST_DEBUG_OBJECT (thread, "signal");
|
|
||||||
g_cond_signal (thread->cond);
|
|
||||||
GST_DEBUG_OBJECT (thread, "wait");
|
|
||||||
g_cond_wait (thread->cond, thread->lock);
|
|
||||||
GST_DEBUG_OBJECT (thread, "done");
|
|
||||||
g_mutex_unlock (thread->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_mutex_free (thread->lock);
|
g_mutex_free (thread->lock);
|
||||||
g_cond_free (thread->cond);
|
g_cond_free (thread->cond);
|
||||||
g_mutex_free (thread->iterate_lock);
|
g_mutex_free (thread->iterate_lock);
|
||||||
|
@ -674,6 +656,7 @@ gst_thread_main_loop (void *arg)
|
||||||
g_cond_signal (thread->cond);
|
g_cond_signal (thread->cond);
|
||||||
GST_LOG_OBJECT (element, "unlocking lock");
|
GST_LOG_OBJECT (element, "unlocking lock");
|
||||||
|
|
||||||
|
gst_object_ref (GST_OBJECT (thread));
|
||||||
/* as long as we're not dying we can continue */
|
/* as long as we're not dying we can continue */
|
||||||
while (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
|
while (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
|
||||||
/* in the playing state we need to do something special */
|
/* in the playing state we need to do something special */
|
||||||
|
@ -697,24 +680,35 @@ gst_thread_main_loop (void *arg)
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* if we hold the last refcount, the app unreffed the
|
||||||
|
* thread and we should stop ASAP */
|
||||||
|
if (G_OBJECT (thread)->ref_count == 1) {
|
||||||
|
GST_DEBUG_OBJECT (thread, "reaping as refcount is only 1");
|
||||||
|
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
|
||||||
|
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* sync section */
|
/* do not try to sync when we are REAPING */
|
||||||
GST_LOG_OBJECT (thread, "entering sync");
|
if (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
|
||||||
GST_DEBUG_OBJECT (thread, "signal");
|
/* sync section */
|
||||||
g_cond_signal (thread->cond);
|
GST_LOG_OBJECT (thread, "entering sync");
|
||||||
GST_DEBUG_OBJECT (thread, "wait");
|
GST_DEBUG_OBJECT (thread, "signal");
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
g_cond_signal (thread->cond);
|
||||||
GST_FLAG_SET (thread, GST_THREAD_STATE_WAITING);
|
GST_DEBUG_OBJECT (thread, "wait");
|
||||||
g_cond_wait (thread->cond, thread->lock);
|
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
|
||||||
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
|
GST_FLAG_SET (thread, GST_THREAD_STATE_WAITING);
|
||||||
GST_LOG_OBJECT (thread, "wait done");
|
g_cond_wait (thread->cond, thread->lock);
|
||||||
|
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
|
||||||
|
GST_LOG_OBJECT (thread, "wait done");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GST_LOG_OBJECT (thread, "unlocking lock");
|
GST_LOG_OBJECT (thread, "unlocking lock");
|
||||||
|
thread->thread_id = NULL;
|
||||||
g_mutex_unlock (thread->lock);
|
g_mutex_unlock (thread->lock);
|
||||||
|
|
||||||
/* we need to destroy the scheduler here because it has mapped it's
|
/* we need to destroy the scheduler here because it might have
|
||||||
* stack into the threads stack space */
|
* mapped it's stack into the threads stack space */
|
||||||
sched = GST_ELEMENT_SCHED (thread);
|
sched = GST_ELEMENT_SCHED (thread);
|
||||||
if (sched)
|
if (sched)
|
||||||
gst_scheduler_reset (sched);
|
gst_scheduler_reset (sched);
|
||||||
|
@ -724,6 +718,7 @@ gst_thread_main_loop (void *arg)
|
||||||
/* signal - we are out */
|
/* signal - we are out */
|
||||||
GST_LOG_OBJECT (thread, "Thread %p exits main loop", g_thread_self ());
|
GST_LOG_OBJECT (thread, "Thread %p exits main loop", g_thread_self ());
|
||||||
g_cond_signal (thread->cond);
|
g_cond_signal (thread->cond);
|
||||||
|
gst_object_unref (GST_OBJECT (thread));
|
||||||
/* don't assume the GstThread object exists anymore now */
|
/* don't assume the GstThread object exists anymore now */
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in a new issue