86895974f7d32c639a645005828c428f411b0e6a
[platform/upstream/gstreamer.git] / docs / random / omega / plan-generation
1 Plan generation happens at transition from NULL to READY (and PLAYING to READY right now, need to fix
2 that).  By way of some logic in gst_bin_change_state(), gst_bin_create_plan() is only called for the
3 outer Bin, usually a Pipeline.  This keeps things from getting nasty later on.
4
5 A major new concept in plan generation is that of the 'manager'.  This is the element that is reponsible
6 for running a given element.  In general, Pipelines and Threads are the only managing-capable elements
7 (have the MANAGER flag set), since they are the only ones with real scheduling authority (because they
8 have a process context to play with, basically).
9
10 gst_bin_set_manager() is called to set the manager element of the bin and all it's children and their
11 children.  However, there's one important trick: it won't recurse into child Bins that have the MANAGER
12 flag set.  This avoids some highly redundant recursion.
13
14 When create_plan() is called on the outside Pipeline, the first thing it does is call
15 set_manager(self,self).  As noted above, this recursion will not proceed into child Bins that have the
16 MANAGER flag set.
17
18 The next step is to recursively generate the plan (yes, head-recursive).  This gives child Bins the
19 opportunity to generate their plan first, causing a inside-to-outside sequence.  This matches the way
20 the scheduling is arranged now, where the plan for a Src/Connection outside a Bin is handled by that
21 Bin, not it's parent.  But we must be very careful not to stomp on that plan in the parent Bin.
22
23 Because create_plan() is called on all Bins, but we can only set up scheduling state in MANAGER bins,
24 create_plan() must perform create_plan() recursion, but not do anything else *unless* the MANAGER bit is
25 set.  It shouldn't even call set_manager() unless it's a MANAGER itself, because calling it otherwise
26 would waste time doing the work again.  Basically, from the standpoing of setting the manager,
27 create_plan() recursion starts it when the current Bin is a MANAGER, and set_manager() stops when it
28 finds the next one.  create_plan()'s further recursion eventually starts the process back up again
29 furtuer down the hierarchy, until everything is covered.
30
31 For all MANAGER Bins, the last step is to actually create the scheduling plan.  This is still one of the
32 nastiest chunks of code in the whole project, and probably will do nothing but get worse from now on (it
33 got better recently, but only because I took a chainsaw to the code and broke everthing...).  It will
34 remain similar to what it is now, but with some definite differences.
35
36 First task is now to find all the elements that we're responsible for.  This is normally a recursive
37 process, because the structure is an arbitrary tree.  However, something like the following should work 
38 (bin is self):
39
40   GSList *elements = NULL;
41   GList *children;
42   GSList *waiting_bins = NULL;
43   GstBin *waiting_bin;
44
45   waiting_bins = g_slist_prepend (waiting_bins,bin);
46
47   while (waiting_bins) {
48     // retrieve the top of the stack and pop it
49     waiting_bin = GST_BIN (waiting_bins->data);
50     waiting_bins = g_slist_remove (waiting_bins,waiting_bin);
51
52     // walk the list of elements, and find bins
53     children = waiting_bin->children;
54     while (children) {
55       // add it to the list of elements
56       elements = g_slist_prepend (elements, children->data);
57
58       // if it's a bin and it's not a managing bin,
59       // shove it on the list of bins to recurse into
60       if (GST_IS_BIN (children->data) && 
61           !GST_FLAG_IS_SET (GST_ELEMENT (children->data)))
62         waiting_bins = g_slist_prepend (waiting_bins,children->data);
63
64       children = g_list_next (children);
65     }
66   }
67
68 The code makes the assumption that the manager of every element is the same until such time as a
69 different managing parent appears in the hierarchy.  This is the result of the aforementioned nested
70 recursion of create_plan() and set_manager(), but may not remain the case forever.  The above loop
71 should probably be slightly re-written to work solely on whether or not the Bin in question is the
72 element's manager.  This means that the child Bins are *always* recursed into, in case there's a rogue
73 element inside of one of them that's supposed to be managed.
74
75 At the same time all the elements managed by this bin are found (i.e. in the inner loop), we can
76 determine some useful bits of information, such as testing for several cases that require the use of
77 cothreads.  The availability of manager information at this point may aid significantly in this
78 decision.
79
80 Finally, the scheduling plan is generated, based on all the elements to be managed by the Bin (the list
81 of which may span several 'generations' of Bins and elements).  Elements which have peers in child
82 self-managed Bins are left alone on for the pad in that makes that connection.  This should keep the
83 parent Bins from stepping all over state set up by the child Bins, by establishing clear implicit
84 ownership on the pad level, based on the managing Bins' relationship to the pad.