From f5affde61c45cb331489ef4068d059709f8bf9a8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Dec 2001 20:03:10 +0000 Subject: [PATCH] - Reclaim cothread state even if the cothread was never activated after the free. Original commit message from CVS: - Reclaim cothread state even if the cothread was never activated after the free. - fix the bin state change when there are no more children. - use a real method to signal the parent bin of a state change. - move the state change policy in the scheduler. - remove the unused and ridiculous state change event - don't free the cothread state when the element is disabled. only free it when the element is removed from the scheduler. --- gst/cothreads.c | 13 ++++++++++++ gst/gstbin.c | 26 ++++++----------------- gst/gstbin.h | 4 ++++ gst/gstelement.c | 33 ++++++++---------------------- gst/gstevent.c | 20 ------------------ gst/gstevent.h | 8 -------- gst/gstqueue.c | 6 ++---- gst/gstscheduler.c | 27 +++++++----------------- gst/gstscheduler.h | 6 ++---- gst/gstthread.c | 7 ++++++- gst/schedulers/gstbasicscheduler.c | 42 ++++++++++++-------------------------- plugins/elements/gstqueue.c | 6 ++---- 12 files changed, 63 insertions(+), 135 deletions(-) diff --git a/gst/cothreads.c b/gst/cothreads.c index eae2012..48aa164 100644 --- a/gst/cothreads.c +++ b/gst/cothreads.c @@ -40,6 +40,8 @@ #define COTHREAD_MAXTHREADS 16 #define COTHREAD_STACKSIZE (STACK_SIZE/COTHREAD_MAXTHREADS) +static void cothread_destroy (cothread_state *thread); + struct _cothread_context { cothread_state *threads[COTHREAD_MAXTHREADS]; @@ -116,6 +118,8 @@ cothread_context_free (cothread_context *ctx) { gint i; + GST_INFO (GST_CAT_COTHREADS, "free cothread context"); + for (i = 0; i < ctx->nthreads; i++) { #ifndef COTHREAD_ATOMIC if (ctx->threads[i]) { @@ -158,6 +162,11 @@ cothread_create (cothread_context *ctx) for (slot = 1; slot < ctx->nthreads; slot++) { if (ctx->threads[slot] == NULL) break; + else if (ctx->threads[slot]->flags & COTHREAD_DESTROYED) { + cothread_destroy (ctx->threads[slot]); + break; + } + } sp = CURRENT_STACK_FRAME; @@ -209,6 +218,8 @@ cothread_free (cothread_state *thread) { g_return_if_fail (thread != NULL); + GST_INFO (GST_CAT_COTHREADS, "flag cothread for destruction"); + /* we simply flag the cothread for destruction here */ thread->flags |= COTHREAD_DESTROYED; } @@ -220,6 +231,8 @@ cothread_destroy (cothread_state *thread) g_return_if_fail (thread != NULL); + GST_INFO (GST_CAT_COTHREADS, "destroy cothread"); + ctx = thread->ctx; #ifndef COTHREAD_ATOMIC g_mutex_free (thread->lock); diff --git a/gst/gstbin.c b/gst/gstbin.c index c1a1b00..19674e8 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -46,8 +46,6 @@ static GstElementStateReturn gst_bin_change_state_norecurse (GstBin *bin); static gboolean gst_bin_change_state_type (GstBin *bin, GstElementState state, GType type); -static void gst_bin_child_state_change (GstBin *bin, GstElementState old, - GstElementState new, GstElement *child); static void gst_bin_send_event (GstElement *element, GstEvent *event); static gboolean gst_bin_iterate_func (GstBin * bin); @@ -359,11 +357,13 @@ gst_bin_remove (GstBin * bin, GstElement * element) gst_object_unparent (GST_OBJECT (element)); /* if we're down to zero children, force state to NULL */ - if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL) - gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL); + if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL) { + GST_STATE_PENDING (bin) = GST_STATE_NULL; + gst_bin_change_state_norecurse (bin); + } } -static void +void gst_bin_child_state_change (GstBin * bin, GstElementState old, GstElementState new, GstElement * child) { @@ -401,21 +401,7 @@ gst_bin_send_event (GstElement *element, GstEvent *event) gst_element_get_name (GST_ELEMENT (GST_EVENT_SRC (event))), gst_element_get_name (element)); - if (GST_ELEMENT (GST_EVENT_SRC (event)) == element) { - GST_ELEMENT_CLASS (parent_class)->send_event (element, event); - return; - } - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_STATE_CHANGE: - gst_bin_child_state_change (GST_BIN (element), GST_EVENT_STATE_OLD (event), - GST_EVENT_STATE_NEW (event), GST_ELEMENT (GST_EVENT_SRC (event))); - gst_event_free (event); - break; - default: - GST_ELEMENT_CLASS (parent_class)->send_event (element, event); - break; - } + GST_ELEMENT_CLASS (parent_class)->send_event (element, event); } static GstElementStateReturn diff --git a/gst/gstbin.h b/gst/gstbin.h index 10ea7f2..7e36704 100644 --- a/gst/gstbin.h +++ b/gst/gstbin.h @@ -110,6 +110,10 @@ gboolean gst_bin_set_state_type (GstBin *bin, GstElementState state, GType type gboolean gst_bin_iterate (GstBin *bin); +/* internal */ +void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate, + GstElementState newstate, GstElement *child); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gst/gstelement.c b/gst/gstelement.c index 44cb156..6315fd6 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -831,9 +831,6 @@ gst_element_send_event_func (GstElement *element, GstEvent *event) } else { switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_STATE_CHANGE: - g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], 0, - GST_EVENT_STATE_OLD (event), GST_EVENT_STATE_NEW (event)); default: g_signal_emit (G_OBJECT (element), gst_element_signals[EVENT], 0, event); } @@ -968,6 +965,7 @@ static GstElementStateReturn gst_element_change_state (GstElement *element) { GstElementState old_state; + //GstEvent *event; g_return_val_if_fail (element != NULL, GST_STATE_FAILURE); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE); @@ -984,24 +982,9 @@ gst_element_change_state (GstElement *element) gst_element_statename (GST_STATE_PENDING (element)), GST_STATE_TRANSITION (element)); - if (GST_STATE_TRANSITION (element) == GST_STATE_PAUSED_TO_PLAYING) { - g_return_val_if_fail (GST_ELEMENT_SCHED (element), GST_STATE_FAILURE); - - if (GST_ELEMENT_PARENT (element)) { - GST_DEBUG (GST_CAT_STATES, "PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n", - GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (GST_ELEMENT_PARENT (element)), - GST_ELEMENT_SCHED (element)); - } - gst_scheduler_enable_element (element->sched, element); - } - else if (GST_STATE_TRANSITION (element) == GST_STATE_PLAYING_TO_PAUSED) { - if (GST_ELEMENT_PARENT (element)) { - GST_DEBUG (GST_CAT_STATES, "PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n", - GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (GST_ELEMENT_PARENT (element)), - GST_ELEMENT_SCHED (element)); - } - gst_scheduler_disable_element (element->sched, element); - } + /* tell the scheduler if we have one */ + if (element->sched) + gst_scheduler_state_transition (element->sched, element, GST_STATE_TRANSITION (element)); GST_STATE (element) = GST_STATE_PENDING (element); GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING; @@ -1010,11 +993,11 @@ gst_element_change_state (GstElement *element) g_cond_signal (element->state_cond); g_mutex_unlock (element->state_mutex); - { - GstEvent *event = gst_event_new_state_change (old_state, GST_STATE (element)); - - gst_element_send_event (element, event); + if (GST_ELEMENT_PARENT (element)) { + gst_bin_child_state_change (GST_BIN (GST_ELEMENT_PARENT (element)), old_state, GST_STATE (element), element); } + //event = gst_event_new_state_change (old_state, GST_STATE (element)); + //gst_element_send_event (element, event); return GST_STATE_SUCCESS; } diff --git a/gst/gstevent.c b/gst/gstevent.c index 2a3ff74..f7557eb 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -153,25 +153,5 @@ gst_event_new_info (const gchar *firstname, ...) return event; } -/** - * gst_event_new_state_change: - * @old: The old state - * @state: The new state - * - * Allocate a new state change event with the given props. - * - * Returns: A new state change event. - */ -GstEvent* -gst_event_new_state_change (GstElementState old, GstElementState state) -{ - GstEvent *event; - - event = gst_event_new (GST_EVENT_STATE_CHANGE); - GST_EVENT_STATE_OLD (event) = old; - GST_EVENT_STATE_NEW (event) = state; - - return event; -} diff --git a/gst/gstevent.h b/gst/gstevent.h index c1f35f2..c163292 100644 --- a/gst/gstevent.h +++ b/gst/gstevent.h @@ -45,7 +45,6 @@ typedef enum { /* vertical events */ GST_EVENT_INFO, GST_EVENT_ERROR, - GST_EVENT_STATE_CHANGE, } GstEventType; extern GType _gst_event_type; @@ -71,10 +70,6 @@ typedef enum { #define GST_EVENT_INFO_PROPS(event) (GST_EVENT(event)->event_data.info.props) -#define GST_EVENT_STATE_OLD(event) (GST_EVENT(event)->event_data.state.old_state) -#define GST_EVENT_STATE_NEW(event) (GST_EVENT(event)->event_data.state.new_state) - - struct _GstEvent { GstData data; @@ -112,9 +107,6 @@ GstEvent* gst_event_new_seek (GstSeekType type, guint64 offset, gboolean flush); /* info events */ GstEvent* gst_event_new_info (const gchar *firstname, ...); -/* state change events */ -GstEvent* gst_event_new_state_change (GstElementState old, GstElementState state); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gst/gstqueue.c b/gst/gstqueue.c index dac68ea..4375cec 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -331,8 +331,7 @@ restart: while (queue->level_buffers == queue->size_buffers) { /* if there's a pending state change for this queue or its manager, switch */ /* back to iterator so bottom half of state change executes */ - while (GST_STATE (queue) != GST_STATE_PLAYING) { - //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); @@ -400,8 +399,7 @@ restart: /* if there's a pending state change for this queue or its manager, switch * back to iterator so bottom half of state change executes */ - while (GST_STATE (queue) != GST_STATE_PLAYING) { - //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c index 553c520..e49ca5c 100644 --- a/gst/gstscheduler.c +++ b/gst/gstscheduler.c @@ -154,31 +154,18 @@ gst_scheduler_add_element (GstScheduler *sched, GstElement *element) } /** - * gst_scheduler_enable_element: + * gst_scheduler_state_transition: * @sched: the schedulerr - * @element: the element to enable + * @element: the element with the state transition + * @transition: the state transition * - * Enable an element for scheduling. + * Tell the scheduler that an element changed its state. */ void -gst_scheduler_enable_element (GstScheduler *sched, GstElement *element) +gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition) { - if (CLASS (sched)->enable_element) - CLASS (sched)->enable_element (sched, element); -} - -/** - * gst_scheduler_disable_element: - * @sched: the schedulerr - * @element: the element to disable - * - * Disable an element for scheduling. - */ -void -gst_scheduler_disable_element (GstScheduler *sched, GstElement *element) -{ - if (CLASS (sched)->disable_element) - CLASS (sched)->disable_element (sched, element); + if (CLASS (sched)->state_transition) + CLASS (sched)->state_transition (sched, element, transition); } /** diff --git a/gst/gstscheduler.h b/gst/gstscheduler.h index c60b55c..1b2dac5 100644 --- a/gst/gstscheduler.h +++ b/gst/gstscheduler.h @@ -69,8 +69,7 @@ struct _GstSchedulerClass { void (*reset) (GstScheduler *sched); void (*add_element) (GstScheduler *sched, GstElement *element); void (*remove_element) (GstScheduler *sched, GstElement *element); - void (*enable_element) (GstScheduler *sched, GstElement *element); - void (*disable_element) (GstScheduler *sched, GstElement *element); + void (*state_transition) (GstScheduler *sched, GstElement *element, gint transition); void (*lock_element) (GstScheduler *sched, GstElement *element); void (*unlock_element) (GstScheduler *sched, GstElement *element); void (*pad_connect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); @@ -90,8 +89,7 @@ void gst_scheduler_setup (GstScheduler *sched); void gst_scheduler_reset (GstScheduler *sched); void gst_scheduler_add_element (GstScheduler *sched, GstElement *element); void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element); -void gst_scheduler_enable_element (GstScheduler *sched, GstElement *element); -void gst_scheduler_disable_element (GstScheduler *sched, GstElement *element); +void gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition); void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element); void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element); void gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); diff --git a/gst/gstthread.c b/gst/gstthread.c index e6a8cd5..e76b8d5 100644 --- a/gst/gstthread.c +++ b/gst/gstthread.c @@ -324,13 +324,18 @@ gst_thread_change_state (GstElement * element) THR_DEBUG (" element \"%s\"\n", GST_ELEMENT_NAME (element)); elements = g_list_next (elements); if (GST_IS_QUEUE (element)) { + GstQueue *queue = GST_QUEUE (element); /* FIXME make this more efficient by only waking queues that are asleep * FIXME and only waking the appropriate condition (depending on if it's * FIXME on up- or down-stream side) * FIXME also make this more efficient by keeping list of managed queues */ THR_DEBUG ("waking queue \"%s\"\n", GST_ELEMENT_NAME (element)); - gst_element_set_state (element, GST_STATE_PAUSED); + g_mutex_lock (queue->qlock); + GST_STATE_PENDING (element) = GST_STATE_PAUSED; + g_cond_signal (queue->not_full); + g_cond_signal (queue->not_empty); + g_mutex_unlock (queue->qlock); } else { GList *pads = GST_ELEMENT_PADS (element); diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c index 9242cd2..02f3848 100644 --- a/gst/schedulers/gstbasicscheduler.c +++ b/gst/schedulers/gstbasicscheduler.c @@ -50,8 +50,7 @@ static void gst_basic_scheduler_setup (GstScheduler *sched); static void gst_basic_scheduler_reset (GstScheduler *sched); static void gst_basic_scheduler_add_element (GstScheduler *sched, GstElement *element); static void gst_basic_scheduler_remove_element (GstScheduler *sched, GstElement *element); -static void gst_basic_scheduler_enable_element (GstScheduler *sched, GstElement *element); -static void gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element); +static void gst_basic_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition); static void gst_basic_scheduler_lock_element (GstScheduler *sched, GstElement *element); static void gst_basic_scheduler_unlock_element (GstScheduler *sched, GstElement *element); static void gst_basic_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); @@ -102,8 +101,7 @@ gst_basic_scheduler_class_init (GstSchedulerClass * klass) klass->reset = GST_DEBUG_FUNCPTR (gst_basic_scheduler_reset); klass->add_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_add_element); klass->remove_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_remove_element); - klass->enable_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_enable_element); - klass->disable_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_disable_element); + klass->state_transition = GST_DEBUG_FUNCPTR (gst_basic_scheduler_state_transition); klass->lock_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_lock_element); klass->unlock_element = GST_DEBUG_FUNCPTR (gst_basic_scheduler_unlock_element); klass->pad_connect = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_connect); @@ -622,12 +620,6 @@ gst_basic_scheduler_chain_disable_element (GstSchedulerChain * chain, GstElement /* reschedule the chain */ /* FIXME this should be done only if manager state != NULL */ /* gst_basic_scheduler_cothreaded_chain(GST_BIN(chain->sched->parent),chain); */ - /* FIXME is this right? */ - /* we have to check for a threadstate here because a queue doesn't have one */ - if (element->threadstate) { - cothread_free (element->threadstate); - element->threadstate = NULL; - } } static void @@ -640,6 +632,11 @@ gst_basic_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement if (g_list_find (chain->elements, element)) { gst_basic_scheduler_chain_disable_element (chain, element); } + /* we have to check for a threadstate here because a queue doesn't have one */ + if (element->threadstate) { + cothread_free (element->threadstate); + element->threadstate = NULL; + } /* remove the element from the list of elements */ chain->disabled = g_list_remove (chain->disabled, element); @@ -907,23 +904,7 @@ gst_basic_scheduler_remove_element (GstScheduler * sched, GstElement * element) } static void -gst_basic_scheduler_enable_element (GstScheduler *sched, GstElement *element) -{ - GstSchedulerChain *chain; - - /* find the chain the element's in */ - chain = gst_basic_scheduler_find_chain (sched, element); - - if (chain) { - gst_basic_scheduler_chain_enable_element (chain, element); - } - else { - GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, not enabling", GST_ELEMENT_NAME (element)); - } -} - -static void -gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element) +gst_basic_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition) { GstSchedulerChain *chain; @@ -932,10 +913,13 @@ gst_basic_scheduler_disable_element (GstScheduler *sched, GstElement *element) /* remove it from the chain */ if (chain) { - gst_basic_scheduler_chain_disable_element (chain, element); + if (transition == GST_STATE_PLAYING_TO_PAUSED) + gst_basic_scheduler_chain_disable_element (chain, element); + if (transition == GST_STATE_PAUSED_TO_PLAYING) + gst_basic_scheduler_chain_enable_element (chain, element); } else { - GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, not disabling", GST_ELEMENT_NAME (element)); + GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, no state change", GST_ELEMENT_NAME (element)); } } diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index dac68ea..4375cec 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -331,8 +331,7 @@ restart: while (queue->level_buffers == queue->size_buffers) { /* if there's a pending state change for this queue or its manager, switch */ /* back to iterator so bottom half of state change executes */ - while (GST_STATE (queue) != GST_STATE_PLAYING) { - //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); @@ -400,8 +399,7 @@ restart: /* if there's a pending state change for this queue or its manager, switch * back to iterator so bottom half of state change executes */ - while (GST_STATE (queue) != GST_STATE_PLAYING) { - //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!\n"); g_mutex_unlock (queue->qlock); cothread_switch(cothread_current_main()); -- 2.7.4