mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-13 03:46:34 +00:00
added incremental scheduling notes
Original commit message from CVS: added incremental scheduling notes
This commit is contained in:
parent
f75bb0f38b
commit
2d0212c808
1 changed files with 125 additions and 0 deletions
125
docs/random/matth/scheduling.txt
Normal file
125
docs/random/matth/scheduling.txt
Normal file
|
@ -0,0 +1,125 @@
|
|||
-----------------------------------------------------------
|
||||
- GStreamer Scheduling / Synchronization (incsched) Notes -
|
||||
-----------------------------------------------------------
|
||||
|
||||
These notes describe deadlock scenarios and proposed solutions for
|
||||
GStreamer. This will be implemented in the INCSCHED1 branch.
|
||||
|
||||
I. Miscelaneous proposals
|
||||
II. Liveness problems (sometimes deadlock ;) and propsed solutions
|
||||
III. State transition approach and responsibility
|
||||
|
||||
MattH.
|
||||
|
||||
--------------------------------
|
||||
- I. Miscalenous proposals -
|
||||
--------------------------------
|
||||
|
||||
1. Change the names of GstThread and GstQueue to GstPtThread and GstPtQueue
|
||||
for pthread versions of Thread and Queue.
|
||||
|
||||
2. Change GstPtQueue to check its pads' peers' managers and make sure
|
||||
they are different. If not, fail and generate error message. (This
|
||||
ensures a GstPtQueue straddles a pthread boundary.)
|
||||
|
||||
3. Change state transitions to NULL <-> READY <-> PAUSED <-> PLAYING.
|
||||
|
||||
|
||||
---------------------------------------------------
|
||||
- II. Deadlock Scenarios and Proposed Solutions -
|
||||
- (in the order they will be implemented) -
|
||||
---------------------------------------------------
|
||||
|
||||
1. A downstream element "waits" for a buffer from its upstream element,
|
||||
a state change happens and "pauses" the upstream element -- the
|
||||
downstream element is blocked and cannot execute its change_state.
|
||||
|
||||
Note that this can only happen within a single GstPtQueue! Either a
|
||||
downstream element calls Pull, finds no buffer, and does a
|
||||
wait_cond(new buffer) or an upstream element calls Push, finds no
|
||||
room, and does a wait_cond(new room). Thus, GstPtQueue contains all
|
||||
the cond_wait / signal code.
|
||||
|
||||
=> The managing container (thread, pipeline) "wakes" up any sleep
|
||||
conditions of its "bottom half". (In the scenario described, it
|
||||
wakes the blocked downstream element's call to Pull.) The GstPtQueue
|
||||
cond_wait section determines that it woke up due to a pending state
|
||||
change and does a cothread_switch(0) to return to the main loop,
|
||||
which then executes the state transition.
|
||||
|
||||
Note that a managing container will have only one sleep condition
|
||||
in its "bottom half."
|
||||
|
||||
|
||||
2. Element "blocked" on getting I/O and cannot execute its change_state.
|
||||
|
||||
=> We will provide an I/O library for the elements to use that does
|
||||
not actually block. (A retry-loop with timeout or select() on
|
||||
2 -- or more -- file descriptors: one the one you want I/O from,
|
||||
the other one that GStreamer uses to "wake" everyone up.) The
|
||||
I/O library determines that it was woken due to a pending state
|
||||
change and does a cothread_switch(0) to return to the main loop,
|
||||
which then executes the state transition.
|
||||
|
||||
Note that a managing container will have only one elements in
|
||||
the middle of doing blocking I/O.
|
||||
|
||||
|
||||
3. Element using a library (code out of its control) which blocks for
|
||||
some reason (e.g., using real blocking I/O) so main loop never gets
|
||||
run to execute change_state.
|
||||
|
||||
=> Build in some timeout in the manging container (the "top half")
|
||||
when waiting for bottom half to respond to pending state. If
|
||||
managing container times out, kill the element's thread with a
|
||||
signal (or series of signals -- escalating priority). This
|
||||
requires that the element (the "bottom half") have matching
|
||||
signal handler(s) that execute(s) the state-transition.
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
- III. State-transition Approach and Responsibility -
|
||||
--------------------------------------------------------
|
||||
|
||||
A. The "top half" context of the managing container. (This is likely the
|
||||
context of the application.)
|
||||
|
||||
Call change_state on the managing container (GstPipeline, GstPtThread).
|
||||
If its "bottom half" (main_loop) is asleep, signal the condition to
|
||||
wake it up. Then do a cond_wait for the "bottom half" to execute the
|
||||
state transition and return (once the state has been changed).
|
||||
|
||||
|
||||
B. The main_loop (the "bottom half") of the managing container.
|
||||
|
||||
Needs to check for pending state transition after every switch back from
|
||||
one of its elements. If a pending state is found, it calls change_state
|
||||
on each of its elements, signals the "top half" that the state has been
|
||||
changed, then continues executing the plan (if Playing) or puts itself
|
||||
to sleep (Paused, Ready).
|
||||
|
||||
|
||||
C. Element.
|
||||
|
||||
Implement a change_state function to make transition for that element.
|
||||
The elements' change_state is what actually changes the state variable
|
||||
and notifies the scheduler that the state was changed. This function
|
||||
may also do things like close or open resources.
|
||||
|
||||
NOTE: when an element goes through certain state transitions (e.g., from
|
||||
Paused to Ready) its state (stack) will be wiped out. If it wants to
|
||||
preserve any state or data, it needs to store the information in a safe
|
||||
place.
|
||||
|
||||
|
||||
D. Cothread Scheduler.
|
||||
|
||||
Gets notified of state transition by elements' change_state functions
|
||||
then (re)set the plan accordingly. Assuming
|
||||
NULL <-> READY <-> PAUSED <-> PLAYING, some would be
|
||||
|
||||
+ Paused -> Playing: jump back where you were in the Plan and continue
|
||||
its execution
|
||||
|
||||
+ Ready -> Paused: reset the cothread pointers foreach cothread in the
|
||||
Plan (don't run)
|
Loading…
Reference in a new issue