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
This commit is contained in:
Wim Taymans 2003-02-27 18:21:34 +00:00
parent ddd3265b11
commit 91d33d766a

View file

@ -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,46 +345,23 @@ 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);
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)
{
GST_INFO (GST_CAT_SCHEDULING, "adding group %p to chain %p", group, chain);
g_assert (group->chain == NULL);
chain->groups = g_slist_prepend (chain->groups, group);
group->chain = chain;
chain->num_groups++;
return chain;
}
static GstOptSchedulerChain*
create_chain (GstOptScheduler *osched)
{
@ -383,7 +369,9 @@ create_chain (GstOptScheduler *osched)
chain = g_new0 (GstOptSchedulerChain, 1);
chain->sched = osched;
chain->refcount = 1;
gst_object_ref (GST_OBJECT (osched));
osched->chains = g_slist_prepend (osched->chains, chain);
GST_INFO (GST_CAT_SCHEDULING, "new chain %p", chain);
@ -391,6 +379,46 @@ create_chain (GstOptScheduler *osched)
return chain;
}
static GstOptSchedulerChain*
ref_chain (GstOptSchedulerChain *chain)
{
GST_INFO (GST_CAT_SCHEDULING, "ref chain %p %d->%d", chain,
chain->refcount, chain->refcount+1);
chain->refcount++;
return chain;
}
static GstOptSchedulerChain*
unref_chain (GstOptSchedulerChain *chain)
{
GST_INFO (GST_CAT_SCHEDULING, "unref chain %p %d->%d", chain,
chain->refcount, chain->refcount-1);
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;
}
static GstOptSchedulerChain*
remove_from_chain (GstOptSchedulerChain *chain, GstOptSchedulerGroup *group)
{
@ -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;
}
@ -482,6 +515,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)
{
@ -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));