From: Wim Taymans Date: Thu, 27 Feb 2003 18:21:34 +0000 (+0000) Subject: Added refcounting to the optimal scheduler to guard against modifications during... X-Git-Tag: OSLOSUMMIT1-200303051~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=91d33d766a4fbfcc2b86f45e2e6137d4b3063db9;p=platform%2Fupstream%2Fgstreamer.git Added refcounting to the optimal scheduler to guard against modifications during iterations Original commit message from CVS: Added refcounting to the optimal scheduler to guard against modifications during iterations --- diff --git a/gst/schedulers/gstoptimalscheduler.c b/gst/schedulers/gstoptimalscheduler.c index 729e206..1d08b08 100644 --- a/gst/schedulers/gstoptimalscheduler.c +++ b/gst/schedulers/gstoptimalscheduler.c @@ -101,6 +101,8 @@ typedef enum { typedef struct _GstOptSchedulerChain GstOptSchedulerChain; struct _GstOptSchedulerChain { + gint refcount; + GstOptScheduler *sched; GstOptSchedulerChainFlags flags; @@ -144,6 +146,8 @@ struct _GstOptSchedulerGroup { GstOptSchedulerGroupFlags flags; /* flags for this group */ GstOptSchedulerGroupType type; /* flags for this group */ + gint refcount; + GSList *elements; /* elements of this group */ gint num_elements; gint num_enabled; @@ -160,6 +164,11 @@ struct _GstOptSchedulerGroup { char **argv; }; +/* some group operations */ +static GstOptSchedulerGroup* ref_group (GstOptSchedulerGroup *group); +static GstOptSchedulerGroup* unref_group (GstOptSchedulerGroup *group); +static void destroy_group (GstOptSchedulerGroup *group); + /* * Scheduler private data for an element */ @@ -336,57 +345,76 @@ GstPluginDesc plugin_desc = { static void -delete_chain (GstOptSchedulerChain *chain) +destroy_chain (GstOptSchedulerChain *chain) { - GSList *groups; GstOptScheduler *osched; - GST_INFO (GST_CAT_SCHEDULING, "delete chain %p", chain); + GST_INFO (GST_CAT_SCHEDULING, "destroy chain %p", chain); - osched = chain->sched; + g_assert (chain->num_groups == 0); + g_assert (chain->groups == NULL); + osched = chain->sched; osched->chains = g_slist_remove (osched->chains, chain); - groups = chain->groups; - while (groups) { - GstOptSchedulerGroup *group = (GstOptSchedulerGroup *) groups->data; + gst_object_unref (GST_OBJECT (osched)); - /* clear all group's chain pointers, so they can never reference us again */ - if (group->chain == chain) - group->chain = NULL; - - groups = g_slist_next (groups); - } - - g_slist_free (chain->groups); g_free (chain); } static GstOptSchedulerChain* -add_to_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group) +create_chain (GstOptScheduler *osched) { - GST_INFO (GST_CAT_SCHEDULING, "adding group %p to chain %p", group, chain); + GstOptSchedulerChain *chain; - g_assert (group->chain == NULL); + chain = g_new0 (GstOptSchedulerChain, 1); + chain->sched = osched; + chain->refcount = 1; - chain->groups = g_slist_prepend (chain->groups, group); - group->chain = chain; - chain->num_groups++; + gst_object_ref (GST_OBJECT (osched)); + osched->chains = g_slist_prepend (osched->chains, chain); + + GST_INFO (GST_CAT_SCHEDULING, "new chain %p", chain); return chain; } static GstOptSchedulerChain* -create_chain (GstOptScheduler *osched) +ref_chain (GstOptSchedulerChain *chain) { - GstOptSchedulerChain *chain; + GST_INFO (GST_CAT_SCHEDULING, "ref chain %p %d->%d", chain, + chain->refcount, chain->refcount+1); + chain->refcount++; - chain = g_new0 (GstOptSchedulerChain, 1); - chain->sched = osched; + return chain; +} - osched->chains = g_slist_prepend (osched->chains, chain); +static GstOptSchedulerChain* +unref_chain (GstOptSchedulerChain *chain) +{ + GST_INFO (GST_CAT_SCHEDULING, "unref chain %p %d->%d", chain, + chain->refcount, chain->refcount-1); - GST_INFO (GST_CAT_SCHEDULING, "new chain %p", chain); + if (--chain->refcount == 0) { + destroy_chain (chain); + chain = NULL; + } + + return chain; +} + +static GstOptSchedulerChain* +add_to_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group) +{ + GST_INFO (GST_CAT_SCHEDULING, "adding group %p to chain %p", group, chain); + + g_assert (group->chain == NULL); + + group = ref_group (group); + + group->chain = ref_chain (chain); + chain->groups = g_slist_prepend (chain->groups, group); + chain->num_groups++; return chain; } @@ -402,18 +430,15 @@ remove_from_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group) g_assert (group); g_assert (group->chain == chain); + group->chain = NULL; chain->groups = g_slist_remove (chain->groups, group); chain->num_groups--; + unref_group (group); - group->chain = NULL; - - if (chain->num_groups == 0) { - GST_INFO (GST_CAT_SCHEDULING, "chain %p is empty, removing", chain); - delete_chain (chain); - - return NULL; - } + if (chain->num_groups == 0) + chain = unref_chain (chain); + chain = unref_chain (chain); return chain; } @@ -429,15 +454,23 @@ merge_chains (GstOptSchedulerChain *chain1, GstOptSchedulerChain *chain2) if (chain1 == chain2 || chain2 == NULL) return chain1; + ref_chain (chain2); walk = chain2->groups; while (walk) { GstOptSchedulerGroup *group = (GstOptSchedulerGroup *) walk->data; walk = g_slist_next (walk); group->chain = NULL; - add_to_chain (chain1, group); + chain2->num_groups--; + chain2 = unref_chain (chain2); + + group->chain = ref_chain (chain1); + chain1->groups = g_slist_prepend (chain1->groups, group); + chain1->num_groups++; } - delete_chain (chain2); + chain2 = unref_chain (chain2); + + g_assert (chain2 == NULL); return chain1; } @@ -483,6 +516,31 @@ chain_group_set_enabled (GstOptSchedulerChain *chain, GstOptSchedulerGroup *grou } static GstOptSchedulerGroup* +ref_group (GstOptSchedulerGroup *group) +{ + GST_INFO (GST_CAT_SCHEDULING, "ref group %p %d->%d", group, + group->refcount, group->refcount+1); + + group->refcount++; + + return group; +} + +static GstOptSchedulerGroup* +unref_group (GstOptSchedulerGroup *group) +{ + GST_INFO (GST_CAT_SCHEDULING, "unref group %p %d->%d", group, + group->refcount, group->refcount-1); + + if (--group->refcount == 1) { + destroy_group (group); + group = NULL; + } + + return group; +} + +static GstOptSchedulerGroup* add_to_group (GstOptSchedulerGroup *group, GstElement *element) { g_assert (group != NULL); @@ -491,17 +549,19 @@ add_to_group (GstOptSchedulerGroup *group, GstElement *element) GST_INFO (GST_CAT_SCHEDULING, "adding element \"%s\" to group %p", GST_ELEMENT_NAME (element), group); if (GST_ELEMENT_IS_DECOUPLED (element)) { - GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" is decoupled, not adding to group %p", GST_ELEMENT_NAME (element), group); + GST_INFO (GST_CAT_SCHEDULING, "element \"%s\" is decoupled, not adding to group %p", + GST_ELEMENT_NAME (element), group); return group; } g_assert (GST_ELEMENT_SCHED_GROUP (element) == NULL); + GST_ELEMENT_SCHED_GROUP (element) = ref_group (group); + + gst_object_ref (GST_OBJECT (element)); group->elements = g_slist_prepend (group->elements, element); group->num_elements++; - GST_ELEMENT_SCHED_GROUP (element) = group; - return group; } @@ -512,6 +572,7 @@ create_group (GstOptSchedulerChain *chain, GstElement *element) group = g_new0 (GstOptSchedulerGroup, 1); GST_INFO (GST_CAT_SCHEDULING, "new group %p", group); + group->refcount = 1; add_to_group (group, element); add_to_chain (chain, group); @@ -525,7 +586,7 @@ destroy_group_scheduler (GstOptSchedulerGroup *group) g_assert (group); if (group->flags & GST_OPT_SCHEDULER_GROUP_RUNNING) - g_warning ("removing running element"); + g_warning ("destroying running group scheduler"); #ifdef USE_COTHREADS if (group->cothread) { @@ -542,29 +603,18 @@ destroy_group_scheduler (GstOptSchedulerGroup *group) } static void -delete_group (GstOptSchedulerGroup *group) +destroy_group (GstOptSchedulerGroup *group) { - GSList *elements; - - GST_INFO (GST_CAT_SCHEDULING, "delete group %p", group); + GST_INFO (GST_CAT_SCHEDULING, "destroy group %p", group); g_assert (group != NULL); - g_assert (group->chain == NULL); + g_assert (group->elements == NULL); + + remove_from_chain (group->chain, group); if (group->flags & GST_OPT_SCHEDULER_GROUP_SCHEDULABLE) destroy_group_scheduler (group); - /* remove all elements from the group */ - elements = group->elements; - while (elements) { - GstElement *element = GST_ELEMENT (elements->data); - - GST_ELEMENT_SCHED_GROUP (element) = NULL; - - elements = g_slist_next (elements); - } - - g_slist_free (group->elements); g_free (group); } @@ -580,13 +630,14 @@ remove_from_group (GstOptSchedulerGroup *group, GstElement *element) group->num_elements--; GST_ELEMENT_SCHED_GROUP (element) = NULL; + gst_object_unref (GST_OBJECT (element)); if (group->num_elements == 0) { - GST_INFO (GST_CAT_SCHEDULING, "group %p is empty, deleting", group); - remove_from_chain (group->chain, group); - delete_group (group); - return NULL; + group = unref_group (group); } + + group = unref_group (group); + return group; } @@ -716,7 +767,7 @@ gst_opt_scheduler_schedule_run_queue (GstOptScheduler *osched) #endif /* a chain is scheduled by picking the first active group and scheduling it */ -static void +static void schedule_chain (GstOptSchedulerChain *chain) { GSList *groups; @@ -735,6 +786,7 @@ schedule_chain (GstOptSchedulerChain *chain) GST_INFO (GST_CAT_SCHEDULING, "scheduling group %p in chain %p", group, chain); + ref_group (group); #ifdef USE_COTHREADS schedule_group (group); #else @@ -745,6 +797,7 @@ schedule_chain (GstOptSchedulerChain *chain) GST_INFO (GST_CAT_SCHEDULING, "done scheduling group %p in chain %p", group, chain); + unref_group (group); break; } } @@ -887,8 +940,14 @@ gst_opt_scheduler_get_wrapper (GstPad *srcpad) schedule_group (group); #else if (!(group->flags & GST_OPT_SCHEDULER_GROUP_RUNNING)) { + ref_group (group); osched->runqueue = g_list_append (osched->runqueue, group); gst_opt_scheduler_schedule_run_queue (osched); + group = unref_group (group); + /* group is gone */ + if (group == NULL) { + return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT)); + } } else { g_warning ("deadlock detected, disabling group %p", group); @@ -1253,15 +1312,7 @@ gst_opt_scheduler_remove_element (GstScheduler *sched, GstElement *element) /* the element is guaranteed to live in it's own group/chain now */ get_group (element, &group); if (group) { - GstOptSchedulerChain *chain; - - GST_ELEMENT_SCHED_GROUP (element) = NULL; - - chain = group->chain; - if (chain) { - remove_from_chain (chain, group); - } - delete_group (group); + remove_from_group (group, element); } g_free (GST_ELEMENT_SCHED_CONTEXT (element));