apitrace/apitrace — pull request #231 by lawlove (2014-02-22 03:56:25+00:00)
Title: qapitrace: fails to find [CALLNO] in first frame

qapitrace [CALLNO]

will mostly fail to find CALLNO if it resides in the first frame (not
always). If CALLNO is in a frame other than frame 0 then it succeeds.

Description
-----------
Apparently a race condition exists between two objects fetching the
list of calls for frame 0. On initialization of the trace, frame 0 is
automatically populated. If the specified CALLNO is also in frame 0
then the function that returns the Frame's children
(TraceLoader::fetchFrameContents) can be accessed simultaneously via
separate SIGNALS. Details below.

I don't think either of these address the issue but the implemented
solution works. It seems there should be a better solution.

Implemented solution
--------------------
Do one or the other:
Pre-populate frame 0 if callno is not given. Otherwise, populate and
expand to the given callno

Solution alternative
--------------------
Don't force populate frame 0 on initialization. Hence, no conflict.
(I don't see a need for pre-populating frame 0. The other frames
load just as fast without being pre-populated.)

Unsuccessful solution attempts
------------------------------
Using QMutex around the fetch function
Using Qt::BlockingQueuedConnection for both SIGNALs

Details
-------
After the trace has been scanned a "finishedParsing()" SIGNAL is
emitted from TraceLoader::loadTrace(). This SIGNAL is connected to
two different objects in a separate thread from the emitting
(TraceLoader) object:

1) SLOT ApiTrace::finishedParsing()
2) SLOT MainWindow::finishedLoadingTrace()
(via SIGNAL ApiTrace::finishedLoadingTrace())

SLOT ApiTrace::finishedParsing() # only loads frame 0
SLOT MainWindow::finishedLoadingTrace() # expands to the given callno.

If the callno is in frame 0 there can be a race condition.

Both objects end up emitting SIGNALS from the ApiTrace object to
TraceLoader object SLOTs where each SLOT in turn calls the

TraceLoader:fetchFrameContents()

function to retrieve the Frame's children, a list of pointers to
call objects (QVector). This list of calls for each
frame should only be generated once. It then emits a SIGNAL to cause
the ApiTrace object to load the calls into the frame. Any subsequent
call to the fetch function just returns the frame's member set of
children call objects.

When the MainWindow SIGNAL is emitted, the fetch function may be
accessed at the same time as the other SIGNAL result. When the
check is made by the fetch function for whether the frame's children
call objects have been loaded, it receives a false and continues to
create another list of the same calls. When this list is returned, the
client looks for the call object associated with the index and then
emits a SIGNAL with that call object. Eventually that call object is
searched for in the (now loaded) Frame's children but has a different
address and hence not found.

Testing
-------
debug_khr.trace # single frame
sample-effects.trace # from issue#218
warzone2100.trace # from issue#218
glxgears.trace

Signed-off-by: Lawrence L Love