- Reclaim cothread state even if the cothread was never activated after the free.
authorWim Taymans <wim.taymans@gmail.com>
Thu, 20 Dec 2001 20:03:10 +0000 (20:03 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 20 Dec 2001 20:03:10 +0000 (20:03 +0000)
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.

12 files changed:
gst/cothreads.c
gst/gstbin.c
gst/gstbin.h
gst/gstelement.c
gst/gstevent.c
gst/gstevent.h
gst/gstqueue.c
gst/gstscheduler.c
gst/gstscheduler.h
gst/gstthread.c
gst/schedulers/gstbasicscheduler.c
plugins/elements/gstqueue.c

index eae2012..48aa164 100644 (file)
@@ -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);
index c1a1b00..19674e8 100644 (file)
@@ -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
index 10ea7f2..7e36704 100644 (file)
@@ -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 */
index 44cb156..6315fd6 100644 (file)
@@ -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;
 }
index 2a3ff74..f7557eb 100644 (file)
@@ -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;
-}
 
 
index c1f35f2..c163292 100644 (file)
@@ -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 */
index dac68ea..4375cec 100644 (file)
@@ -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());
index 553c520..e49ca5c 100644 (file)
@@ -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);
 }
 
 /**
index c60b55c..1b2dac5 100644 (file)
@@ -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);
index e6a8cd5..e76b8d5 100644 (file)
@@ -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);
index 9242cd2..02f3848 100644 (file)
@@ -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));
   }
 }
 
index dac68ea..4375cec 100644 (file)
@@ -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());