Discussion:
CDI/MI nightmares
Elena Laskavaia
2008-01-14 18:30:29 UTC
Permalink
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

Loading...