2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstscheduler.c: Default scheduling code for most cases
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
29 #include "cothreads_compat.h"
31 GST_DEBUG_CATEGORY_STATIC (debug_dataflow);
32 GST_DEBUG_CATEGORY_STATIC (debug_scheduler);
33 #define GST_CAT_DEFAULT debug_scheduler
35 typedef struct _GstSchedulerChain GstSchedulerChain;
37 #define GST_ELEMENT_THREADSTATE(elem) (GST_ELEMENT (elem)->sched_private)
38 #define GST_RPAD_BUFPEN(pad) (GST_REAL_PAD(pad)->sched_private)
40 #define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1
41 #define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING)
43 typedef struct _GstBasicScheduler GstBasicScheduler;
44 typedef struct _GstBasicSchedulerClass GstBasicSchedulerClass;
46 #ifdef _COTHREADS_STANDARD
47 # define _SCHEDULER_NAME "standard"
49 # define _SCHEDULER_NAME "basic"
52 struct _GstSchedulerChain
54 GstBasicScheduler *sched;
63 gint cothreaded_elements;
67 #define GST_TYPE_BASIC_SCHEDULER \
68 (gst_basic_scheduler_get_type())
69 #define GST_BASIC_SCHEDULER(obj) \
70 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASIC_SCHEDULER,GstBasicScheduler))
71 #define GST_BASIC_SCHEDULER_CLASS(klass) \
72 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASIC_SCHEDULER,GstBasicSchedulerClass))
73 #define GST_IS_BASIC_SCHEDULER(obj) \
74 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASIC_SCHEDULER))
75 #define GST_IS_BASIC_SCHEDULER_CLASS(obj) \
76 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASIC_SCHEDULER))
78 #define SCHED(element) GST_BASIC_SCHEDULER (GST_ELEMENT_SCHEDULER (element))
82 GST_BASIC_SCHEDULER_STATE_NONE,
83 GST_BASIC_SCHEDULER_STATE_STOPPED,
84 GST_BASIC_SCHEDULER_STATE_ERROR,
85 GST_BASIC_SCHEDULER_STATE_RUNNING
87 GstBasicSchedulerState;
91 /* something important has changed inside the scheduler */
92 GST_BASIC_SCHEDULER_CHANGE = GST_SCHEDULER_FLAG_LAST
94 GstBasicSchedulerFlags;
96 struct _GstBasicScheduler
106 GstBasicSchedulerState state;
108 cothread_context *context;
112 struct _GstBasicSchedulerClass
114 GstSchedulerClass parent_class;
117 static GType _gst_basic_scheduler_type = 0;
119 static void gst_basic_scheduler_class_init (GstBasicSchedulerClass * klass);
120 static void gst_basic_scheduler_init (GstBasicScheduler * scheduler);
122 static void gst_basic_scheduler_dispose (GObject * object);
124 static void gst_basic_scheduler_setup (GstScheduler * sched);
125 static void gst_basic_scheduler_reset (GstScheduler * sched);
126 static void gst_basic_scheduler_add_element (GstScheduler * sched,
127 GstElement * element);
128 static void gst_basic_scheduler_remove_element (GstScheduler * sched,
129 GstElement * element);
130 static GstElementStateReturn gst_basic_scheduler_state_transition (GstScheduler
131 * sched, GstElement * element, gint transition);
132 static gboolean gst_basic_scheduler_yield (GstScheduler * sched,
133 GstElement * element);
134 static gboolean gst_basic_scheduler_interrupt (GstScheduler * sched,
135 GstElement * element);
136 static void gst_basic_scheduler_error (GstScheduler * sched,
137 GstElement * element);
138 static void gst_basic_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad,
140 static void gst_basic_scheduler_pad_unlink (GstScheduler * sched,
141 GstPad * srcpad, GstPad * sinkpad);
142 static GstData *gst_basic_scheduler_pad_select (GstScheduler * sched,
143 GstPad ** selected, GstPad ** padlist);
144 static GstSchedulerState gst_basic_scheduler_iterate (GstScheduler * sched);
146 static void gst_basic_scheduler_show (GstScheduler * sched);
148 static GstSchedulerClass *parent_class = NULL;
150 /* for threaded bins, these pre- and post-run functions lock and unlock the
151 * elements. we have to avoid deadlocks, so we make these convenience macros
152 * that will avoid using do_cothread_switch from within the scheduler. */
154 #define do_element_switch(element) G_STMT_START{ \
155 SCHED (element)->current = element; \
156 do_cothread_switch (GST_ELEMENT_THREADSTATE (element)); \
159 #define do_switch_to_main(sched) G_STMT_START{ \
160 ((GstBasicScheduler*) sched)->current = NULL; \
162 (do_cothread_get_main \
163 (((GstBasicScheduler*)sched)->context)); \
166 #define do_switch_from_main(entry) G_STMT_START{ \
167 SCHED (entry)->current = entry; \
168 do_cothread_switch (GST_ELEMENT_THREADSTATE (entry)); \
172 gst_basic_scheduler_get_type (void)
174 if (!_gst_basic_scheduler_type) {
175 static const GTypeInfo scheduler_info = {
176 sizeof (GstBasicSchedulerClass),
179 (GClassInitFunc) gst_basic_scheduler_class_init,
182 sizeof (GstBasicScheduler),
184 (GInstanceInitFunc) gst_basic_scheduler_init,
188 _gst_basic_scheduler_type =
189 g_type_register_static (GST_TYPE_SCHEDULER,
190 "Gst" COTHREADS_NAME_CAPITAL "Scheduler", &scheduler_info, 0);
192 return _gst_basic_scheduler_type;
196 gst_basic_scheduler_class_init (GstBasicSchedulerClass * klass)
198 GObjectClass *gobject_class;
199 GstObjectClass *gstobject_class;
200 GstSchedulerClass *gstscheduler_class;
202 gobject_class = (GObjectClass *) klass;
203 gstobject_class = (GstObjectClass *) klass;
204 gstscheduler_class = (GstSchedulerClass *) klass;
206 parent_class = g_type_class_ref (GST_TYPE_SCHEDULER);
208 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_basic_scheduler_dispose);
210 gstscheduler_class->setup = GST_DEBUG_FUNCPTR (gst_basic_scheduler_setup);
211 gstscheduler_class->reset = GST_DEBUG_FUNCPTR (gst_basic_scheduler_reset);
212 gstscheduler_class->add_element =
213 GST_DEBUG_FUNCPTR (gst_basic_scheduler_add_element);
214 gstscheduler_class->remove_element =
215 GST_DEBUG_FUNCPTR (gst_basic_scheduler_remove_element);
216 gstscheduler_class->state_transition =
217 GST_DEBUG_FUNCPTR (gst_basic_scheduler_state_transition);
218 gstscheduler_class->yield = GST_DEBUG_FUNCPTR (gst_basic_scheduler_yield);
219 gstscheduler_class->interrupt =
220 GST_DEBUG_FUNCPTR (gst_basic_scheduler_interrupt);
221 gstscheduler_class->error = GST_DEBUG_FUNCPTR (gst_basic_scheduler_error);
222 gstscheduler_class->pad_link =
223 GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_link);
224 gstscheduler_class->pad_unlink =
225 GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_unlink);
226 gstscheduler_class->pad_select =
227 GST_DEBUG_FUNCPTR (gst_basic_scheduler_pad_select);
228 gstscheduler_class->clock_wait = NULL;
229 gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_basic_scheduler_iterate);
231 gstscheduler_class->show = GST_DEBUG_FUNCPTR (gst_basic_scheduler_show);
233 do_cothreads_init (NULL);
237 gst_basic_scheduler_init (GstBasicScheduler * scheduler)
239 scheduler->elements = NULL;
240 scheduler->num_elements = 0;
241 scheduler->chains = NULL;
242 scheduler->num_chains = 0;
244 GST_FLAG_SET (scheduler, GST_SCHEDULER_FLAG_NEW_API);
248 gst_basic_scheduler_dispose (GObject * object)
250 G_OBJECT_CLASS (parent_class)->dispose (object);
254 plugin_init (GstPlugin * plugin)
256 if (!gst_scheduler_register (plugin, "basic" COTHREADS_NAME,
257 "A basic scheduler using " COTHREADS_NAME " cothreads",
258 gst_basic_scheduler_get_type ()))
261 GST_DEBUG_CATEGORY_INIT (debug_dataflow, "basic_dataflow", 0,
262 "basic scheduler dataflow");
263 GST_DEBUG_CATEGORY_INIT (debug_scheduler, "basic_scheduler", 0,
264 "basic scheduler general information");
269 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
271 "gstbasic" COTHREADS_NAME "scheduler",
272 "a basic scheduler using " COTHREADS_NAME " cothreads",
273 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
275 static int gst_basic_scheduler_loopfunc_wrapper (int argc, char **argv)
277 GstElement *element = GST_ELEMENT (argv);
278 G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element);
280 GST_DEBUG ("entering loopfunc wrapper of %s", name);
282 gst_object_ref (GST_OBJECT (element));
284 GST_CAT_DEBUG (debug_dataflow, "calling loopfunc %s for element %s",
285 GST_DEBUG_FUNCPTR_NAME (element->loopfunc), name);
286 (element->loopfunc) (element);
287 GST_CAT_DEBUG (debug_dataflow, "element %s ended loop function", name);
289 } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
290 GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING);
292 /* due to oddities in the cothreads code, when this function returns it will
293 * switch to the main cothread. thus, we need to unlock the current element. */
294 if (SCHED (element)) {
295 SCHED (element)->current = NULL;
298 GST_DEBUG ("leaving loopfunc wrapper of %s", name);
299 gst_object_unref (GST_OBJECT (element));
305 gst_basic_scheduler_chain_wrapper (int argc, char **argv)
307 GSList *already_iterated = NULL;
308 GstElement *element = GST_ELEMENT (argv);
309 G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element);
311 GST_DEBUG ("entered chain wrapper of element %s", name);
313 GST_CAT_DEBUG (debug_dataflow, "stepping through pads");
315 gst_object_ref (GST_OBJECT (element));
320 pads = element->pads;
323 GstPad *pad = GST_PAD (pads->data);
326 if (!GST_IS_REAL_PAD (pad))
329 realpad = GST_REAL_PAD (pad);
331 if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SINK &&
332 GST_PAD_IS_LINKED (realpad) &&
333 g_slist_find (already_iterated, pad) == NULL) {
336 GST_CAT_DEBUG (debug_dataflow, "pulling data from %s:%s", name,
338 data = gst_pad_pull (pad);
340 if (GST_IS_EVENT (data) && !GST_ELEMENT_IS_EVENT_AWARE (element)) {
341 gst_pad_send_event (pad, GST_EVENT (data));
343 GST_CAT_DEBUG (debug_dataflow,
344 "calling chain function of %s:%s %p", name,
345 GST_PAD_NAME (pad), data);
346 gst_pad_call_chain_function (GST_PAD (realpad), data);
347 GST_CAT_DEBUG (debug_dataflow,
348 "calling chain function of element %s done", name);
351 already_iterated = g_slist_prepend (already_iterated, pad);
354 pads = g_list_next (pads);
356 } while (pads != NULL);
357 if (already_iterated == NULL) {
358 GST_DEBUG_OBJECT (SCHED (element), "nothing to iterate for element %s",
359 GST_ELEMENT_NAME (element));
362 g_slist_free (already_iterated);
363 already_iterated = NULL;
364 } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
366 GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING);
368 /* due to oddities in the cothreads code, when this function returns it will
369 * switch to the main cothread. thus, we need to unlock the current element. */
370 if (SCHED (element)) {
371 SCHED (element)->current = NULL;
374 GST_CAT_DEBUG (debug_dataflow, "leaving chain wrapper of element %s", name);
375 gst_object_unref (GST_OBJECT (element));
381 gst_basic_scheduler_src_wrapper (int argc, char **argv)
383 GstElement *element = GST_ELEMENT (argv);
386 GstData *data = NULL;
388 G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element);
390 GST_DEBUG ("entering src wrapper of element %s", name);
394 pads = element->pads;
397 if (!GST_IS_REAL_PAD (pads->data))
400 realpad = GST_REAL_PAD (pads->data);
402 pads = g_list_next (pads);
403 if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SRC) {
405 GST_CAT_DEBUG (debug_dataflow, "calling _getfunc for %s:%s",
406 GST_DEBUG_PAD_NAME (realpad));
407 data = gst_pad_call_get_function (GST_PAD (realpad));
409 GST_CAT_DEBUG (debug_dataflow, "calling gst_pad_push on pad %s:%s %p",
410 GST_DEBUG_PAD_NAME (realpad), data);
411 gst_pad_push (GST_PAD (realpad), data);
415 } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element) && !inf_loop);
417 GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING);
419 /* due to oddities in the cothreads code, when this function returns it will
420 * switch to the main cothread. thus, we need to unlock the current element. */
421 SCHED (element)->current = NULL;
423 GST_DEBUG ("leaving src wrapper of element %s", name);
429 gst_basic_scheduler_chainhandler_proxy (GstPad * pad, GstData * data)
431 gint loop_count = 100;
435 parent = GST_PAD_PARENT (pad);
436 peer = GST_RPAD_PEER (pad);
438 GST_CAT_DEBUG (debug_dataflow, "putting buffer %p in peer \"%s:%s\"'s pen",
439 data, GST_DEBUG_PAD_NAME (peer));
442 * loop until the bufferpen is empty so we can fill it up again
444 while (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) != NULL && --loop_count) {
445 GST_CAT_DEBUG (debug_dataflow, "switching to %p to empty bufpen %d",
446 GST_ELEMENT_THREADSTATE (parent), loop_count);
448 do_element_switch (parent);
450 /* we may no longer be the same pad, check. */
451 if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) {
452 GST_CAT_DEBUG (debug_dataflow, "new pad in mid-switch!");
453 pad = (GstPad *) GST_RPAD_PEER (peer);
455 parent = GST_PAD_PARENT (pad);
456 peer = GST_RPAD_PEER (pad);
459 if (loop_count == 0) {
460 GST_ELEMENT_ERROR (parent, CORE, SCHEDULER, (NULL),
461 ("(internal error) basic: maximum number of switches exceeded"));
465 g_assert (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) == NULL);
467 /* now fill the bufferpen and switch so it can be consumed */
468 GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) = data;
469 GST_CAT_DEBUG (debug_dataflow, "switching to %p to consume buffer %p",
470 GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad)), data);
472 do_element_switch (parent);
474 GST_CAT_DEBUG (debug_dataflow, "leaving chainhandler proxy of %s:%s",
475 GST_DEBUG_PAD_NAME (pad));
479 gst_basic_scheduler_select_proxy (GstPad * pad, GstData * data)
483 parent = GST_PAD_PARENT (pad);
485 GST_CAT_DEBUG (debug_dataflow, "putting buffer %p in peer's pen of pad %s:%s",
486 data, GST_DEBUG_PAD_NAME (pad));
488 g_assert (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) == NULL);
489 /* now fill the bufferpen and switch so it can be consumed */
490 GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) = data;
491 GST_CAT_DEBUG (debug_dataflow, "switching to %p",
492 GST_ELEMENT_THREADSTATE (parent));
493 /* FIXME temporarily diabled */
494 /* parent->select_pad = pad; */
496 do_element_switch (parent);
498 GST_CAT_DEBUG (debug_dataflow, "done switching");
503 gst_basic_scheduler_gethandler_proxy (GstPad * pad)
509 GST_CAT_DEBUG (debug_dataflow, "entering gethandler proxy of %s:%s",
510 GST_DEBUG_PAD_NAME (pad));
512 parent = GST_PAD_PARENT (pad);
513 peer = GST_RPAD_PEER (pad);
515 /* FIXME this should be bounded */
516 /* we will loop switching to the peer until it's filled up the bufferpen */
517 while (GST_RPAD_BUFPEN (pad) == NULL) {
519 GST_CAT_DEBUG (debug_dataflow, "switching to \"%s\": %p to fill bufpen",
520 GST_ELEMENT_NAME (parent), GST_ELEMENT_THREADSTATE (parent));
522 do_element_switch (parent);
524 /* we may no longer be the same pad, check. */
525 if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) {
526 GST_CAT_DEBUG (debug_dataflow, "new pad in mid-switch!");
527 pad = (GstPad *) GST_RPAD_PEER (peer);
529 GST_ELEMENT_ERROR (parent, CORE, PAD, (NULL), ("pad unlinked"));
531 parent = GST_PAD_PARENT (pad);
532 peer = GST_RPAD_PEER (pad);
535 GST_CAT_DEBUG (debug_dataflow, "done switching");
537 /* now grab the buffer from the pen, clear the pen, and return the buffer */
538 data = GST_RPAD_BUFPEN (pad);
539 GST_RPAD_BUFPEN (pad) = NULL;
541 GST_CAT_DEBUG (debug_dataflow, "leaving gethandler proxy of %s:%s",
542 GST_DEBUG_PAD_NAME (pad));
548 gst_basic_scheduler_eventhandler_proxy (GstPad * srcpad, GstEvent * event)
552 GST_CAT_INFO (debug_dataflow, "intercepting event %d on pad %s:%s",
553 GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (srcpad));
555 /* figure out if we need to flush */
556 switch (GST_EVENT_TYPE (event)) {
557 case GST_EVENT_FLUSH:
561 case GST_EVENT_SEEK_SEGMENT:
562 flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
570 GstData *data = GST_RPAD_BUFPEN (srcpad);
572 GST_CAT_INFO (debug_dataflow, "event is flush");
575 GST_CAT_INFO (debug_dataflow, "need to clear some buffers");
577 gst_data_unref (data);
578 GST_RPAD_BUFPEN (srcpad) = NULL;
581 return GST_RPAD_EVENTFUNC (srcpad) (srcpad, event);
585 gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain)
589 cothread_func wrapper_function;
593 GST_DEBUG ("chain is using COTHREADS");
595 g_assert (chain->sched->context != NULL);
597 /* walk through all the chain's elements */
598 elements = chain->elements;
602 element = GST_ELEMENT (elements->data);
603 elements = g_list_next (elements);
605 decoupled = GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED);
607 /* start out without a wrapper function, we select it later */
608 wrapper_function = NULL;
610 /* if the element has a loopfunc... */
611 if (element->loopfunc != NULL) {
613 GST_DEBUG_FUNCPTR (gst_basic_scheduler_loopfunc_wrapper);
614 GST_DEBUG ("element '%s' is a loop-based", GST_ELEMENT_NAME (element));
616 /* otherwise we need to decide what kind of cothread
617 * if it's not DECOUPLED, we decide based on
618 * whether it's a source or not */
620 /* if it doesn't have any sinks, it must be a source (duh) */
621 if (element->numsinkpads == 0) {
623 GST_DEBUG_FUNCPTR (gst_basic_scheduler_src_wrapper);
624 GST_DEBUG ("element '%s' is a source, using _src_wrapper",
625 GST_ELEMENT_NAME (element));
628 GST_DEBUG_FUNCPTR (gst_basic_scheduler_chain_wrapper);
629 GST_DEBUG ("element '%s' is a filter, using _chain_wrapper",
630 GST_ELEMENT_NAME (element));
635 /* now we have to walk through the pads to set up their state */
636 pads = element->pads;
640 pad = GST_PAD (pads->data);
641 pads = g_list_next (pads);
643 if (!GST_IS_REAL_PAD (pad))
646 peerpad = GST_PAD_PEER (pad);
648 GstElement *peerelement = GST_ELEMENT (GST_PAD_PARENT (peerpad));
649 gboolean different_sched =
650 (peerelement->scheduler != GST_SCHEDULER (chain->sched));
651 gboolean peer_decoupled =
652 GST_FLAG_IS_SET (peerelement, GST_ELEMENT_DECOUPLED);
654 GST_DEBUG ("inspecting pad %s:%s", GST_DEBUG_PAD_NAME (peerpad));
656 /* we don't need to check this for decoupled elements */
658 /* if the peer element is in another schedule,
659 * it's not decoupled and we are not decoupled
660 * either, we have an error */
661 if (different_sched && !peer_decoupled) {
662 GST_ELEMENT_ERROR (element, CORE, SCHEDULER, (NULL),
663 ("element \"%s\" is not decoupled but has pads in different schedulers",
664 GST_ELEMENT_NAME (element)));
667 /* ok, the peer is in a different scheduler and is decoupled,
669 * handlers so we can talk with it */
670 else if (different_sched) {
671 if (GST_RPAD_DIRECTION (peerpad) == GST_PAD_SINK) {
672 GST_DEBUG ("copying chain func into push proxy for peer %s:%s",
673 GST_DEBUG_PAD_NAME (peerpad));
674 GST_RPAD_CHAINHANDLER (peerpad) = gst_pad_call_chain_function;
676 GST_DEBUG ("copying get func into pull proxy for peer %s:%s",
677 GST_DEBUG_PAD_NAME (peerpad));
678 GST_RPAD_GETHANDLER (peerpad) = gst_pad_call_get_function;
682 /* in any case we need to copy the eventfunc into the handler */
683 GST_RPAD_EVENTHANDLER (peerpad) = GST_RPAD_EVENTFUNC (peerpad);
686 /* if the element is DECOUPLED or outside the manager, we have to chain */
688 /* set the chain proxies */
689 if (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK) {
690 GST_DEBUG ("copying chain function into push proxy for %s:%s",
691 GST_DEBUG_PAD_NAME (pad));
692 GST_RPAD_CHAINHANDLER (pad) = gst_pad_call_chain_function;
694 GST_DEBUG ("copying get function into pull proxy for %s:%s",
695 GST_DEBUG_PAD_NAME (pad));
696 GST_RPAD_GETHANDLER (pad) = gst_pad_call_get_function;
699 /* otherwise we really are a cothread */
701 if (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK) {
702 GST_DEBUG ("setting cothreaded push proxy for sinkpad %s:%s",
703 GST_DEBUG_PAD_NAME (pad));
704 GST_RPAD_CHAINHANDLER (pad) =
705 GST_DEBUG_FUNCPTR (gst_basic_scheduler_chainhandler_proxy);
706 GST_RPAD_EVENTHANDLER (pad) = GST_RPAD_EVENTFUNC (pad);
708 GST_DEBUG ("setting cothreaded pull proxy for srcpad %s:%s",
709 GST_DEBUG_PAD_NAME (pad));
710 GST_RPAD_GETHANDLER (pad) =
711 GST_DEBUG_FUNCPTR (gst_basic_scheduler_gethandler_proxy);
712 /* the gethandler proxy function can queue a buffer in the bufpen, we need
713 * to remove this buffer when a flush event is sent on the pad */
714 GST_RPAD_EVENTHANDLER (pad) =
715 GST_DEBUG_FUNCPTR (gst_basic_scheduler_eventhandler_proxy);
720 /* need to set up the cothread now */
721 if (wrapper_function != NULL) {
722 if (GST_ELEMENT_THREADSTATE (element) == NULL) {
723 GST_DEBUG ("about to create a cothread, wrapper for '%s' is &%s",
724 GST_ELEMENT_NAME (element),
725 GST_DEBUG_FUNCPTR_NAME (wrapper_function));
726 do_cothread_create (GST_ELEMENT_THREADSTATE (element),
727 chain->sched->context, wrapper_function, 0, (char **) element);
728 if (GST_ELEMENT_THREADSTATE (element) == NULL) {
729 GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, (NULL),
730 ("could not create cothread for \"%s\"",
731 GST_ELEMENT_NAME (element)));
734 GST_DEBUG ("created cothread %p for '%s'",
735 GST_ELEMENT_THREADSTATE (element), GST_ELEMENT_NAME (element));
737 /* set the cothread wrapper function */
738 GST_DEBUG ("about to set the wrapper function for '%s' to &%s",
739 GST_ELEMENT_NAME (element),
740 GST_DEBUG_FUNCPTR_NAME (wrapper_function));
741 do_cothread_setfunc (GST_ELEMENT_THREADSTATE (element),
742 chain->sched->context, wrapper_function, 0, (char **) element);
743 GST_DEBUG ("set wrapper function for '%s' to &%s",
744 GST_ELEMENT_NAME (element),
745 GST_DEBUG_FUNCPTR_NAME (wrapper_function));
753 static GstSchedulerChain *
754 gst_basic_scheduler_chain_new (GstBasicScheduler * sched)
756 GstSchedulerChain *chain = g_new (GstSchedulerChain, 1);
758 /* initialize the chain with sane values */
759 chain->sched = sched;
760 chain->disabled = NULL;
761 chain->elements = NULL;
762 chain->num_elements = 0;
764 chain->cothreaded_elements = 0;
765 chain->schedule = FALSE;
767 /* add the chain to the schedulers' list of chains */
768 sched->chains = g_list_prepend (sched->chains, chain);
771 /* notify the scheduler that something changed */
772 GST_FLAG_SET (sched, GST_BASIC_SCHEDULER_CHANGE);
774 GST_INFO ("created new chain %p, now are %d chains in sched %p",
775 chain, sched->num_chains, sched);
781 gst_basic_scheduler_chain_destroy (GstSchedulerChain * chain)
783 GstBasicScheduler *sched = chain->sched;
785 /* remove the chain from the schedulers' list of chains */
786 sched->chains = g_list_remove (sched->chains, chain);
789 /* destroy the chain */
790 g_list_free (chain->disabled); /* should be empty... */
791 g_list_free (chain->elements); /* ditto */
793 GST_INFO ("destroyed chain %p, now are %d chains in sched %p", chain,
794 sched->num_chains, sched);
798 /* notify the scheduler that something changed */
799 GST_FLAG_SET (sched, GST_BASIC_SCHEDULER_CHANGE);
803 gst_basic_scheduler_chain_add_element (GstSchedulerChain * chain,
804 GstElement * element)
806 /* set the sched pointer for the element */
807 element->scheduler = GST_SCHEDULER (chain->sched);
809 /* add the element to either the main list or the disabled list */
810 if (GST_STATE (element) == GST_STATE_PLAYING) {
811 GST_INFO ("adding element \"%s\" to chain %p enabled",
812 GST_ELEMENT_NAME (element), chain);
813 chain->elements = g_list_prepend (chain->elements, element);
815 GST_INFO ("adding element \"%s\" to chain %p disabled",
816 GST_ELEMENT_NAME (element), chain);
817 chain->disabled = g_list_prepend (chain->disabled, element);
819 chain->num_elements++;
821 /* notify the scheduler that something changed */
822 GST_FLAG_SET (chain->sched, GST_BASIC_SCHEDULER_CHANGE);
826 gst_basic_scheduler_chain_enable_element (GstSchedulerChain * chain,
827 GstElement * element)
829 GST_INFO ("enabling element \"%s\" in chain %p",
830 GST_ELEMENT_NAME (element), chain);
832 /* remove from disabled list */
833 chain->disabled = g_list_remove (chain->disabled, element);
835 /* add to elements list */
836 chain->elements = g_list_prepend (chain->elements, element);
838 /* notify the scheduler that something changed */
839 GST_FLAG_SET (chain->sched, GST_BASIC_SCHEDULER_CHANGE);
840 /* GST_FLAG_UNSET(element, GST_ELEMENT_COTHREAD_STOPPING); */
842 /* reschedule the chain */
843 return gst_basic_scheduler_cothreaded_chain (GST_BIN (GST_SCHEDULER (chain->
844 sched)->parent), chain);
848 gst_basic_scheduler_chain_disable_element (GstSchedulerChain * chain,
849 GstElement * element)
851 GST_INFO ("disabling element \"%s\" in chain %p",
852 GST_ELEMENT_NAME (element), chain);
854 /* remove from elements list */
855 chain->elements = g_list_remove (chain->elements, element);
857 /* add to disabled list */
858 chain->disabled = g_list_prepend (chain->disabled, element);
860 /* notify the scheduler that something changed */
861 GST_FLAG_SET (chain->sched, GST_BASIC_SCHEDULER_CHANGE);
862 GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING);
864 /* reschedule the chain */
865 /* FIXME this should be done only if manager state != NULL */
866 /* gst_basic_scheduler_cothreaded_chain(GST_BIN(chain->sched->parent),chain); */
870 gst_basic_scheduler_chain_remove_element (GstSchedulerChain * chain,
871 GstElement * element)
873 GST_INFO ("removing element \"%s\" from chain %p", GST_ELEMENT_NAME (element),
876 /* if it's active, deactivate it */
877 if (g_list_find (chain->elements, element)) {
878 gst_basic_scheduler_chain_disable_element (chain, element);
880 /* we have to check for a threadstate here because a queue doesn't have one */
881 if (GST_ELEMENT_THREADSTATE (element)) {
882 do_cothread_destroy (GST_ELEMENT_THREADSTATE (element));
883 GST_ELEMENT_THREADSTATE (element) = NULL;
886 /* remove the element from the list of elements */
887 chain->disabled = g_list_remove (chain->disabled, element);
888 chain->num_elements--;
890 /* notify the scheduler that something changed */
891 GST_FLAG_SET (chain->sched, GST_BASIC_SCHEDULER_CHANGE);
893 /* if there are no more elements in the chain, destroy the chain */
894 if (chain->num_elements == 0)
895 gst_basic_scheduler_chain_destroy (chain);
900 gst_basic_scheduler_chain_elements (GstBasicScheduler * sched,
901 GstElement * element1, GstElement * element2)
904 GstSchedulerChain *chain;
905 GstSchedulerChain *chain1 = NULL, *chain2 = NULL;
908 /* first find the chains that hold the two */
909 chains = sched->chains;
911 chain = (GstSchedulerChain *) (chains->data);
912 chains = g_list_next (chains);
914 if (g_list_find (chain->disabled, element1))
916 else if (g_list_find (chain->elements, element1))
919 if (g_list_find (chain->disabled, element2))
921 else if (g_list_find (chain->elements, element2))
925 /* first check to see if they're in the same chain, we're done if that's the case */
926 if ((chain1 != NULL) && (chain1 == chain2)) {
927 GST_INFO ("elements are already in the same chain");
931 /* now, if neither element has a chain, create one */
932 if ((chain1 == NULL) && (chain2 == NULL)) {
933 GST_INFO ("creating new chain to hold two new elements");
934 chain = gst_basic_scheduler_chain_new (sched);
935 gst_basic_scheduler_chain_add_element (chain, element1);
936 gst_basic_scheduler_chain_add_element (chain, element2);
937 /* FIXME chain changed here */
938 /* gst_basic_scheduler_cothreaded_chain(chain->sched->parent,chain); */
940 /* otherwise if both have chains already, join them */
941 } else if ((chain1 != NULL) && (chain2 != NULL)) {
942 GST_INFO ("merging chain %p into chain %p", chain2, chain1);
943 /* take the contents of chain2 and merge them into chain1 */
945 g_list_concat (chain1->disabled, g_list_copy (chain2->disabled));
947 g_list_concat (chain1->elements, g_list_copy (chain2->elements));
948 chain1->num_elements += chain2->num_elements;
949 gst_basic_scheduler_chain_destroy (chain2);
952 gst_basic_scheduler_cothreaded_chain (GST_BIN (GST_SCHEDULER (chain1->
953 sched)->parent), chain1);
955 /* otherwise one has a chain already, the other doesn't */
957 /* pick out which one has the chain, and which doesn't */
959 chain = chain1, element = element2;
961 chain = chain2, element = element1;
963 GST_INFO ("adding element to existing chain");
964 gst_basic_scheduler_chain_add_element (chain, element);
965 /* FIXME chain changed here */
966 /* gst_basic_scheduler_cothreaded_chain(chain->sched->parent,chain); */
972 /* find the chain within the scheduler that holds the element, if any */
973 static GstSchedulerChain *
974 gst_basic_scheduler_find_chain (GstBasicScheduler * sched, GstElement * element)
977 GstSchedulerChain *chain;
979 GST_INFO ("searching for element \"%s\" in chains",
980 GST_ELEMENT_NAME (element));
982 chains = sched->chains;
984 chain = (GstSchedulerChain *) (chains->data);
985 chains = g_list_next (chains);
987 if (g_list_find (chain->elements, element))
989 if (g_list_find (chain->disabled, element))
997 gst_basic_scheduler_chain_recursive_add (GstSchedulerChain * chain,
998 GstElement * element, gboolean remove)
1002 GstElement *peerelement;
1003 GstSchedulerChain *prevchain;
1005 /* check to see if it's in a chain already */
1006 prevchain = gst_basic_scheduler_find_chain (chain->sched, element);
1007 /* if it's already in another chain, either remove or punt */
1008 if (prevchain != NULL) {
1010 gst_basic_scheduler_chain_remove_element (prevchain, element);
1015 /* add it to this one */
1016 gst_basic_scheduler_chain_add_element (chain, element);
1018 GST_DEBUG ("recursing on element \"%s\"", GST_ELEMENT_NAME (element));
1019 /* now go through all the pads and see which peers can be added */
1020 pads = element->pads;
1022 pad = GST_PAD (pads->data);
1023 pads = g_list_next (pads);
1025 GST_DEBUG ("have pad %s:%s, checking for valid peer",
1026 GST_DEBUG_PAD_NAME (pad));
1027 /* if the peer exists and could be in the same chain */
1028 if (GST_PAD_PEER (pad)) {
1029 GST_DEBUG ("has peer %s:%s", GST_DEBUG_PAD_NAME (GST_PAD_PEER (pad)));
1030 peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad));
1031 if (GST_ELEMENT_SCHEDULER (GST_PAD_PARENT (pad)) ==
1032 GST_ELEMENT_SCHEDULER (peerelement)) {
1033 GST_DEBUG ("peer \"%s\" is valid for same chain",
1034 GST_ELEMENT_NAME (peerelement));
1035 gst_basic_scheduler_chain_recursive_add (chain, peerelement, remove);
1042 * Entry points for this scheduler.
1045 gst_basic_scheduler_setup (GstScheduler * sched)
1047 /* first create thread context */
1048 if (GST_BASIC_SCHEDULER (sched)->context == NULL) {
1049 GST_DEBUG ("initializing cothread context");
1050 GST_BASIC_SCHEDULER (sched)->context = do_cothread_context_init ();
1055 gst_basic_scheduler_reset (GstScheduler * sched)
1057 cothread_context *ctx;
1058 GList *elements = GST_BASIC_SCHEDULER (sched)->elements;
1061 GstElement *element = GST_ELEMENT (elements->data);
1063 if (GST_ELEMENT_THREADSTATE (element)) {
1064 do_cothread_destroy (GST_ELEMENT_THREADSTATE (element));
1065 GST_ELEMENT_THREADSTATE (element) = NULL;
1067 elements = g_list_next (elements);
1070 ctx = GST_BASIC_SCHEDULER (sched)->context;
1072 do_cothread_context_destroy (ctx);
1074 GST_BASIC_SCHEDULER (sched)->context = NULL;
1078 gst_basic_scheduler_add_element (GstScheduler * sched, GstElement * element)
1080 GstSchedulerChain *chain;
1081 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1083 GST_INFO ("adding element \"%s\" to scheduler", GST_ELEMENT_NAME (element));
1085 /* only deal with elements after this point, not bins */
1086 /* exception is made for Bin's that are schedulable, like the autoplugger */
1087 if (GST_IS_BIN (element)
1088 && !GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE))
1091 /* first add it to the list of elements that are to be scheduled */
1092 bsched->elements = g_list_prepend (bsched->elements, element);
1093 bsched->num_elements++;
1095 /* create a chain to hold it, and add */
1096 chain = gst_basic_scheduler_chain_new (bsched);
1097 gst_basic_scheduler_chain_add_element (chain, element);
1101 gst_basic_scheduler_remove_element (GstScheduler * sched, GstElement * element)
1103 GstSchedulerChain *chain;
1104 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1106 if (g_list_find (bsched->elements, element)) {
1107 GST_INFO ("removing element \"%s\" from scheduler",
1108 GST_ELEMENT_NAME (element));
1110 /* if we are removing the currently scheduled element */
1111 if (bsched->current == element) {
1112 GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING);
1113 bsched->current = NULL;
1115 /* find what chain the element is in */
1116 chain = gst_basic_scheduler_find_chain (bsched, element);
1118 /* remove it from its chain */
1119 if (chain != NULL) {
1120 gst_basic_scheduler_chain_remove_element (chain, element);
1123 /* remove it from the list of elements */
1124 bsched->elements = g_list_remove (bsched->elements, element);
1125 bsched->num_elements--;
1127 /* unset the scheduler pointer in the element */
1131 static GstElementStateReturn
1132 gst_basic_scheduler_state_transition (GstScheduler * sched,
1133 GstElement * element, gint transition)
1135 GstSchedulerChain *chain;
1136 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1138 /* check if our parent changed state */
1139 if (GST_SCHEDULER_PARENT (sched) == element) {
1140 GST_INFO ("parent \"%s\" changed state", GST_ELEMENT_NAME (element));
1141 if (transition == GST_STATE_PLAYING_TO_PAUSED) {
1142 GST_INFO ("setting scheduler state to stopped");
1143 GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_STOPPED;
1144 } else if (transition == GST_STATE_PAUSED_TO_PLAYING) {
1145 GST_INFO ("setting scheduler state to running");
1146 GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_RUNNING;
1148 GST_INFO ("no interesting state change, doing nothing");
1150 } else if (transition == GST_STATE_PLAYING_TO_PAUSED ||
1151 transition == GST_STATE_PAUSED_TO_PLAYING) {
1152 /* find the chain the element is in */
1153 chain = gst_basic_scheduler_find_chain (bsched, element);
1155 /* remove it from the chain */
1157 if (transition == GST_STATE_PLAYING_TO_PAUSED) {
1158 gst_basic_scheduler_chain_disable_element (chain, element);
1159 } else if (transition == GST_STATE_PAUSED_TO_PLAYING) {
1160 if (!gst_basic_scheduler_chain_enable_element (chain, element)) {
1161 GST_INFO ("could not enable element \"%s\"",
1162 GST_ELEMENT_NAME (element));
1163 return GST_STATE_FAILURE;
1167 GST_INFO ("element \"%s\" not found in any chain, no state change",
1168 GST_ELEMENT_NAME (element));
1172 return GST_STATE_SUCCESS;
1176 gst_basic_scheduler_yield (GstScheduler * sched, GstElement * element)
1178 if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) {
1180 do_switch_to_main (sched);
1182 /* no need to do a pre_run, the cothread is stopping */
1188 gst_basic_scheduler_interrupt (GstScheduler * sched, GstElement * element)
1191 GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING);
1192 do_switch_to_main (sched);
1198 gst_basic_scheduler_error (GstScheduler * sched, GstElement * element)
1200 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1202 if (GST_ELEMENT_THREADSTATE (element)) {
1203 GstSchedulerChain *chain;
1205 chain = gst_basic_scheduler_find_chain (bsched, element);
1207 gst_basic_scheduler_chain_disable_element (chain, element);
1209 GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_ERROR;
1211 do_switch_to_main (sched);
1216 gst_basic_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad,
1219 GstElement *srcelement, *sinkelement;
1220 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1222 srcelement = GST_PAD_PARENT (srcpad);
1223 g_return_if_fail (srcelement != NULL);
1224 sinkelement = GST_PAD_PARENT (sinkpad);
1225 g_return_if_fail (sinkelement != NULL);
1227 GST_INFO ("have pad linked callback on %s:%s to %s:%s",
1228 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
1229 GST_DEBUG ("srcpad sched is %p, sinkpad sched is %p",
1230 GST_ELEMENT_SCHEDULER (srcelement), GST_ELEMENT_SCHEDULER (sinkelement));
1232 gst_basic_scheduler_chain_elements (bsched, srcelement, sinkelement);
1236 gst_basic_scheduler_pad_unlink (GstScheduler * sched, GstPad * srcpad,
1239 GstElement *element1, *element2;
1240 GstSchedulerChain *chain1, *chain2;
1241 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1243 GST_INFO ("unlinking pads %s:%s and %s:%s",
1244 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
1246 /* we need to have the parent elements of each pad */
1247 element1 = GST_ELEMENT (GST_PAD_PARENT (srcpad));
1248 element2 = GST_ELEMENT (GST_PAD_PARENT (sinkpad));
1250 /* first task is to remove the old chain they belonged to.
1251 * this can be accomplished by taking either of the elements,
1252 * since they are guaranteed to be in the same chain
1253 * FIXME is it potentially better to make an attempt at splitting cleaner??
1255 chain1 = gst_basic_scheduler_find_chain (bsched, element1);
1256 chain2 = gst_basic_scheduler_find_chain (bsched, element2);
1258 /* FIXME: The old code still works in most cases, but does not deal with
1259 * the problem of screwed up sched chains in some autoplugging cases.
1260 * The new code has an infinite recursion bug during pipeline shutdown,
1261 * which must be fixed before it can be enabled again.
1264 if (chain1 != chain2) {
1265 /* elements not in the same chain don't need to be separated */
1266 GST_INFO ("elements not in the same chain");
1271 GST_INFO ("destroying chain");
1272 gst_basic_scheduler_chain_destroy (chain1);
1274 /* now create a new chain to hold element1 and build it from scratch */
1275 chain1 = gst_basic_scheduler_chain_new (bsched);
1276 gst_basic_scheduler_chain_recursive_add (chain1, element1, FALSE);
1279 /* check the other element to see if it landed in the newly created chain */
1280 if (gst_basic_scheduler_find_chain (bsched, element2) == NULL) {
1281 /* if not in chain, create chain and build from scratch */
1282 chain2 = gst_basic_scheduler_chain_new (bsched);
1283 gst_basic_scheduler_chain_recursive_add (chain2, element2, FALSE);
1287 /* if they're both in the same chain, move second set of elements to a new chain */
1288 if (chain1 && (chain1 == chain2)) {
1289 GST_INFO ("creating new chain for second element and peers");
1290 chain2 = gst_basic_scheduler_chain_new (bsched);
1291 gst_basic_scheduler_chain_recursive_add (chain2, element2, TRUE);
1297 gst_basic_scheduler_pad_select (GstScheduler * sched, GstPad ** selected,
1300 GstData *data = NULL;
1303 GST_INFO ("performing select");
1305 while (padlist[i]) {
1306 GstPad *pad = padlist[i];
1308 GST_RPAD_CHAINHANDLER (pad) =
1309 GST_DEBUG_FUNCPTR (gst_basic_scheduler_select_proxy);
1312 do_element_switch (GST_PAD_PARENT (GST_PAD_PEER (padlist[0])));
1315 while (padlist[i]) {
1316 GstPad *pad = padlist[i];
1318 if (GST_RPAD_BUFPEN (pad)) {
1320 data = GST_RPAD_BUFPEN (pad);
1321 GST_RPAD_BUFPEN (pad) = NULL;
1324 GST_RPAD_CHAINHANDLER (pad) =
1325 GST_DEBUG_FUNCPTR (gst_basic_scheduler_chainhandler_proxy);
1328 g_assert (data != NULL);
1332 static GstSchedulerState
1333 gst_basic_scheduler_iterate (GstScheduler * sched)
1336 GstSchedulerChain *chain;
1340 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1342 GST_CAT_LOG_OBJECT (debug_dataflow, sched,
1343 "starting iteration in bin %s", GST_ELEMENT_NAME (sched->parent));
1345 /* clear the changes flag */
1346 GST_FLAG_UNSET (bsched, GST_BASIC_SCHEDULER_CHANGE);
1348 /* step through all the chains */
1349 chains = bsched->chains;
1352 return GST_SCHEDULER_STATE_STOPPED;
1355 chain = (GstSchedulerChain *) (chains->data);
1356 chains = g_list_next (chains);
1358 /* all we really have to do is switch to the first child */
1359 /* FIXME this should be lots more intelligent about where to start */
1360 GST_CAT_DEBUG (debug_dataflow,
1361 "starting iteration via cothreads using %s scheduler", _SCHEDULER_NAME);
1363 if (chain->elements) {
1364 entry = NULL; /*MattH ADDED? */
1365 GST_DEBUG ("there are %d elements in this chain", chain->num_elements);
1366 elements = chain->elements;
1368 entry = GST_ELEMENT (elements->data);
1369 elements = g_list_next (elements);
1370 if (GST_FLAG_IS_SET (entry, GST_ELEMENT_DECOUPLED)) {
1371 GST_DEBUG ("entry \"%s\" is DECOUPLED, skipping",
1372 GST_ELEMENT_NAME (entry));
1374 } else if (GST_FLAG_IS_SET (entry, GST_ELEMENT_INFINITE_LOOP)) {
1375 GST_DEBUG ("entry \"%s\" is not valid, skipping",
1376 GST_ELEMENT_NAME (entry));
1382 GstSchedulerState state;
1384 GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING);
1386 GST_CAT_DEBUG (debug_dataflow,
1387 "set COTHREAD_STOPPING flag on \"%s\"(@%p)",
1388 GST_ELEMENT_NAME (entry), entry);
1389 if (GST_ELEMENT_THREADSTATE (entry)) {
1391 do_switch_from_main (entry);
1393 state = GST_SCHEDULER_STATE (sched);
1394 /* if something changed, return - go on else */
1395 if (GST_FLAG_IS_SET (bsched, GST_BASIC_SCHEDULER_CHANGE) &&
1396 state != GST_SCHEDULER_STATE_ERROR)
1397 return GST_SCHEDULER_STATE_RUNNING;
1399 GST_CAT_DEBUG (debug_dataflow,
1400 "cothread switch not possible, element has no threadstate");
1401 return GST_SCHEDULER_STATE_ERROR;
1404 /* following is a check to see if the chain was interrupted due to a
1405 * top-half state_change(). (i.e., if there's a pending state.)
1407 * if it was, return to gstthread.c::gst_thread_main_loop() to
1408 * execute the state change.
1410 GST_CAT_DEBUG (debug_dataflow, "cothread switch ended or interrupted");
1412 if (state != GST_SCHEDULER_STATE_RUNNING) {
1413 GST_CAT_INFO (debug_dataflow, "scheduler is not running, in state %d",
1420 GST_CAT_INFO (debug_dataflow,
1421 "no entry in this chain, trying the next one");
1424 GST_CAT_INFO (debug_dataflow,
1425 "no enabled elements in this chain, trying the next one");
1429 GST_CAT_LOG_OBJECT (debug_dataflow, sched, "leaving (%s)",
1430 GST_ELEMENT_NAME (sched->parent));
1431 if (scheduled == 0) {
1432 GST_CAT_INFO (debug_dataflow, "nothing was scheduled, return STOPPED");
1433 return GST_SCHEDULER_STATE_STOPPED;
1435 GST_CAT_INFO (debug_dataflow, "scheduler still running, return RUNNING");
1436 return GST_SCHEDULER_STATE_RUNNING;
1442 gst_basic_scheduler_show (GstScheduler * sched)
1444 GList *chains, *elements;
1445 GstElement *element;
1446 GstSchedulerChain *chain;
1447 GstBasicScheduler *bsched = GST_BASIC_SCHEDULER (sched);
1449 if (sched == NULL) {
1450 g_print ("scheduler doesn't exist for this element\n");
1454 g_return_if_fail (GST_IS_SCHEDULER (sched));
1456 g_print ("SCHEDULER DUMP FOR MANAGING BIN \"%s\"\n",
1457 GST_ELEMENT_NAME (sched->parent));
1459 g_print ("scheduler has %d elements in it: ", bsched->num_elements);
1460 elements = bsched->elements;
1462 element = GST_ELEMENT (elements->data);
1463 elements = g_list_next (elements);
1465 g_print ("%s, ", GST_ELEMENT_NAME (element));
1469 g_print ("scheduler has %d chains in it\n", bsched->num_chains);
1470 chains = bsched->chains;
1472 chain = (GstSchedulerChain *) (chains->data);
1473 chains = g_list_next (chains);
1475 g_print ("%p: ", chain);
1477 elements = chain->disabled;
1479 element = GST_ELEMENT (elements->data);
1480 elements = g_list_next (elements);
1482 g_print ("!%s, ", GST_ELEMENT_NAME (element));
1485 elements = chain->elements;
1487 element = GST_ELEMENT (elements->data);
1488 elements = g_list_next (elements);
1490 g_print ("%s, ", GST_ELEMENT_NAME (element));