diff --git a/common b/common index e5997d9e2b..8d060610bb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit e5997d9e2b4e162ad423f9b9ec3ac9b29e12bb05 +Subproject commit 8d060610bbe0af2f159b40c8b23076896b4104a5 diff --git a/gst/schedulers/Makefile.am b/gst/schedulers/Makefile.am index a0b856da04..182c8c212d 100644 --- a/gst/schedulers/Makefile.am +++ b/gst/schedulers/Makefile.am @@ -1,21 +1,26 @@ plugindir = $(libdir)/gst -plugin_LTLIBRARIES = libgstbasicscheduler.la libgststandardscheduler.la libgstfastscheduler.la +plugin_LTLIBRARIES = libgstbasicscheduler.la libgststandardscheduler.la libgstfastbasicscheduler.la libgstfaststandardscheduler.la libgstbasicscheduler_la_SOURCES = gstbasicscheduler.c -libgstbasicscheduler_la_CFLAGS = $(GST_CFLAGS) +libgstbasicscheduler_la_CFLAGS = $(GST_CFLAGS) -D_COTHREADS_BASIC libgstbasicscheduler_la_LIBADD = ../libcothreads.la libgstbasicscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgststandardscheduler_la_SOURCES = gststandardscheduler.c -libgststandardscheduler_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/libs/ext/cothreads +libgststandardscheduler_la_SOURCES = gstbasicscheduler.c +libgststandardscheduler_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/libs/ext/cothreads -D_COTHREADS_STANDARD libgststandardscheduler_la_LIBADD = $(top_builddir)/libs/ext/cothreads/cothreads/libcothreads-gthreads.la libgststandardscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstfastscheduler_la_SOURCES = gstfastscheduler.c -libgstfastscheduler_la_CFLAGS = $(GST_CFLAGS) -libgstfastscheduler_la_LIBADD = ../libcothreads.la -libgstfastscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstfastbasicscheduler_la_SOURCES = gstfastscheduler.c +libgstfastbasicscheduler_la_CFLAGS = $(GST_CFLAGS) -D_COTHREADS_BASIC +libgstfastbasicscheduler_la_LIBADD = ../libcothreads.la +libgstfastbasicscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +libgstfaststandardscheduler_la_SOURCES = gstfastscheduler.c +libgstfaststandardscheduler_la_CFLAGS = $(GST_CFLAGS) -I$(top_srcdir)/libs/ext/cothreads -D_COTHREADS_STANDARD +libgstfaststandardscheduler_la_LIBADD = $(top_builddir)/libs/ext/cothreads/cothreads/libcothreads-gthreads.la +libgstfaststandardscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) ## this is a REALLY evil hack ## but we need to keep it as long as we have libs/gst and libs/ext diff --git a/gst/schedulers/cothreads_compat.h b/gst/schedulers/cothreads_compat.h new file mode 100644 index 0000000000..5e1d19236f --- /dev/null +++ b/gst/schedulers/cothreads_compat.h @@ -0,0 +1,133 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstscheduler.c: Default scheduling code for most cases + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* use the old cothreads implementation in gst/cothreads.[ch] */ +#if defined(_COTHREADS_BASIC) + +#include "../cothreads.h" + +/* the name of this cothreads type */ +#define COTHREADS_NAME "basic" +#define COTHREADS_NAME_CAPITAL "Basic" + +/* unify the structs + * + * "cothread" and "cothread_context" need to vbe defined + */ +typedef cothread_state cothread; + +/* define functions + * the macros are prepended with "do_" + */ +#define do_cothreads_init(x) /* NOP */ + +#define do_cothread_switch(to) cothread_switch(to) + +#define do_cothread_create(new_thread, context, func, argc, argv) \ + G_STMT_START{ \ + new_thread = cothread_create (context); \ + if (new_thread) { \ + cothread_setfunc (new_thread, (func), (argc), (argv)); \ + }\ + }G_STMT_END + +#define do_cothread_reset(cothread, context, func, argc, argv) \ + cothread_setfunc ((cothread), (func), (argc), (argv)) + +#define do_cothread_destroy(cothread) cothread_free(cothread) + +#define do_cothread_context_init() (cothread_context_init ()) +#define do_cothread_context_destroy(context) cothread_context_free (context) + +#define do_cothread_lock(cothread) cothread_lock(cothread) +#define do_cothread_unlock(cothread) cothread_unlock(cothread) + +#define do_cothread_get_current() (cothread_current()) +#define do_cothread_get_main(context) (cothread_current_main()) + + + + +/* use the new cothreads implementation in libs/ext/cothreads */ +#elif defined(_COTHREADS_STANDARD) + +#include +#include + +/* the name of this cothreads */ +#define COTHREADS_NAME "standard" +#define COTHREADS_NAME_CAPITAL "Standard" + +/* unify the structs + * + * "cothread" and "cothread_context" need to vbe defined + */ +typedef cothread cothread_context; + +/* define functions + * the macros are prepended with "do_" + */ +#define do_cothreads_init(x) G_STMT_START{ \ + if (!cothreads_initialized()) \ + cothreads_init(x); \ + }G_STMT_END + +#define do_cothread_switch(to) G_STMT_START{ \ + cothread *from = cothread_self (); \ + if (from == (to)) { \ + GST_DEBUG (GST_CAT_COTHREAD_SWITCH, "trying to switch to the same cothread (%p), not allowed", \ + (to)); \ + g_warning ("trying to switch to the same cothread, not allowed"); \ + } else { \ + GST_INFO (GST_CAT_COTHREAD_SWITCH, "switching from cothread %p to cothread %p", \ + from, (to)); \ + cothread_switch (from, (to)); \ + GST_INFO (GST_CAT_COTHREAD_SWITCH, "we're in cothread %p now", from); \ + } \ +}G_STMT_END + +#define do_cothread_create(new_thread, context, func, argc, argv) \ + G_STMT_START{ \ + new_thread = cothread_create ((func), 0, (void**) (argv), (context)); \ + }G_STMT_END + +#define do_cothread_reset(cothread, context, func, argc, argv) \ + cothread_reset ((cothread), (func), (argc), (void **) (argv), (context)) + +#define do_cothread_destroy(cothread) cothread_destroy(cothread) + +#define do_cothread_context_init() (cothread_create (NULL, 0, NULL, NULL)) +#define do_cothread_context_destroy(context) cothread_destroy (context) + +#define do_cothread_lock(cothread) /* FIXME */ +#define do_cothread_unlock(cothread) /* FIXME */ + +#define do_cothread_get_current() (cothread_self()) +#define do_cothread_get_main(context) (context) + + + + +/* bail out with an error if no cothreads package is defined */ +#else +#error "No cothreads package defined" +#endif diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c index 6420ae06ac..4aac1d9145 100644 --- a/gst/schedulers/gstbasicscheduler.c +++ b/gst/schedulers/gstbasicscheduler.c @@ -22,13 +22,13 @@ /*#define GST_DEBUG_ENABLED */ #include -#include <../cothreads.h> + +#include "cothreads_compat.h" typedef struct _GstSchedulerChain GstSchedulerChain; -#define GST_PAD_THREADSTATE(pad) (cothread_state*) (GST_PAD_CAST (pad)->sched_private) -#define GST_ELEMENT_THREADSTATE(elem) (cothread_state*) (GST_ELEMENT_CAST (elem)->sched_private) -#define GST_BIN_THREADCONTEXT(bin) (cothread_context*) (GST_BIN_CAST (bin)->sched_private) +#define GST_PAD_THREADSTATE(pad) (cothread*) (GST_PAD_CAST (pad)->sched_private) +#define GST_ELEMENT_THREADSTATE(elem) (cothread*) (GST_ELEMENT_CAST (elem)->sched_private) #define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1 #define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING) @@ -85,6 +85,8 @@ struct _GstBasicScheduler { gint num_chains; GstBasicSchedulerState state; + + cothread_context *context; }; struct _GstBasicSchedulerClass { @@ -138,7 +140,7 @@ gst_basic_scheduler_get_type (void) NULL }; - _gst_basic_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstBasicScheduler", &scheduler_info, 0); + _gst_basic_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "Gst"COTHREADS_NAME_CAPITAL"Scheduler", &scheduler_info, 0); } return _gst_basic_scheduler_type; } @@ -175,6 +177,8 @@ gst_basic_scheduler_class_init (GstBasicSchedulerClass * klass) gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_basic_scheduler_iterate); gstscheduler_class->show = GST_DEBUG_FUNCPTR (gst_basic_scheduler_show); + + do_cothreads_init(NULL); } static void @@ -199,15 +203,15 @@ plugin_init (GModule *module, GstPlugin *plugin) gst_plugin_set_longname (plugin, "A basic scheduler"); - factory = gst_scheduler_factory_new ("basic", - "A basic scheduler, it uses cothreads", + factory = gst_scheduler_factory_new (COTHREADS_NAME, + "A basic scheduler, it uses "COTHREADS_NAME" cothreads", gst_basic_scheduler_get_type()); if (factory != NULL) { gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); } else { - g_warning ("could not register scheduler: basic"); + g_warning ("could not register scheduler: "COTHREADS_NAME); } return TRUE; } @@ -215,7 +219,7 @@ plugin_init (GModule *module, GstPlugin *plugin) GstPluginDesc plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, - "gstbasicscheduler", + "gst"COTHREADS_NAME"scheduler", plugin_init }; @@ -363,7 +367,7 @@ gst_basic_scheduler_chainhandler_proxy (GstPad * pad, GstBuffer * buf) while (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) != NULL && --loop_count) { GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to empty bufpen %d", GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad)), loop_count); - cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); + do_cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); /* we may no longer be the same pad, check. */ if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { @@ -382,7 +386,7 @@ gst_basic_scheduler_chainhandler_proxy (GstPad * pad, GstBuffer * buf) GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) = buf; GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p", GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); + do_cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); } @@ -401,7 +405,7 @@ gst_basic_scheduler_select_proxy (GstPad * pad, GstBuffer * buf) GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); GST_ELEMENT (GST_PAD_PARENT (pad))->select_pad = pad; - cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); + do_cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); } @@ -421,7 +425,7 @@ gst_basic_scheduler_gethandler_proxy (GstPad * pad) GST_DEBUG (GST_CAT_DATAFLOW, "switching to \"%s\": %p to fill bufpen", GST_ELEMENT_NAME (GST_ELEMENT (GST_PAD_PARENT (pad))), GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); + do_cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); /* we may no longer be the same pad, check. */ if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { @@ -459,7 +463,7 @@ gst_basic_scheduler_pullregionfunc_proxy (GstPad * pad, GstRegionType type, guin while (GST_RPAD_BUFPEN (pad) == NULL) { GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to fill bufpen", GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); + do_cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); /* we may no longer be the same pad, check. */ if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { @@ -487,7 +491,7 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) GST_DEBUG (GST_CAT_SCHEDULING, "chain is using COTHREADS"); - g_assert (GST_BIN_THREADCONTEXT (bin) != NULL); + g_assert (chain->sched->context != NULL); /* walk through all the chain's elements */ elements = chain->elements; @@ -583,8 +587,8 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) /* need to set up the cothread now */ if (wrapper_function != NULL) { if (GST_ELEMENT_THREADSTATE (element) == NULL) { - GST_ELEMENT_THREADSTATE (element) = cothread_create (GST_BIN_THREADCONTEXT (bin)); - cothread_set_private (GST_ELEMENT_THREADSTATE (element), element); + do_cothread_create (GST_ELEMENT_THREADSTATE (element), chain->sched->context, + wrapper_function, 0, (char **) element); if (GST_ELEMENT_THREADSTATE (element) == NULL) { gst_element_error (element, "could not create cothread for \"%s\"", GST_ELEMENT_NAME (element), NULL); @@ -593,10 +597,12 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) GST_DEBUG (GST_CAT_SCHEDULING, "created cothread %p for '%s'", GST_ELEMENT_THREADSTATE (element), GST_ELEMENT_NAME (element)); + } else { + do_cothread_reset (GST_ELEMENT_THREADSTATE (element), chain->sched->context, + wrapper_function, 0, (char **) element); + GST_DEBUG (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s", + GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); } - cothread_setfunc (GST_ELEMENT_THREADSTATE (element), wrapper_function, 0, (char **) element); - GST_DEBUG (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s", - GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); } } @@ -722,7 +728,7 @@ gst_basic_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement } /* we have to check for a threadstate here because a queue doesn't have one */ if (GST_ELEMENT_THREADSTATE (element)) { - cothread_free (GST_ELEMENT_THREADSTATE (element)); + do_cothread_destroy (GST_ELEMENT_THREADSTATE (element)); GST_ELEMENT_THREADSTATE (element) = NULL; } @@ -875,12 +881,11 @@ gst_basic_scheduler_chain_recursive_add (GstSchedulerChain * chain, GstElement * static void gst_basic_scheduler_setup (GstScheduler *sched) { - GstBin *bin = GST_BIN (sched->parent); /* first create thread context */ - if (GST_BIN_THREADCONTEXT (bin) == NULL) { + if (GST_BASIC_SCHEDULER_CAST (sched)->context == NULL) { GST_DEBUG (GST_CAT_SCHEDULING, "initializing cothread context"); - GST_BIN_THREADCONTEXT (bin) = cothread_context_init (); + GST_BASIC_SCHEDULER_CAST (sched)->context = do_cothread_context_init (); } } @@ -891,15 +896,16 @@ gst_basic_scheduler_reset (GstScheduler *sched) GList *elements = GST_BASIC_SCHEDULER_CAST (sched)->elements; while (elements) { + /* FIXME: wingo, do we need to destroy the cothreads here? */ GST_ELEMENT_THREADSTATE (elements->data) = NULL; elements = g_list_next (elements); } - ctx = GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)); + ctx = GST_BASIC_SCHEDULER_CAST (sched)->context; - cothread_context_free (ctx); + do_cothread_context_destroy (ctx); - GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)) = NULL; + GST_BASIC_SCHEDULER_CAST (sched)->context = NULL; } static void @@ -1040,21 +1046,21 @@ static void gst_basic_scheduler_lock_element (GstScheduler * sched, GstElement * element) { if (GST_ELEMENT_THREADSTATE (element)) - cothread_lock (GST_ELEMENT_THREADSTATE (element)); + do_cothread_lock (GST_ELEMENT_THREADSTATE (element)); } static void gst_basic_scheduler_unlock_element (GstScheduler * sched, GstElement * element) { if (GST_ELEMENT_THREADSTATE (element)) - cothread_unlock (GST_ELEMENT_THREADSTATE (element)); + do_cothread_unlock (GST_ELEMENT_THREADSTATE (element)); } static void gst_basic_scheduler_yield (GstScheduler *sched, GstElement *element) { if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) { - cothread_switch (cothread_current_main ()); + do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); } } @@ -1062,7 +1068,7 @@ static gboolean gst_basic_scheduler_interrupt (GstScheduler *sched, GstElement *element) { GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING); - cothread_switch (cothread_current_main ()); + do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); return FALSE; } @@ -1081,7 +1087,7 @@ gst_basic_scheduler_error (GstScheduler *sched, GstElement *element) GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_ERROR; - cothread_switch (cothread_current_main ()); + do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); } } @@ -1182,7 +1188,7 @@ gst_basic_scheduler_pad_select (GstScheduler * sched, GList * padlist) if (pad != NULL) { GstRealPad *peer = GST_RPAD_PEER (pad); - cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (peer))); + do_cothread_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (peer))); pad = GST_ELEMENT (GST_PAD_PARENT (pad))->select_pad; @@ -1256,7 +1262,7 @@ gst_basic_scheduler_iterate (GstScheduler * sched) GST_DEBUG (GST_CAT_DATAFLOW, "set COTHREAD_STOPPING flag on \"%s\"(@%p)", GST_ELEMENT_NAME (entry), entry); if (GST_ELEMENT_THREADSTATE (entry)) { - cothread_switch (GST_ELEMENT_THREADSTATE (entry)); + do_cothread_switch (GST_ELEMENT_THREADSTATE (entry)); /* if something changed, return - go on else */ if (GST_FLAG_IS_SET(bsched, GST_BASIC_SCHEDULER_CHANGE)) return GST_SCHEDULER_STATE_RUNNING; diff --git a/gst/schedulers/gstfastscheduler.c b/gst/schedulers/gstfastscheduler.c index 2f133040ee..2b5aac171d 100644 --- a/gst/schedulers/gstfastscheduler.c +++ b/gst/schedulers/gstfastscheduler.c @@ -22,13 +22,13 @@ /*#define GST_DEBUG_ENABLED */ #include -#include <../cothreads.h> + +#include "cothreads_compat.h" typedef struct _GstSchedulerChain GstSchedulerChain; -#define GST_PAD_THREADSTATE(pad) (cothread_state*) (GST_PAD_CAST (pad)->sched_private) -#define GST_ELEMENT_THREADSTATE(elem) (cothread_state*) (GST_ELEMENT_CAST (elem)->sched_private) -#define GST_BIN_THREADCONTEXT(bin) (cothread_context*) (GST_BIN_CAST (bin)->sched_private) +#define GST_PAD_THREADSTATE(pad) (cothread*) (GST_PAD_CAST (pad)->sched_private) +#define GST_ELEMENT_THREADSTATE(elem) (cothread*) (GST_ELEMENT_CAST (elem)->sched_private) #define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1 #define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING) @@ -85,6 +85,7 @@ struct _GstFastScheduler { GstFastSchedulerState state; + cothread_context *context; }; struct _GstFastSchedulerClass { @@ -136,7 +137,7 @@ gst_fast_scheduler_get_type (void) NULL }; - _gst_fast_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstFastScheduler", &scheduler_info, 0); + _gst_fast_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstFast"COTHREADS_NAME_CAPITAL"Scheduler", &scheduler_info, 0); } return _gst_fast_scheduler_type; } @@ -170,6 +171,8 @@ gst_fast_scheduler_class_init (GstFastSchedulerClass * klass) gstscheduler_class->pad_disconnect = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_disconnect); gstscheduler_class->pad_select = GST_DEBUG_FUNCPTR (gst_fast_scheduler_pad_select); gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_fast_scheduler_iterate); + + do_cothreads_init(NULL); } static void @@ -194,8 +197,8 @@ plugin_init (GModule *module, GstPlugin *plugin) gst_plugin_set_longname (plugin, "A fast scheduler"); - factory = gst_scheduler_factory_new ("fast", - "A fast scheduler, it uses cothreads", + factory = gst_scheduler_factory_new ("fast"COTHREADS_NAME, + "A fast scheduler, it uses "COTHREADS_NAME" cothreads", gst_fast_scheduler_get_type()); if (factory != NULL) { @@ -210,7 +213,7 @@ plugin_init (GModule *module, GstPlugin *plugin) GstPluginDesc plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, - "gstfastscheduler", + "gstfast"COTHREADS_NAME_CAPITAL"scheduler", plugin_init }; @@ -246,7 +249,7 @@ gst_fast_scheduler_chainfunc_proxy (GstPad *pad, GstBuffer *buffer) while (GST_RPAD_BUFPEN (pad) != NULL) { if (GST_ELEMENT_THREADSTATE (element)) { - cothread_switch (GST_ELEMENT_THREADSTATE (element)); + do_cothread_switch (GST_ELEMENT_THREADSTATE (element)); } else { g_assert_not_reached(); @@ -266,7 +269,7 @@ gst_fast_scheduler_getfunc_proxy (GstPad *pad) while (GST_RPAD_BUFPEN (peer) == NULL) { if (GST_ELEMENT_THREADSTATE (element)) { - cothread_switch (GST_ELEMENT_THREADSTATE (element)); + do_cothread_switch (GST_ELEMENT_THREADSTATE (element)); } else { g_assert_not_reached(); @@ -285,24 +288,27 @@ gst_fast_scheduler_cothreaded_element (GstBin * bin, GstElement *element) { cothread_func wrapper_function; GList *pads; - + GstFastScheduler *sched; + GST_DEBUG (GST_CAT_SCHEDULING, "element is using COTHREADS\n"); - g_assert (GST_BIN_THREADCONTEXT (bin) != NULL); + sched = (GstFastScheduler *) GST_ELEMENT_SCHED (bin); + g_assert (GST_IS_FAST_SCHEDULER (sched)); wrapper_function = GST_DEBUG_FUNCPTR (gst_fast_scheduler_loopfunc_wrapper); if (GST_ELEMENT_THREADSTATE (element) == NULL) { - GST_ELEMENT_THREADSTATE (element) = cothread_create (GST_BIN_THREADCONTEXT (bin)); + do_cothread_create (GST_ELEMENT_THREADSTATE (element), sched->context, wrapper_function, 0, (char **) element); if (GST_ELEMENT_THREADSTATE (element) == NULL) { gst_element_error (element, "could not create cothread for \"%s\"", GST_ELEMENT_NAME (element), NULL); return FALSE; - } - GST_DEBUG (GST_CAT_SCHEDULING, "created cothread %p for '%s'\n", + GST_DEBUG (GST_CAT_SCHEDULING, "created cothread %p for '%s' with wrapper function &%s\n", GST_ELEMENT_THREADSTATE (element), - GST_ELEMENT_NAME (element)); - cothread_setfunc (GST_ELEMENT_THREADSTATE (element), wrapper_function, 0, (char **) element); + GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); + } + } else { + do_cothread_reset (GST_ELEMENT_THREADSTATE (element), sched->context, wrapper_function, 0, (char **) element); GST_DEBUG (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s\n", GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); } @@ -478,7 +484,7 @@ gst_fast_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement * } /* we have to check for a threadstate here because a queue doesn't have one */ if (GST_ELEMENT_THREADSTATE (element)) { - cothread_free (GST_ELEMENT_THREADSTATE (element)); + do_cothread_destroy (GST_ELEMENT_THREADSTATE (element)); GST_ELEMENT_THREADSTATE (element) = NULL; } @@ -622,31 +628,29 @@ gst_fast_scheduler_chain_recursive_add (GstSchedulerChain * chain, GstElement * static void gst_fast_scheduler_setup (GstScheduler *sched) { - GstBin *bin = GST_BIN (sched->parent); + GstFastScheduler *fast = GST_FAST_SCHEDULER_CAST (sched); /* first create thread context */ - if (GST_BIN_THREADCONTEXT (bin) == NULL) { + if (fast->context == NULL) { GST_DEBUG (GST_CAT_SCHEDULING, "initializing cothread context\n"); - GST_BIN_THREADCONTEXT (bin) = cothread_context_init (); + fast->context = do_cothread_context_init (); } } static void gst_fast_scheduler_reset (GstScheduler *sched) { - cothread_context *ctx; - GList *elements = GST_FAST_SCHEDULER_CAST (sched)->elements; + GstFastScheduler *fast = GST_FAST_SCHEDULER_CAST (sched); + GList *elements = fast->elements; while (elements) { GST_ELEMENT_THREADSTATE (elements->data) = NULL; elements = g_list_next (elements); } - ctx = GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)); - - cothread_context_free (ctx); + do_cothread_context_destroy (fast->context); - GST_BIN_THREADCONTEXT (GST_SCHEDULER_PARENT (sched)) = NULL; + fast->context = NULL; } static void @@ -785,29 +789,29 @@ static void gst_fast_scheduler_lock_element (GstScheduler * sched, GstElement * element) { if (GST_ELEMENT_THREADSTATE (element)) - cothread_lock (GST_ELEMENT_THREADSTATE (element)); + do_cothread_lock (GST_ELEMENT_THREADSTATE (element)); } static void gst_fast_scheduler_unlock_element (GstScheduler * sched, GstElement * element) { if (GST_ELEMENT_THREADSTATE (element)) - cothread_unlock (GST_ELEMENT_THREADSTATE (element)); + do_cothread_unlock (GST_ELEMENT_THREADSTATE (element)); } static void gst_fast_scheduler_yield (GstScheduler *sched, GstElement *element) { if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) { - cothread_switch (cothread_current_main ()); + do_cothread_switch (do_cothread_get_main (GST_FAST_SCHEDULER_CAST (sched)->context)); } } static gboolean gst_fast_scheduler_interrupt (GstScheduler *sched, GstElement *element) { - if (cothread_current () != cothread_current_main()) { - cothread_switch (cothread_current_main ()); + if (do_cothread_get_current () != do_cothread_get_main (GST_FAST_SCHEDULER_CAST (sched)->context)) { + do_cothread_switch (do_cothread_get_main (GST_FAST_SCHEDULER_CAST (sched)->context)); return FALSE; } GST_FLAG_SET (element, GST_ELEMENT_INTERRUPTED); @@ -958,7 +962,7 @@ gst_fast_scheduler_iterate (GstScheduler * sched) GST_ELEMENT_NAME (entry), entry); if (GST_ELEMENT_THREADSTATE (entry)) { - cothread_switch (GST_ELEMENT_THREADSTATE (entry)); + do_cothread_switch (GST_ELEMENT_THREADSTATE (entry)); } else { GST_DEBUG (GST_CAT_DATAFLOW, "cothread switch not possible, element has no threadstate\n"); diff --git a/gst/schedulers/gststandardscheduler.c b/gst/schedulers/gststandardscheduler.c deleted file mode 100644 index 099c4ce1b0..0000000000 --- a/gst/schedulers/gststandardscheduler.c +++ /dev/null @@ -1,1310 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * gstscheduler.c: Default scheduling code for most cases - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/*#define GST_DEBUG_ENABLED */ -#include -#include - -#include - -typedef struct _GstSchedulerChain GstSchedulerChain; - -#define GST_PAD_THREADSTATE(pad) (cothread*) (GST_PAD_CAST (pad)->sched_private) -#define GST_ELEMENT_THREADSTATE(elem) (cothread*) (GST_ELEMENT_CAST (elem)->sched_private) -#define GST_ELEMENT_STANDARD_SCHED(elem) (GstStandardScheduler*) (GST_ELEMENT_CAST (elem)->sched) -#define GST_PAD_STANDARD_SCHED(pad) (GstStandardScheduler*) (GST_PAD_PARENT (pad)->sched) - -#define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1 -#define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING) - -typedef struct _GstStandardScheduler GstStandardScheduler; -typedef struct _GstStandardSchedulerClass GstStandardSchedulerClass; - -struct _GstSchedulerChain { - GstStandardScheduler *sched; - - GList *disabled; - - GList *elements; - gint num_elements; - - GstElement *entry; - - gint cothreaded_elements; - gboolean schedule; -}; - -#define GST_TYPE_STANDARD_SCHEDULER \ - (gst_standard_scheduler_get_type()) -#define GST_STANDARD_SCHEDULER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STANDARD_SCHEDULER,GstStandardScheduler)) -#define GST_STANDARD_SCHEDULER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STANDARD_SCHEDULER,GstStandardSchedulerClass)) -#define GST_IS_STANDARD_SCHEDULER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STANDARD_SCHEDULER)) -#define GST_IS_STANDARD_SCHEDULER_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STANDARD_SCHEDULER)) - -#define GST_STANDARD_SCHEDULER_CAST(sched) ((GstStandardScheduler *)(sched)) - -typedef enum { - GST_STANDARD_SCHEDULER_STATE_NONE, - GST_STANDARD_SCHEDULER_STATE_STOPPED, - GST_STANDARD_SCHEDULER_STATE_ERROR, - GST_STANDARD_SCHEDULER_STATE_RUNNING, -} GstStandardSchedulerState; - -typedef enum { - /* something important has changed inside the scheduler */ - GST_STANDARD_SCHEDULER_CHANGE = GST_OBJECT_FLAG_LAST, -} GstStandardSchedulerFlags; - -struct _GstStandardScheduler { - GstScheduler parent; - - GList *elements; - gint num_elements; - - GList *chains; - gint num_chains; - - GstStandardSchedulerState state; - - cothread *main; -}; - -struct _GstStandardSchedulerClass { - GstSchedulerClass parent_class; -}; - -static GType _gst_standard_scheduler_type = 0; - -static void gst_standard_scheduler_class_init (GstStandardSchedulerClass * klass); -static void gst_standard_scheduler_init (GstStandardScheduler * scheduler); - -static void gst_standard_scheduler_dispose (GObject *object); - -static void gst_standard_scheduler_setup (GstScheduler *sched); -static void gst_standard_scheduler_reset (GstScheduler *sched); -static void gst_standard_scheduler_add_element (GstScheduler *sched, GstElement *element); -static void gst_standard_scheduler_remove_element (GstScheduler *sched, GstElement *element); -static GstElementStateReturn - gst_standard_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition); -static void gst_standard_scheduler_lock_element (GstScheduler *sched, GstElement *element); -static void gst_standard_scheduler_unlock_element (GstScheduler *sched, GstElement *element); -static void gst_standard_scheduler_yield (GstScheduler *sched, GstElement *element); -static gboolean gst_standard_scheduler_interrupt (GstScheduler *sched, GstElement *element); -static void gst_standard_scheduler_error (GstScheduler *sched, GstElement *element); -static void gst_standard_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); -static void gst_standard_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); -static GstSchedulerState - gst_standard_scheduler_iterate (GstScheduler *sched); - -static void gst_standard_scheduler_show (GstScheduler *sched); - -static GstSchedulerClass *parent_class = NULL; - -static GType -gst_standard_scheduler_get_type (void) -{ - if (!_gst_standard_scheduler_type) { - static const GTypeInfo scheduler_info = { - sizeof (GstStandardSchedulerClass), - NULL, - NULL, - (GClassInitFunc) gst_standard_scheduler_class_init, - NULL, - NULL, - sizeof (GstStandardScheduler), - 0, - (GInstanceInitFunc) gst_standard_scheduler_init, - NULL - }; - - _gst_standard_scheduler_type = g_type_register_static (GST_TYPE_SCHEDULER, "GstStandardScheduler", &scheduler_info, 0); - } - return _gst_standard_scheduler_type; -} - -static void -gst_standard_scheduler_class_init (GstStandardSchedulerClass * klass) -{ - GObjectClass *gobject_class; - GstObjectClass *gstobject_class; - GstSchedulerClass *gstscheduler_class; - - gobject_class = (GObjectClass*)klass; - gstobject_class = (GstObjectClass*)klass; - gstscheduler_class = (GstSchedulerClass*)klass; - - parent_class = g_type_class_ref (GST_TYPE_SCHEDULER); - - gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_standard_scheduler_dispose); - - gstscheduler_class->setup = GST_DEBUG_FUNCPTR (gst_standard_scheduler_setup); - gstscheduler_class->reset = GST_DEBUG_FUNCPTR (gst_standard_scheduler_reset); - gstscheduler_class->add_element = GST_DEBUG_FUNCPTR (gst_standard_scheduler_add_element); - gstscheduler_class->remove_element = GST_DEBUG_FUNCPTR (gst_standard_scheduler_remove_element); - gstscheduler_class->state_transition = GST_DEBUG_FUNCPTR (gst_standard_scheduler_state_transition); - gstscheduler_class->lock_element = GST_DEBUG_FUNCPTR (gst_standard_scheduler_lock_element); - gstscheduler_class->unlock_element = GST_DEBUG_FUNCPTR (gst_standard_scheduler_unlock_element); - gstscheduler_class->yield = GST_DEBUG_FUNCPTR (gst_standard_scheduler_yield); - gstscheduler_class->interrupt = GST_DEBUG_FUNCPTR (gst_standard_scheduler_interrupt); - gstscheduler_class->error = GST_DEBUG_FUNCPTR (gst_standard_scheduler_error); - gstscheduler_class->pad_connect = GST_DEBUG_FUNCPTR (gst_standard_scheduler_pad_connect); - gstscheduler_class->pad_disconnect = GST_DEBUG_FUNCPTR (gst_standard_scheduler_pad_disconnect); - gstscheduler_class->pad_select = NULL; /* FIXME */ - gstscheduler_class->iterate = GST_DEBUG_FUNCPTR (gst_standard_scheduler_iterate); - - gstscheduler_class->show = GST_DEBUG_FUNCPTR (gst_standard_scheduler_show); - - cothreads_init(NULL); -} - -static void -gst_standard_scheduler_init (GstStandardScheduler *scheduler) -{ - scheduler->elements = NULL; - scheduler->num_elements = 0; - scheduler->chains = NULL; - scheduler->num_chains = 0; -} - -static void -gst_standard_scheduler_dispose (GObject *object) -{ - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static gboolean -plugin_init (GModule *module, GstPlugin *plugin) -{ - GstSchedulerFactory *factory; - - gst_plugin_set_longname (plugin, "A standard scheduler"); - - factory = gst_scheduler_factory_new ("standard", - "A standard scheduler, it uses cothreads", - gst_standard_scheduler_get_type()); - - if (factory != NULL) { - gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); - } - else { - g_warning ("could not register scheduler: standard"); - } - return TRUE; -} - -GstPluginDesc plugin_desc = { - GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "gststandardscheduler", - plugin_init -}; - -static cothread* sched_create (GstStandardScheduler *scheduler, GstElement *element, cothread_func func) -{ - cothread *ret = NULL; - - GST_DEBUG (GST_CAT_COTHREADS, "calling cothread_create (%p, %d, %p, %p)", func, 1, element, scheduler->main); - - ret = cothread_create (func, 1, (void**) element, scheduler->main); - - GST_INFO (GST_CAT_COTHREADS, "created new cothread %p", ret); - - return ret; -} - -static void sched_switch (cothread *to) -{ - cothread *from = cothread_self (); - - if (from == to) { - GST_DEBUG (GST_CAT_COTHREAD_SWITCH, "trying to switch to the same cothread (%p), not allowed", - to); - g_assert_not_reached (); - } - GST_INFO (GST_CAT_COTHREAD_SWITCH, "switching from cothread %p to cothread %p", - from, to); - cothread_switch (from, to); - GST_INFO (GST_CAT_COTHREAD_SWITCH, "we're in cothread %p now", from); -} - -static int -gst_standard_scheduler_loopfunc_wrapper (int argc, char *argv[]) -{ - GstElement *element = GST_ELEMENT_CAST (argv); - G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); - - GST_DEBUG_ENTER ("(%d,'%s')", argc, name); - - do { - GST_DEBUG (GST_CAT_DATAFLOW, "calling loopfunc %s for element %s", - GST_DEBUG_FUNCPTR_NAME (element->loopfunc), name); - (element->loopfunc) (element); - GST_DEBUG (GST_CAT_DATAFLOW, "element %s ended loop function", name); - - } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); - GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); - - GST_DEBUG_LEAVE ("(%d,'%s')", argc, name); - return 0; -} - -static int -gst_standard_scheduler_chain_wrapper (int argc, char *argv[]) -{ - GstElement *element = GST_ELEMENT_CAST (argv); - G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); - - GST_DEBUG_ENTER ("(\"%s\")", name); - - GST_DEBUG (GST_CAT_DATAFLOW, "stepping through pads"); - - do { - GList *pads = element->pads; - - while (pads) { - GstPad *pad = GST_PAD (pads->data); - GstRealPad *realpad; - - pads = g_list_next (pads); - if (!GST_IS_REAL_PAD (pad)) - continue; - - realpad = GST_REAL_PAD_CAST (pad); - - if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SINK) { - GstBuffer *buf; - - GST_DEBUG (GST_CAT_DATAFLOW, "pulling data from %s:%s", name, GST_PAD_NAME (pad)); - buf = gst_pad_pull (pad); - if (buf) { - if (GST_IS_EVENT (buf) && !GST_ELEMENT_IS_EVENT_AWARE (element)) { - /*gst_pad_event_default (pad, GST_EVENT (buf)); */ - gst_pad_send_event (pad, GST_EVENT (buf)); - } - else { - GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function of %s:%s", name, - GST_PAD_NAME (pad)); - GST_RPAD_CHAINFUNC (realpad) (pad, buf); - GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function of element %s done", name); - } - } - else { - gst_element_error (element, "NULL buffer detected. Is \"%s:%s\" connected?", - name, GST_PAD_NAME (pad), NULL); - } - } - } - } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); - GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); - - GST_DEBUG_LEAVE ("(%d,'%s')", argc, name); - return 0; -} - -static int -gst_standard_scheduler_src_wrapper (int argc, char *argv[]) -{ - GstElement *element = GST_ELEMENT_CAST (argv); - GList *pads; - GstRealPad *realpad; - GstBuffer *buf = NULL; - G_GNUC_UNUSED const gchar *name = GST_ELEMENT_NAME (element); - - GST_DEBUG_ENTER ("(%d,\"%s\")", argc, name); - - do { - pads = element->pads; - while (pads) { - - if (!GST_IS_REAL_PAD (pads->data)) - continue; - - realpad = GST_REAL_PAD_CAST (pads->data); - - pads = g_list_next (pads); - if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SRC) { - GST_DEBUG (GST_CAT_DATAFLOW, "calling _getfunc for %s:%s", GST_DEBUG_PAD_NAME (realpad)); - if (realpad->regiontype != GST_REGION_VOID) { - g_return_val_if_fail (GST_RPAD_GETREGIONFUNC (realpad) != NULL, 0); -/* if (GST_RPAD_GETREGIONFUNC(realpad) == NULL) */ -/* fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name); */ -/* else */ - buf = - (GST_RPAD_GETREGIONFUNC (realpad)) (GST_PAD_CAST (realpad), realpad->regiontype, - realpad->offset, realpad->len); - realpad->regiontype = GST_REGION_VOID; - } - else { - g_return_val_if_fail (GST_RPAD_GETFUNC (realpad) != NULL, 0); -/* if (GST_RPAD_GETFUNC(realpad) == NULL) */ -/* fprintf(stderr,"error, no getfunc in \"%s\"\n", name); */ -/* else */ - buf = GST_RPAD_GETFUNC (realpad) (GST_PAD_CAST (realpad)); - } - - GST_DEBUG (GST_CAT_DATAFLOW, "calling gst_pad_push on pad %s:%s", - GST_DEBUG_PAD_NAME (realpad)); - gst_pad_push (GST_PAD_CAST (realpad), buf); - } - } - } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); - - GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); - - GST_DEBUG_LEAVE (""); - return 0; -} - -static void -gst_standard_scheduler_chainhandler_proxy (GstPad * pad, GstBuffer * buf) -{ - GstRealPad *peer = GST_RPAD_PEER (pad); - gint loop_count = 100; - - GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); - GST_DEBUG (GST_CAT_DATAFLOW, "putting buffer %p in peer \"%s:%s\"'s pen", buf, - GST_DEBUG_PAD_NAME (peer)); - - /* - * loop until the bufferpen is empty so we can fill it up again - */ - while (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) != NULL && --loop_count) { - GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to empty bufpen %d", - GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad)), loop_count); - sched_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - - /* we may no longer be the same pad, check. */ - if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { - GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!"); - pad = (GstPad *) GST_RPAD_PEER (peer); - } - } - - if (loop_count == 0) { - gst_element_error (GST_PAD_PARENT (pad), - "(internal error) maximum number of switches exceeded"); - return; - } - g_assert (GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) == NULL); - /* now fill the bufferpen and switch so it can be consumed */ - GST_RPAD_BUFPEN (GST_RPAD_PEER (pad)) = buf; - GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p", - GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - sched_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - - GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); -} - -static GstBuffer * -gst_standard_scheduler_gethandler_proxy (GstPad * pad) -{ - GstBuffer *buf; - GstRealPad *peer = GST_RPAD_PEER (pad); - - GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad)); - - /* FIXME this should be bounded */ - /* we will loop switching to the peer until it's filled up the bufferpen */ - while (GST_RPAD_BUFPEN (pad) == NULL) { - GST_DEBUG (GST_CAT_DATAFLOW, "switching to \"%s\": %p to fill bufpen", - GST_ELEMENT_NAME (GST_ELEMENT (GST_PAD_PARENT (pad))), - GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - sched_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - - /* we may no longer be the same pad, check. */ - if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { - GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!"); - pad = (GstPad *) GST_RPAD_PEER (peer); - } - } - GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); - - /* now grab the buffer from the pen, clear the pen, and return the buffer */ - buf = GST_RPAD_BUFPEN (pad); - GST_RPAD_BUFPEN (pad) = NULL; - - return buf; -} - -static GstBuffer * -gst_standard_scheduler_pullregionfunc_proxy (GstPad * pad, GstRegionType type, guint64 offset, guint64 len) -{ - GstBuffer *buf; - GstRealPad *peer = GST_RPAD_PEER (pad); - - GST_DEBUG_ENTER ("%s:%s,%d,%lld,%lld", GST_DEBUG_PAD_NAME (pad), type, offset, len); - - /* put the region info into the pad */ - GST_RPAD_REGIONTYPE (pad) = type; - GST_RPAD_OFFSET (pad) = offset; - GST_RPAD_LEN (pad) = len; - - /* FIXME this should be bounded */ - /* we will loop switching to the peer until it's filled up the bufferpen */ - while (GST_RPAD_BUFPEN (pad) == NULL) { - GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to fill bufpen", - GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - sched_switch (GST_ELEMENT_THREADSTATE (GST_PAD_PARENT (pad))); - - /* we may no longer be the same pad, check. */ - if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { - GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!"); - pad = (GstPad *) GST_RPAD_PEER (peer); - } - } - GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); - - /* now grab the buffer from the pen, clear the pen, and return the buffer */ - buf = GST_RPAD_BUFPEN (pad); - GST_RPAD_BUFPEN (pad) = NULL; - return buf; -} - - -static gboolean -gst_standard_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) -{ - GList *elements; - GstElement *element; - cothread_func wrapper_function; - GList *pads; - GstPad *pad; - - GST_DEBUG (GST_CAT_SCHEDULING, "chain is using COTHREADS"); - - /* walk through all the chain's elements */ - elements = chain->elements; - while (elements) { - gboolean decoupled; - - element = GST_ELEMENT_CAST (elements->data); - elements = g_list_next (elements); - - decoupled = (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED) ? TRUE : FALSE); - - /* start out without a wrapper function, we select it later */ - wrapper_function = NULL; - - /* if the element has a loopfunc... */ - if (element->loopfunc != NULL) { - wrapper_function = GST_DEBUG_FUNCPTR (gst_standard_scheduler_loopfunc_wrapper); - GST_DEBUG (GST_CAT_SCHEDULING, "element '%s' is a loop-based", GST_ELEMENT_NAME (element)); - } - else { - /* otherwise we need to decide what kind of cothread */ - /* if it's not DECOUPLED, we decide based on whether it's a source or not */ - if (!decoupled) { - /* if it doesn't have any sinks, it must be a source (duh) */ - if (element->numsinkpads == 0) { - wrapper_function = GST_DEBUG_FUNCPTR (gst_standard_scheduler_src_wrapper); - GST_DEBUG (GST_CAT_SCHEDULING, "element '%s' is a source, using _src_wrapper", - GST_ELEMENT_NAME (element)); - } - else { - wrapper_function = GST_DEBUG_FUNCPTR (gst_standard_scheduler_chain_wrapper); - GST_DEBUG (GST_CAT_SCHEDULING, "element '%s' is a filter, using _chain_wrapper", - GST_ELEMENT_NAME (element)); - } - } - } - - /* now we have to walk through the pads to set up their state */ - pads = gst_element_get_pad_list (element); - while (pads) { - GstPad *peerpad; - - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - - if (!GST_IS_REAL_PAD (pad)) - continue; - - peerpad = GST_PAD (GST_RPAD_PEER (pad)); - - /* if the element is DECOUPLED or outside the manager, we have to chain */ - if ((wrapper_function == NULL) || - (peerpad && (GST_ELEMENT_CAST (GST_PAD_PARENT (peerpad))->sched != GST_SCHEDULER (chain->sched)))) { - - if (!decoupled && GST_RPAD_PEER (pad) && - !GST_FLAG_IS_SET (GST_PAD_PARENT (peerpad), GST_ELEMENT_DECOUPLED)) { - /* whoa non decoupled with different schedulers */ - gst_element_error (element, "element \"%s\" is not decoupled but has pads in different schedulers", - GST_ELEMENT_NAME (element), NULL); - return FALSE; - } - - /* set the chain proxies */ - if (GST_RPAD_DIRECTION (pad) == GST_PAD_SINK) { - GST_DEBUG (GST_CAT_SCHEDULING, "copying chain function into push proxy for %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_RPAD_CHAINHANDLER (pad) = GST_RPAD_CHAINFUNC (pad); - } - else { - GST_DEBUG (GST_CAT_SCHEDULING, "copying get function into pull proxy for %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_RPAD_GETHANDLER (pad) = GST_RPAD_GETFUNC (pad); - GST_RPAD_PULLREGIONFUNC (pad) = GST_RPAD_GETREGIONFUNC (pad); - } - - } - /* otherwise we really are a cothread */ - else { - if (gst_pad_get_direction (pad) == GST_PAD_SINK) { - GST_DEBUG (GST_CAT_SCHEDULING, "setting cothreaded push proxy for sinkpad %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_RPAD_CHAINHANDLER (pad) = GST_DEBUG_FUNCPTR (gst_standard_scheduler_chainhandler_proxy); - } - else { - GST_DEBUG (GST_CAT_SCHEDULING, "setting cothreaded pull proxy for srcpad %s:%s", - GST_DEBUG_PAD_NAME (pad)); - GST_RPAD_GETHANDLER (pad) = GST_DEBUG_FUNCPTR (gst_standard_scheduler_gethandler_proxy); - GST_RPAD_PULLREGIONFUNC (pad) = GST_DEBUG_FUNCPTR (gst_standard_scheduler_pullregionfunc_proxy); - } - } - } - - /* need to set up the cothread now */ - if (wrapper_function != NULL) { - if (!GST_ELEMENT_THREADSTATE (element)) { - GST_ELEMENT_THREADSTATE (element) = sched_create (chain->sched, element, wrapper_function); - if (GST_ELEMENT_THREADSTATE (element) == NULL) { - gst_element_error (element, "could not create cothread for \"%s\"", - GST_ELEMENT_NAME (element), NULL); - return FALSE; - } - GST_DEBUG (GST_CAT_SCHEDULING, "created cothread %p for '%s'", - GST_ELEMENT_THREADSTATE (element), - GST_ELEMENT_NAME (element)); - } else { - cothread_reset (GST_ELEMENT_THREADSTATE (element), wrapper_function, 1, (void **) element, chain->sched->main); - GST_DEBUG (GST_CAT_SCHEDULING, "set wrapper function for '%s' to &%s", - GST_ELEMENT_NAME (element), GST_DEBUG_FUNCPTR_NAME (wrapper_function)); - } - } - } - - return TRUE; -} - -static GstSchedulerChain * -gst_standard_scheduler_chain_new (GstStandardScheduler * sched) -{ - GstSchedulerChain *chain = g_new (GstSchedulerChain, 1); - - /* initialize the chain with sane values */ - chain->sched = sched; - chain->disabled = NULL; - chain->elements = NULL; - chain->num_elements = 0; - chain->entry = NULL; - chain->cothreaded_elements = 0; - chain->schedule = FALSE; - - /* add the chain to the schedulers' list of chains */ - sched->chains = g_list_prepend (sched->chains, chain); - sched->num_chains++; - - /* notify the scheduler that something changed */ - GST_FLAG_SET(sched, GST_STANDARD_SCHEDULER_CHANGE); - - GST_INFO (GST_CAT_SCHEDULING, "created new chain %p, now are %d chains in sched %p", - chain, sched->num_chains, sched); - - return chain; -} - -static void -gst_standard_scheduler_chain_destroy (GstSchedulerChain * chain) -{ - GstStandardScheduler *sched = chain->sched; - - /* remove the chain from the schedulers' list of chains */ - sched->chains = g_list_remove (sched->chains, chain); - sched->num_chains--; - - /* destroy the chain */ - g_list_free (chain->disabled); /* should be empty... */ - g_list_free (chain->elements); /* ditto */ - - GST_INFO (GST_CAT_SCHEDULING, "destroyed chain %p, now are %d chains in sched %p", chain, - sched->num_chains, sched); - - g_free (chain); - - /* notify the scheduler that something changed */ - GST_FLAG_SET(sched, GST_STANDARD_SCHEDULER_CHANGE); -} - -static void -gst_standard_scheduler_chain_add_element (GstSchedulerChain * chain, GstElement * element) -{ - GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to chain %p", GST_ELEMENT_NAME (element), - chain); - - /* set the sched pointer for the element */ - element->sched = GST_SCHEDULER (chain->sched); - - /* add the element to the list of 'disabled' elements */ - chain->disabled = g_list_prepend (chain->disabled, element); - chain->num_elements++; - - /* notify the scheduler that something changed */ - GST_FLAG_SET(chain->sched, GST_STANDARD_SCHEDULER_CHANGE); -} - -static gboolean -gst_standard_scheduler_chain_enable_element (GstSchedulerChain * chain, GstElement * element) -{ - GST_INFO (GST_CAT_SCHEDULING, "enabling element \"%s\" in chain %p", GST_ELEMENT_NAME (element), - chain); - - /* remove from disabled list */ - chain->disabled = g_list_remove (chain->disabled, element); - - /* add to elements list */ - chain->elements = g_list_prepend (chain->elements, element); - - /* notify the scheduler that something changed */ - GST_FLAG_SET(chain->sched, GST_STANDARD_SCHEDULER_CHANGE); - - /* reschedule the chain */ - return gst_standard_scheduler_cothreaded_chain (GST_BIN (GST_SCHEDULER (chain->sched)->parent), chain); -} - -static void -gst_standard_scheduler_chain_disable_element (GstSchedulerChain * chain, GstElement * element) -{ - GST_INFO (GST_CAT_SCHEDULING, "disabling element \"%s\" in chain %p", GST_ELEMENT_NAME (element), - chain); - - /* remove from elements list */ - chain->elements = g_list_remove (chain->elements, element); - - /* add to disabled list */ - chain->disabled = g_list_prepend (chain->disabled, element); - - /* notify the scheduler that something changed */ - GST_FLAG_SET(chain->sched, GST_STANDARD_SCHEDULER_CHANGE); - - /* reschedule the chain */ -/* FIXME this should be done only if manager state != NULL */ -/* gst_standard_scheduler_cothreaded_chain(GST_BIN(chain->sched->parent),chain); */ -} - -static void -gst_standard_scheduler_chain_remove_element (GstSchedulerChain * chain, GstElement * element) -{ - GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from chain %p", GST_ELEMENT_NAME (element), - chain); - - /* if it's active, deactivate it */ - if (g_list_find (chain->elements, element)) { - gst_standard_scheduler_chain_disable_element (chain, element); - } - /* we have to check for a threadstate here because a queue doesn't have one */ - if (GST_ELEMENT_THREADSTATE (element)) { - cothread_destroy (GST_ELEMENT_THREADSTATE (element)); - GST_ELEMENT_THREADSTATE (element) = NULL; - } - - /* remove the element from the list of elements */ - chain->disabled = g_list_remove (chain->disabled, element); - chain->num_elements--; - - /* notify the scheduler that something changed */ - GST_FLAG_SET(chain->sched, GST_STANDARD_SCHEDULER_CHANGE); - - /* if there are no more elements in the chain, destroy the chain */ - if (chain->num_elements == 0) - gst_standard_scheduler_chain_destroy (chain); -} - -static void -gst_standard_scheduler_chain_elements (GstStandardScheduler * sched, GstElement * element1, GstElement * element2) -{ - GList *chains; - GstSchedulerChain *chain; - GstSchedulerChain *chain1 = NULL, *chain2 = NULL; - GstElement *element; - - /* first find the chains that hold the two */ - chains = sched->chains; - while (chains) { - chain = (GstSchedulerChain *) (chains->data); - chains = g_list_next (chains); - - if (g_list_find (chain->disabled, element1)) - chain1 = chain; - else if (g_list_find (chain->elements, element1)) - chain1 = chain; - - if (g_list_find (chain->disabled, element2)) - chain2 = chain; - else if (g_list_find (chain->elements, element2)) - chain2 = chain; - } - - /* first check to see if they're in the same chain, we're done if that's the case */ - if ((chain1 != NULL) && (chain1 == chain2)) { - GST_INFO (GST_CAT_SCHEDULING, "elements are already in the same chain"); - return; - } - - /* now, if neither element has a chain, create one */ - if ((chain1 == NULL) && (chain2 == NULL)) { - GST_INFO (GST_CAT_SCHEDULING, "creating new chain to hold two new elements"); - chain = gst_standard_scheduler_chain_new (sched); - gst_standard_scheduler_chain_add_element (chain, element1); - gst_standard_scheduler_chain_add_element (chain, element2); - /* FIXME chain changed here */ -/* gst_standard_scheduler_cothreaded_chain(chain->sched->parent,chain); */ - - /* otherwise if both have chains already, join them */ - } - else if ((chain1 != NULL) && (chain2 != NULL)) { - GST_INFO (GST_CAT_SCHEDULING, "merging chain %p into chain %p", chain2, chain1); - /* take the contents of chain2 and merge them into chain1 */ - chain1->disabled = g_list_concat (chain1->disabled, g_list_copy (chain2->disabled)); - chain1->elements = g_list_concat (chain1->elements, g_list_copy (chain2->elements)); - chain1->num_elements += chain2->num_elements; - /* FIXME chain changed here */ -/* gst_standard_scheduler_cothreaded_chain(chain->sched->parent,chain); */ - - gst_standard_scheduler_chain_destroy (chain2); - - /* otherwise one has a chain already, the other doesn't */ - } - else { - /* pick out which one has the chain, and which doesn't */ - if (chain1 != NULL) - chain = chain1, element = element2; - else - chain = chain2, element = element1; - - GST_INFO (GST_CAT_SCHEDULING, "adding element to existing chain"); - gst_standard_scheduler_chain_add_element (chain, element); - /* FIXME chain changed here */ -/* gst_standard_scheduler_cothreaded_chain(chain->sched->parent,chain); */ - } - -} - - -/* find the chain within the scheduler that holds the element, if any */ -static GstSchedulerChain * -gst_standard_scheduler_find_chain (GstStandardScheduler * sched, GstElement * element) -{ - GList *chains; - GstSchedulerChain *chain; - - GST_INFO (GST_CAT_SCHEDULING, "searching for element \"%s\" in chains", - GST_ELEMENT_NAME (element)); - - chains = sched->chains; - while (chains) { - chain = (GstSchedulerChain *) (chains->data); - chains = g_list_next (chains); - - if (g_list_find (chain->elements, element)) - return chain; - if (g_list_find (chain->disabled, element)) - return chain; - } - - return NULL; -} - -static void -gst_standard_scheduler_chain_recursive_add (GstSchedulerChain * chain, GstElement * element) -{ - GList *pads; - GstPad *pad; - GstElement *peerelement; - - /* add the element to the chain */ - gst_standard_scheduler_chain_add_element (chain, element); - - GST_DEBUG (GST_CAT_SCHEDULING, "recursing on element \"%s\"", GST_ELEMENT_NAME (element)); - /* now go through all the pads and see which peers can be added */ - pads = element->pads; - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - - GST_DEBUG (GST_CAT_SCHEDULING, "have pad %s:%s, checking for valid peer", - GST_DEBUG_PAD_NAME (pad)); - /* if the peer exists and could be in the same chain */ - if (GST_PAD_PEER (pad)) { - GST_DEBUG (GST_CAT_SCHEDULING, "has peer %s:%s", GST_DEBUG_PAD_NAME (GST_PAD_PEER (pad))); - peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad)); - if (GST_ELEMENT_SCHED (GST_PAD_PARENT (pad)) == GST_ELEMENT_SCHED (peerelement)) { - GST_DEBUG (GST_CAT_SCHEDULING, "peer \"%s\" is valid for same chain", - GST_ELEMENT_NAME (peerelement)); - /* if it's not already in a chain, add it to this one */ - if (gst_standard_scheduler_find_chain (chain->sched, peerelement) == NULL) { - gst_standard_scheduler_chain_recursive_add (chain, peerelement); - } - } - } - } -} - -/* - * Entry points for this scheduler. - */ -static void -gst_standard_scheduler_setup (GstScheduler *sched) -{ - GstStandardScheduler *scheduler = GST_STANDARD_SCHEDULER (sched); - - /* initialize the main cothread here. this way we know that we're within the - gthread that the sched will be running */ - if (!scheduler->main) - scheduler->main = cothread_create (NULL, 0, NULL, NULL); - - g_return_if_fail (scheduler->main != NULL); -} - -static void -gst_standard_scheduler_reset (GstScheduler *sched) -{ - GList *elements = GST_STANDARD_SCHEDULER_CAST (sched)->elements; - - while (elements) { - GST_ELEMENT_THREADSTATE (elements->data) = NULL; - elements = g_list_next (elements); - } -} - -static void -gst_standard_scheduler_add_element (GstScheduler * sched, GstElement * element) -{ - GList *pads; - GstPad *pad; - GstElement *peerelement; - GstSchedulerChain *chain; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - /* if it's already in this scheduler, don't bother doing anything */ - if (GST_ELEMENT_SCHED (element) == sched) - return; - - GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to scheduler", GST_ELEMENT_NAME (element)); - - /* if the element already has a scheduler something went wrong */ - if (GST_ELEMENT_SCHED (element)) { - GST_ERROR (element, "grave error"); - return; - } - - /* set the sched pointer in the element itself */ - GST_ELEMENT_SCHED (element) = sched; - - /* only deal with elements after this point, not bins */ - /* exception is made for Bin's that are schedulable, like the autoplugger */ - if (GST_IS_BIN (element) && !GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) - return; - - /* first add it to the list of elements that are to be scheduled */ - bsched->elements = g_list_prepend (bsched->elements, element); - bsched->num_elements++; - - /* create a chain to hold it, and add */ - chain = gst_standard_scheduler_chain_new (bsched); - gst_standard_scheduler_chain_add_element (chain, element); - - /* set the sched pointer in all the pads */ - pads = element->pads; - while (pads) { - pad = GST_PAD (pads->data); - pads = g_list_next (pads); - - /* we only operate on real pads */ - if (!GST_IS_REAL_PAD (pad)) - continue; - - /* set the pad's sched pointer */ - gst_pad_set_sched (pad, sched); - - /* if the peer element exists and is a candidate */ - if (GST_PAD_PEER (pad)) { - peerelement = GST_PAD_PARENT (GST_PAD_PEER (pad)); - if (GST_ELEMENT_SCHED (element) == GST_ELEMENT_SCHED (peerelement)) { - GST_INFO (GST_CAT_SCHEDULING, "peer is in same scheduler, chaining together"); - /* make sure that the two elements are in the same chain */ - gst_standard_scheduler_chain_elements (bsched, element, peerelement); - } - } - } -} - -static void -gst_standard_scheduler_remove_element (GstScheduler * sched, GstElement * element) -{ - GstSchedulerChain *chain; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - if (g_list_find (bsched->elements, element)) { - GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from scheduler", - GST_ELEMENT_NAME (element)); - - /* find what chain the element is in */ - chain = gst_standard_scheduler_find_chain (bsched, element); - - /* remove it from its chain */ - gst_standard_scheduler_chain_remove_element (chain, element); - - /* remove it from the list of elements */ - bsched->elements = g_list_remove (bsched->elements, element); - bsched->num_elements--; - } - - /* unset the scheduler pointer in the element */ - GST_ELEMENT_SCHED (element) = NULL; -} - -static GstElementStateReturn -gst_standard_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition) -{ - GstSchedulerChain *chain; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - /* check if our parent changed state */ - if (GST_SCHEDULER_PARENT (sched) == element) { - GST_INFO (GST_CAT_SCHEDULING, "parent \"%s\" changed state", GST_ELEMENT_NAME (element)); - if (transition == GST_STATE_PLAYING_TO_PAUSED) { - GST_INFO (GST_CAT_SCHEDULING, "setting scheduler state to stopped"); - GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_STOPPED; - } - else if (transition == GST_STATE_PAUSED_TO_PLAYING) { - GST_INFO (GST_CAT_SCHEDULING, "setting scheduler state to running"); - GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_RUNNING; - } - else { - GST_INFO (GST_CAT_SCHEDULING, "no interesting state change, doing nothing"); - } - } - else if (transition == GST_STATE_PLAYING_TO_PAUSED || - transition == GST_STATE_PAUSED_TO_PLAYING) { - /* find the chain the element is in */ - chain = gst_standard_scheduler_find_chain (bsched, element); - - /* remove it from the chain */ - if (chain) { - if (transition == GST_STATE_PLAYING_TO_PAUSED) { - gst_standard_scheduler_chain_disable_element (chain, element); - } - else if (transition == GST_STATE_PAUSED_TO_PLAYING) { - if (!gst_standard_scheduler_chain_enable_element (chain, element)) { - GST_INFO (GST_CAT_SCHEDULING, "could not enable element \"%s\"", GST_ELEMENT_NAME (element)); - return GST_STATE_FAILURE; - } - } - } - else { - GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" not found in any chain, no state change", GST_ELEMENT_NAME (element)); - } - } - - return GST_STATE_SUCCESS; -} - -static void -gst_standard_scheduler_lock_element (GstScheduler * sched, GstElement * element) -{ -/* if (GST_ELEMENT_THREADSTATE (element)) */ -/* cothread_lock (GST_ELEMENT_THREADSTATE (element)); */ -} - -static void -gst_standard_scheduler_unlock_element (GstScheduler * sched, GstElement * element) -{ -/* if (GST_ELEMENT_THREADSTATE (element)) */ -/* cothread_unlock (GST_ELEMENT_THREADSTATE (element)); */ -} - -static void -gst_standard_scheduler_yield (GstScheduler *sched, GstElement *element) -{ - if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) { - sched_switch (((GstStandardScheduler*) sched)->main); - } -} - -static gboolean -gst_standard_scheduler_interrupt (GstScheduler *sched, GstElement *element) -{ - GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING); - sched_switch (((GstStandardScheduler*) sched)->main); - - return FALSE; -} - -static void -gst_standard_scheduler_error (GstScheduler *sched, GstElement *element) -{ - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - if (GST_ELEMENT_THREADSTATE (element)) { - GstSchedulerChain *chain; - - chain = gst_standard_scheduler_find_chain (bsched, element); - if (chain) - gst_standard_scheduler_chain_disable_element (chain, element); - - GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_ERROR; - - sched_switch (((GstStandardScheduler*) sched)->main); - } -} - -static void -gst_standard_scheduler_pad_connect (GstScheduler * sched, GstPad *srcpad, GstPad *sinkpad) -{ - GstElement *srcelement, *sinkelement; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - srcelement = GST_PAD_PARENT (srcpad); - g_return_if_fail (srcelement != NULL); - sinkelement = GST_PAD_PARENT (sinkpad); - g_return_if_fail (sinkelement != NULL); - - GST_INFO (GST_CAT_SCHEDULING, "have pad connected callback on %s:%s to %s:%s", - GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); - GST_DEBUG (GST_CAT_SCHEDULING, "srcpad sched is %p, sinkpad sched is %p", - GST_ELEMENT_SCHED (srcelement), GST_ELEMENT_SCHED (sinkelement)); - - if (GST_ELEMENT_SCHED (srcelement) == GST_ELEMENT_SCHED (sinkelement)) { - GST_INFO (GST_CAT_SCHEDULING, "peer %s:%s is in same scheduler, chaining together", - GST_DEBUG_PAD_NAME (sinkpad)); - gst_standard_scheduler_chain_elements (bsched, srcelement, sinkelement); - } -} - -static void -gst_standard_scheduler_pad_disconnect (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad) -{ - GstElement *element1, *element2; - GstSchedulerChain *chain1, *chain2; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - GST_INFO (GST_CAT_SCHEDULING, "disconnecting pads %s:%s and %s:%s", - GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); - - /* we need to have the parent elements of each pad */ - element1 = GST_ELEMENT_CAST (GST_PAD_PARENT (srcpad)); - element2 = GST_ELEMENT_CAST (GST_PAD_PARENT (sinkpad)); - - /* first task is to remove the old chain they belonged to. - * this can be accomplished by taking either of the elements, - * since they are guaranteed to be in the same chain - * FIXME is it potentially better to make an attempt at splitting cleaner?? - */ - chain1 = gst_standard_scheduler_find_chain (bsched, element1); - chain2 = gst_standard_scheduler_find_chain (bsched, element2); - - if (chain1 != chain2) { - /* elements not in the same chain don't need to be separated */ - GST_INFO (GST_CAT_SCHEDULING, "elements not in the same chain"); - return; - } - - if (chain1) { - GST_INFO (GST_CAT_SCHEDULING, "destroying chain"); - gst_standard_scheduler_chain_destroy (chain1); - - /* now create a new chain to hold element1 and build it from scratch */ - chain1 = gst_standard_scheduler_chain_new (bsched); - gst_standard_scheduler_chain_recursive_add (chain1, element1); - } - - /* check the other element to see if it landed in the newly created chain */ - if (gst_standard_scheduler_find_chain (bsched, element2) == NULL) { - /* if not in chain, create chain and build from scratch */ - chain2 = gst_standard_scheduler_chain_new (bsched); - gst_standard_scheduler_chain_recursive_add (chain2, element2); - } -} - -static GstSchedulerState -gst_standard_scheduler_iterate (GstScheduler * sched) -{ - GstBin *bin = GST_BIN (sched->parent); - GList *chains; - GstSchedulerChain *chain; - GstElement *entry; - GList *elements; - gint scheduled = 0; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - GST_DEBUG_ENTER ("(\"%s\")", GST_ELEMENT_NAME (bin)); - - /* clear the changes flag */ - GST_FLAG_UNSET(bsched, GST_STANDARD_SCHEDULER_CHANGE); - - /* step through all the chains */ - chains = bsched->chains; - - if (chains == NULL) - return GST_SCHEDULER_STATE_STOPPED; - - while (chains) { - chain = (GstSchedulerChain *) (chains->data); - chains = g_list_next (chains); - - /* all we really have to do is switch to the first child */ - /* FIXME this should be lots more intelligent about where to start */ - GST_DEBUG (GST_CAT_DATAFLOW, "starting iteration via cothreads"); - - if (chain->elements) { - entry = NULL; /*MattH ADDED?*/ - GST_DEBUG (GST_CAT_SCHEDULING, "there are %d elements in this chain", chain->num_elements); - elements = chain->elements; - while (elements) { - entry = GST_ELEMENT_CAST (elements->data); - elements = g_list_next (elements); - if (GST_FLAG_IS_SET (entry, GST_ELEMENT_DECOUPLED)) { - GST_DEBUG (GST_CAT_SCHEDULING, "entry \"%s\" is DECOUPLED, skipping", - GST_ELEMENT_NAME (entry)); - entry = NULL; - } - else if (GST_FLAG_IS_SET (entry, GST_ELEMENT_INFINITE_LOOP)) { - GST_DEBUG (GST_CAT_SCHEDULING, "entry \"%s\" is not valid, skipping", - GST_ELEMENT_NAME (entry)); - entry = NULL; - } - else - break; - } - if (entry) { - GstSchedulerState state; - - GST_FLAG_SET (entry, GST_ELEMENT_COTHREAD_STOPPING); - - GST_DEBUG (GST_CAT_DATAFLOW, "set COTHREAD_STOPPING flag on \"%s\"(@%p)", - GST_ELEMENT_NAME (entry), entry); - if (GST_ELEMENT_THREADSTATE (entry)) { - sched_switch (GST_ELEMENT_THREADSTATE (entry)); - /* if something changed, return - go on else */ - if (GST_FLAG_IS_SET(bsched, GST_STANDARD_SCHEDULER_CHANGE)) - return GST_SCHEDULER_STATE_RUNNING; - } - else { - GST_DEBUG (GST_CAT_DATAFLOW, "cothread switch not possible, element has no threadstate"); - return GST_SCHEDULER_STATE_ERROR; - } - - state = GST_SCHEDULER_STATE (sched); - - /* following is a check to see if the chain was interrupted due to a - * top-half state_change(). (i.e., if there's a pending state.) - * - * if it was, return to gstthread.c::gst_thread_main_loop() to - * execute the state change. - */ - GST_DEBUG (GST_CAT_DATAFLOW, "cothread switch ended or interrupted"); - - if (state != GST_SCHEDULER_STATE_RUNNING) { - GST_INFO (GST_CAT_DATAFLOW, "scheduler is not running, in state %d", state); - return state; - } - - scheduled++; - } - else { - GST_INFO (GST_CAT_DATAFLOW, "no entry in this chain, trying the next one"); - } - } - else { - GST_INFO (GST_CAT_DATAFLOW, "no enabled elements in this chain, trying the next one"); - } - } - - GST_DEBUG (GST_CAT_DATAFLOW, "leaving (%s)", GST_ELEMENT_NAME (bin)); - if (scheduled == 0) { - GST_INFO (GST_CAT_DATAFLOW, "nothing was scheduled, return STOPPED"); - return GST_SCHEDULER_STATE_STOPPED; - } - else { - GST_INFO (GST_CAT_DATAFLOW, "scheduler still running, return RUNNING"); - return GST_SCHEDULER_STATE_RUNNING; - } -} - - -static void -gst_standard_scheduler_show (GstScheduler * sched) -{ - GList *chains, *elements; - GstElement *element; - GstSchedulerChain *chain; - GstStandardScheduler *bsched = GST_STANDARD_SCHEDULER (sched); - - if (sched == NULL) { - g_print ("scheduler doesn't exist for this element\n"); - return; - } - - g_return_if_fail (GST_IS_SCHEDULER (sched)); - - g_print ("SCHEDULER DUMP FOR MANAGING BIN \"%s\"\n", GST_ELEMENT_NAME (sched->parent)); - - g_print ("scheduler has %d elements in it: ", bsched->num_elements); - elements = bsched->elements; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - g_print ("%s, ", GST_ELEMENT_NAME (element)); - } - g_print ("\n"); - - g_print ("scheduler has %d chains in it\n", bsched->num_chains); - chains = bsched->chains; - while (chains) { - chain = (GstSchedulerChain *) (chains->data); - chains = g_list_next (chains); - - g_print ("%p: ", chain); - - elements = chain->disabled; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - g_print ("!%s, ", GST_ELEMENT_NAME (element)); - } - - elements = chain->elements; - while (elements) { - element = GST_ELEMENT (elements->data); - elements = g_list_next (elements); - - g_print ("%s, ", GST_ELEMENT_NAME (element)); - } - g_print ("\n"); - } -}