[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