I am new to this group but I have to fix CDI/MI part of
current debugger because it is not really working for our customers.
I know it is close to be rewritten with DSF but this “close”
is not going to be in the next half of year at least, so I have to do something
now.
I just want to know opinions of you guys, who spent with
debugger more time than me. Here is outline of current problems. Example is
given using method BreakpointManager::enableBreakpoint (from 4.0 branch)
231: boolean restart
= false;
MISession
miSession = target.getMISession();
CommandFactory
factory = miSession.getCommandFactory();
MIBreakEnable
breakEnable = factory.createMIBreakEnable(numbers);
try {
236: restart
= suspendInferior(target);
237: miSession.postCommand(breakEnable);
MIInfo
info = breakEnable.getMIInfo();
if (info
== null) {
throw new
CDIException(CdiResources.getString("cdi.Common.No_answer")); //$NON-NLS-1$
}
} catch
(MIException e) {
243: throw new
MI2CDIException(e);
} finally {
// Resume the program and enable events.
246: resumeInferior(target,
restart);
}
248: for (int i = 0;
i < miBreakpoints.length; i++) {
miBreakpoints[i].setEnabled(true);
}
251: breakpoint.setEnabled0(true);
// Fire a changed Event.
253: miSession.fireEvent(new
MIBreakpointChangedEvent(miSession, numbers[0]));
}
This code may work ok when a) program was suspended when it
was called b) it worked without exceptions. Any other scenarios would lead to
ui-debugger missinchronization at least and in some cases in ui deadlock. Here
is some scenarios:
1) Breakpoint
set command failed. In this case user would see breakpoint enabled but model
and debugger would see it disabled. Happens because debugger did not fire
update event with new status of breakpoint after failed attempt to set it (i.e.
like 253 should be probably in finally block while 248 at the end of try block)
2) UI
Missinchronization due to missed event. resumeInferior looks like this:
void resumeInferior(Target target, boolean
shouldRestart) throws CDIException {
if
(shouldRestart) {
target.resume();
// Enable events again.
((EventManager)getSession().getEventManager()).allowProcessingEvents(true);
}
}
So, let say
we enable breakpoint while process was running, and as a result it was hit as soon
as we resume it. Now because processing of events was OFF during all enable breakpoint
operation and there is no synchronization here we will miss this event COMPLETELY.
Meaning when we exit enableBreakpoint, inferior is stopped while UI does not think
so and continue showing it running.
3) Never resume event processing. Now lets say we execute 236 suspendInterior
while process is running. It turns off events (no synchronization again) and run
target.suspend(). Let say it failed for some reason (like time-out due to slow
target), so it throws exception and we hit finally block, but restart is false,
so we never actually restart AND we never resume events process that
suspendInferior turned off. Meaning debugger would not process stopped events
anymore, even we explicitly try to stop the process.
All this “unlikely” to happened
events are actually easily reproducible with simple scenario of bulk enabling
breakpoints (bulk – 3 breakpoints) while process is running, where race
condition on state of inferior creating exception and error while
resume/suspend on wrong state with consequences outlines above.
The problem is I don’t see easy fix
of this mess. I can re-arrange finally blocks and some statements to fix some
of it but it would still not work properly. Any thoughts on that?
Alena Laskavaia