assorted fixes:

Original commit message from CVS:
assorted fixes:
- fix for #111146 (works now with lots of warnings (or maybe even without - the fun of races))
- more useful debugging output
- restructuring of when to release the lock
- emitting SHUTDOWN when holding lock so we're not destroyed while signalling
- probably something else I don't remember
This commit is contained in:
Benjamin Otte 2003-04-21 18:09:29 +00:00
parent 22fa9810d6
commit 7f5dc1299b
2 changed files with 41 additions and 11 deletions

View file

@ -337,9 +337,17 @@ static void
gst_thread_catch (GstThread *thread) gst_thread_catch (GstThread *thread)
{ {
gboolean wait; gboolean wait;
g_mutex_lock (thread->lock); if (thread == gst_thread_get_current()) {
if (thread != gst_thread_get_current()) { /* we're trying to catch ourself */
if (!GST_FLAG_IS_SET (thread, GST_THREAD_MUTEX_LOCKED)) {
g_mutex_lock (thread->lock);
GST_FLAG_SET (thread, GST_THREAD_MUTEX_LOCKED);
}
GST_DEBUG (GST_CAT_THREAD, "%s is catching itself", GST_ELEMENT_NAME (thread));
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
} else {
/* another thread is trying to catch us */ /* another thread is trying to catch us */
g_mutex_lock (thread->lock);
wait = !GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING); wait = !GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING);
while (!wait) { while (!wait) {
GTimeVal tv; GTimeVal tv;
@ -358,16 +366,20 @@ gst_thread_catch (GstThread *thread)
static void static void
gst_thread_release (GstThread *thread) gst_thread_release (GstThread *thread)
{ {
g_cond_signal (thread->cond); if (thread != gst_thread_get_current()) {
g_mutex_unlock (thread->lock); g_cond_signal (thread->cond);
g_mutex_unlock (thread->lock);
}
} }
static GstElementStateReturn static GstElementStateReturn
gst_thread_change_state (GstElement *element) gst_thread_change_state (GstElement *element)
{ {
GstThread *thread; GstThread *thread;
GstElementStateReturn ret; GstElementStateReturn ret;
gint transition;
g_return_val_if_fail (GST_IS_THREAD (element), GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_THREAD (element), GST_STATE_FAILURE);
transition = GST_STATE_TRANSITION (element);
thread = GST_THREAD (element); thread = GST_THREAD (element);
@ -377,7 +389,14 @@ gst_thread_change_state (GstElement *element)
gst_thread_catch (thread); gst_thread_catch (thread);
switch (GST_STATE_TRANSITION (element)) { /* FIXME: (or GStreamers ideas about "threading"): the element variables are
commonly accessed by multiple threads at the same time (see bug #111146
for an example) */
if (transition != GST_STATE_TRANSITION (element)) {
g_warning ("inconsistent state information, fix threading please");
}
switch (transition) {
case GST_STATE_NULL_TO_READY: case GST_STATE_NULL_TO_READY:
/* create the thread */ /* create the thread */
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING); GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
@ -474,7 +493,11 @@ static void
gst_thread_child_state_change (GstBin *bin, GstElementState oldstate, gst_thread_child_state_change (GstBin *bin, GstElementState oldstate,
GstElementState newstate, GstElement *element) GstElementState newstate, GstElement *element)
{ {
parent_class->child_state_change (bin, oldstate, newstate, element); GST_DEBUG (GST_CAT_THREAD, "%s (from thread %s) child %s changed state from %s to %s\n",
GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (gst_thread_get_current()), GST_ELEMENT_NAME (element),
gst_element_state_get_name (oldstate), gst_element_state_get_name (newstate));
if (parent_class->child_state_change)
parent_class->child_state_change (bin, oldstate, newstate, element);
/* We'll wake up the main thread now. Note that we can't lock the thread here, /* We'll wake up the main thread now. Note that we can't lock the thread here,
because we might be called from inside gst_thread_change_state when holding because we might be called from inside gst_thread_change_state when holding
the lock. But this doesn't cause any problems. */ the lock. But this doesn't cause any problems. */
@ -514,7 +537,11 @@ gst_thread_main_loop (void *arg)
while (status && GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) { while (status && GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
g_mutex_unlock (thread->lock); g_mutex_unlock (thread->lock);
status = gst_bin_iterate (GST_BIN (thread)); status = gst_bin_iterate (GST_BIN (thread));
g_mutex_lock (thread->lock); if (GST_FLAG_IS_SET (thread, GST_THREAD_MUTEX_LOCKED)) {
GST_FLAG_UNSET (thread, GST_THREAD_MUTEX_LOCKED);
} else {
g_mutex_lock (thread->lock);
}
} }
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING); GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
} }
@ -529,6 +556,9 @@ gst_thread_main_loop (void *arg)
* stack into the threads stack space */ * stack into the threads stack space */
gst_scheduler_reset (GST_ELEMENT_SCHED (thread)); gst_scheduler_reset (GST_ELEMENT_SCHED (thread));
/* must do that before releasing the lock - we might get disposed before being done */
g_signal_emit (G_OBJECT (thread), gst_thread_signals[SHUTDOWN], 0);
/* unlock and signal - we are out */ /* unlock and signal - we are out */
g_cond_signal (thread->cond); g_cond_signal (thread->cond);
g_mutex_unlock (thread->lock); g_mutex_unlock (thread->lock);
@ -536,8 +566,6 @@ gst_thread_main_loop (void *arg)
GST_INFO (GST_CAT_THREAD, "gstthread: thread \"%s\" is stopped", GST_INFO (GST_CAT_THREAD, "gstthread: thread \"%s\" is stopped",
GST_ELEMENT_NAME (thread)); GST_ELEMENT_NAME (thread));
g_signal_emit (G_OBJECT (thread), gst_thread_signals[SHUTDOWN], 0);
return NULL; return NULL;
} }

View file

@ -36,9 +36,11 @@ extern GstElementDetails gst_thread_details;
typedef enum { typedef enum {
GST_THREAD_STATE_STARTED = GST_BIN_FLAG_LAST, GST_THREAD_STATE_SPINNING = GST_BIN_FLAG_LAST,
GST_THREAD_STATE_SPINNING,
GST_THREAD_STATE_REAPING, GST_THREAD_STATE_REAPING,
/* when iterating with mutex locked (special cases)
may only be set by thread itself */
GST_THREAD_MUTEX_LOCKED,
/* padding */ /* padding */
GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4 GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4