typedef struct _GstOptSchedulerChain GstOptSchedulerChain;
struct _GstOptSchedulerChain {
+ gint refcount;
+
GstOptScheduler *sched;
GstOptSchedulerChainFlags flags;
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;
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
*/
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;
}
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;
}
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;
}
}
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);
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;
}
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);
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) {
}
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);
}
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;
}
#endif
/* a chain is scheduled by picking the first active group and scheduling it */
-static void
+static void
schedule_chain (GstOptSchedulerChain *chain)
{
GSList *groups;
GST_INFO (GST_CAT_SCHEDULING, "scheduling group %p in chain %p",
group, chain);
+ ref_group (group);
#ifdef USE_COTHREADS
schedule_group (group);
#else
GST_INFO (GST_CAT_SCHEDULING, "done scheduling group %p in chain %p",
group, chain);
+ unref_group (group);
break;
}
}
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);
/* 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));