From 0694a337a112537e06564c5dd280e6a152f03802 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sun, 2 Jun 2002 16:20:09 +0000 Subject: [PATCH] Properly fix locking in the scheduler Original commit message from CVS: Properly fix locking in the scheduler --- gst/schedulers/gstbasicscheduler.c | 66 +++++++++++++++++------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c index a201365050..79faea4688 100644 --- a/gst/schedulers/gstbasicscheduler.c +++ b/gst/schedulers/gstbasicscheduler.c @@ -125,6 +125,10 @@ static void gst_basic_scheduler_show (GstScheduler *sched); static GstSchedulerClass *parent_class = NULL; +/* for threaded bins, these pre- and post-run functions lock and unlock the + * elements. we have to avoid deadlocks, so we make these convenience macros + * that will avoid using do_cothread_switch from within the scheduler. */ + #define do_element_switch(element) G_STMT_START{ \ GstElement *from = SCHED (element)->current; \ if (from->post_run_func) \ @@ -135,6 +139,23 @@ static GstSchedulerClass *parent_class = NULL; do_cothread_switch (GST_ELEMENT_THREADSTATE (element)); \ }G_STMT_END +#define do_switch_to_main(sched) G_STMT_START{ \ + GstElement *current = ((GstBasicScheduler*)sched)->current; \ + if (current->post_run_func) \ + current->post_run_func (current); \ + SCHED (current)->current = NULL; \ + do_cothread_switch \ + (do_cothread_get_main \ + (((GstBasicScheduler*)sched)->context)); \ +}G_STMT_END + +#define do_switch_from_main(entry) G_STMT_START{ \ + if (entry->pre_run_func) \ + entry->pre_run_func (entry); \ + SCHED (entry)->current = entry; \ + do_cothread_switch (GST_ELEMENT_THREADSTATE (entry)); \ +}G_STMT_END + static GType gst_basic_scheduler_get_type (void) { @@ -301,9 +322,11 @@ gst_basic_scheduler_chain_wrapper (int argc, char *argv[]) } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); - /* this will return to cothread 0, so we need to unlock the current element */ - if (element->post_run_func) - element->post_run_func (element); + /* due to oddities in the cothreads code, when this function returns it will + * switch to the main cothread. thus, we need to unlock the current element. */ + if (SCHED (element)->current->post_run_func) + SCHED (element)->current->post_run_func (SCHED (element)->current); + SCHED (element)->current = NULL; GST_DEBUG_LEAVE ("(%d,'%s')", argc, name); gst_object_unref (GST_OBJECT (element)); @@ -346,6 +369,12 @@ gst_basic_scheduler_src_wrapper (int argc, char *argv[]) GST_FLAG_UNSET (element, GST_ELEMENT_COTHREAD_STOPPING); + /* due to oddities in the cothreads code, when this function returns it will + * switch to the main cothread. thus, we need to unlock the current element. */ + if (SCHED (element)->current->post_run_func) + SCHED (element)->current->post_run_func (SCHED (element)->current); + SCHED (element)->current = NULL; + GST_DEBUG_LEAVE (""); return 0; } @@ -1050,11 +1079,8 @@ static void gst_basic_scheduler_yield (GstScheduler *sched, GstElement *element) { if (GST_ELEMENT_IS_COTHREAD_STOPPING (element)) { - if (element->post_run_func) - element->post_run_func (element); - - SCHED (element)->current = NULL; - do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); + + do_switch_to_main (sched); /* no need to do a pre_run, the cothread is stopping */ } @@ -1063,15 +1089,9 @@ gst_basic_scheduler_yield (GstScheduler *sched, GstElement *element) static gboolean gst_basic_scheduler_interrupt (GstScheduler *sched, GstElement *element) { - GstElement *current = SCHED (element)->current; - GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING); - if (current->post_run_func) - current->post_run_func (current); - - SCHED (element)->current = NULL; - do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); + do_switch_to_main (sched); return FALSE; } @@ -1090,11 +1110,7 @@ gst_basic_scheduler_error (GstScheduler *sched, GstElement *element) GST_SCHEDULER_STATE (sched) = GST_SCHEDULER_STATE_ERROR; - if (element->post_run_func) - element->post_run_func (element); - - SCHED (element)->current = NULL; - do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); + do_switch_to_main (sched); } } @@ -1269,17 +1285,9 @@ 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)) { - if (entry->pre_run_func) - entry->pre_run_func (entry); - bsched->current = entry; + do_switch_from_main (entry); - do_cothread_switch (GST_ELEMENT_THREADSTATE (entry)); - - if (bsched->current && bsched->current->post_run_func) { - bsched->current->post_run_func (bsched->current); - } - state = GST_SCHEDULER_STATE (sched); /* if something changed, return - go on else */ if (GST_FLAG_IS_SET(bsched, GST_BASIC_SCHEDULER_CHANGE) &&