[Live-devel] infinite recursion
Ross Finlayson
finlayson at live.com
Tue Jan 13 12:09:03 PST 2004
>I think this is a bug. at least, afterGetting should not be called
>directly, if doGetNextFrame1 was not called from
>the networkReadHandler.
No, it's not a bug - it's an optimization. As you discovered, it leads to
recursion only when "MultiFramedRTPSource::doGetNextFrame()" is consuming
data that has already been read - e.g., when it's reading a RTP packet that
contains multiple frames. And this recursion is not infinite, because
eventually all of the frames in the RTP packet will be consumed, and once
that happens, the next call to "MultiFramedRTPSource::doGetNextFrame()"
will return, completing the recursion. (After that, the program will
return to the event loop, and eventually
"MultiFramedRTPSource::networkReadHandler()" will get called for the next
packet, starting the process all over again.)
The bug was in your "BufferedSink" (modification to "FileSink") - it wasn't
consuming data from the input RTP packet.- which led to infinite recursion.
A reminder of the LIVE.COM code's execution model:
It is event-driven code, using an event loop - that works basically as follows:
while (1) {
find a task that needs to be done (by looking on the delay
queue,
and the list of network read handlers);
do this task;
}
Plus, before entering this loop, applications will typically call
"someSink->startPlaying()"
one or more times (for each sink), to start generating tasks that need to
be done.
Data passes through a chain of 'source's and 'sink's - e.g.,
'source1' -> 'source2' (a filter) -> 'source3' (a filter) -> 'sink'
Whenever a module (a 'sink' or one of the intermediate filter 'source's)
wants to get more data, it calls "FramedSource::getNextFrame()" on the
module that's to its immediate left. This is implemented by the pure
virtual function "FramedSource::doGetNextFrame()", that is implemented by
each 'source' module.
Each 'source' module's implementation of "doGetNextFrame()" works by
arranging for an 'after getting' function to be called when new data
becomes available for the caller. *In principle*, this is always done by
either (i) adding the 'after getting' function to the delay queue, using
"TaskScheduler::scheduleDelayedTask()" (perhaps with a 'delay' of 0), or
(ii) arranging for a network socket read handler function to be called when
the socket becomes readable. In each case, this causes the control flow to
return from the chain of "getNextFrame()" calls, and to continue executing
the event loop.
*However*, if the needed data is already available, it is often possible to
optimize case (i) by calling the 'after getting' function directly. This
replaces event loop handling with a direct function call. This produces
recursion (because the 'sink' - once it gets its data - will then call
"getNextFrame" once again). However, it won't be *infinite* recursion, as
long as new data isn't always immediately available. Once a source module
runs out of data, it won't be able to call the 'after getting' function
directly, and so the recursion will end.
Ross Finlayson
LIVE.COM
<http://www.live.com/>
More information about the live-devel
mailing list