Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 337893 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java (-22 / +37 lines)
Lines 135-143 Link Here
135
135
136
	/**
136
	/**
137
	 * Indicates that the given thread has been suspended.
137
	 * Indicates that the given thread has been suspended.
138
	 * @since 4.0
138
	 */
139
	 */
139
	@Immutable
140
	@Immutable
140
	private static class SuspendedEvent extends RunControlEvent<IExecutionDMContext, MIStoppedEvent>
141
	protected static class SuspendedEvent extends RunControlEvent<IExecutionDMContext, MIStoppedEvent>
141
	implements ISuspendedDMEvent
142
	implements ISuspendedDMEvent
142
	{
143
	{
143
		SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) {
144
		SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) {
Lines 188-197 Link Here
188
189
189
    /**
190
    /**
190
     * Indicates that the given thread has been suspended on a breakpoint.
191
     * Indicates that the given thread has been suspended on a breakpoint.
191
     * @since 3.0
192
     * @since 4.0
192
     */
193
     */
193
    @Immutable
194
    @Immutable
194
    private static class BreakpointHitEvent extends SuspendedEvent
195
    protected static class BreakpointHitEvent extends SuspendedEvent
195
    implements IBreakpointHitDMEvent
196
    implements IBreakpointHitDMEvent
196
    {
197
    {
197
        final private IBreakpointDMContext[] fBreakpoints;
198
        final private IBreakpointDMContext[] fBreakpoints;
Lines 207-214 Link Here
207
        }
208
        }
208
    }
209
    }
209
210
211
	/**
212
	 * @since 4.0
213
	 */
210
	@Immutable
214
	@Immutable
211
	private static class ResumedEvent extends RunControlEvent<IExecutionDMContext, MIRunningEvent>
215
	protected static class ResumedEvent extends RunControlEvent<IExecutionDMContext, MIRunningEvent>
212
	implements IResumedDMEvent
216
	implements IResumedDMEvent
213
	{
217
	{
214
		ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) {
218
		ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) {
Lines 235-242 Link Here
235
		}
239
		}
236
	}
240
	}
237
241
242
	/**
243
	 * @since 4.0
244
	 */
238
	@Immutable
245
	@Immutable
239
	private static class StartedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadCreatedEvent>
246
	protected static class StartedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadCreatedEvent>
240
	implements IStartedDMEvent
247
	implements IStartedDMEvent
241
	{
248
	{
242
		StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) {
249
		StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) {
Lines 244-251 Link Here
244
		}
251
		}
245
	}
252
	}
246
253
254
	/**
255
	 * @since 4.0
256
	 */
247
	@Immutable
257
	@Immutable
248
	private static class ExitedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadExitEvent>
258
	protected static class ExitedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadExitEvent>
249
	implements IExitedDMEvent
259
	implements IExitedDMEvent
250
	{
260
	{
251
		ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) {
261
		ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) {
Lines 273-279 Link Here
273
		String fStateChangeDetails;
283
		String fStateChangeDetails;
274
	}
284
	}
275
285
276
	private static class RunToLineActiveOperation {
286
	/**
287
	 * @since 4.0
288
	 */
289
	protected static class RunToLineActiveOperation {
277
		private IMIExecutionDMContext fThreadContext;
290
		private IMIExecutionDMContext fThreadContext;
278
		private int fBpId;
291
		private int fBpId;
279
		private String fFileLocation;
292
		private String fFileLocation;
Lines 310-315 Link Here
310
323
311
	private RunToLineActiveOperation fRunToLineActiveOperation = null;
324
	private RunToLineActiveOperation fRunToLineActiveOperation = null;
312
325
326
	/** @since 4.0 */
327
	protected RunToLineActiveOperation getRunToLineActiveOperation() {
328
		return fRunToLineActiveOperation;
329
	}
330
331
	/** @since 4.0 */
332
	protected void setRunToLineActiveOperation(RunToLineActiveOperation operation) {
333
		fRunToLineActiveOperation = operation;
334
	}
335
313
	/** 
336
	/** 
314
	 * Indicates that the next MIRunning event for this thread should be silenced.
337
	 * Indicates that the next MIRunning event for this thread should be silenced.
315
	 */
338
	 */
Lines 334-339 Link Here
334
	// Initialization and shutdown
357
	// Initialization and shutdown
335
	///////////////////////////////////////////////////////////////////////////
358
	///////////////////////////////////////////////////////////////////////////
336
359
360
337
	public GDBRunControl_7_0_NS(DsfSession session) {
361
	public GDBRunControl_7_0_NS(DsfSession session) {
338
		super(session);
362
		super(session);
339
	}
363
	}
Lines 1180-1200 Link Here
1180
		
1204
		
1181
		@Override
1205
		@Override
1182
		public void execute(final RequestMonitor rm) {
1206
		public void execute(final RequestMonitor rm) {
1183
			fContainerDmcToSuspend = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
1207
			// In non-stop, for single address-space multi-process,
1184
			if (fContainerDmcToSuspend != null) {
1208
			// we need any one of the processes to be suspended.
1185
				String groupId = ((IMIContainerDMContext)fContainerDmcToSuspend).getGroupId();
1209
			// Note that even if we can obtain a container dmc from fCtx
1186
				if (groupId != null && groupId.length() > 0) {
1210
			// we will have issues because that context is probably not
1187
					// If we have a fully formed containerDmc, we can use it directly.
1211
			// fully formed (missing groupId and procId).  So, we just
1188
					fTargetAvailable = isSuspended(fContainerDmcToSuspend);
1212
			// make it easy on ourselves and fetch the containers directly
1189
					rm.done();
1190
					return;
1191
				}
1192
				// else, the container is not fully formed, so let's fetch it below, since
1193
				// we know we are running single-process and there is only one process
1194
			}
1195
1196
			// If we get here, we have to get the list of processes to know if any of
1197
			// them is suspended.
1198
			ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
1213
			ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
1199
			IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1214
			IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1200
			processControl.getProcessesBeingDebugged(
1215
			processControl.getProcessesBeingDebugged(
(-)src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_2_NS.java (+572 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 Wind River Systems and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     Wind River Systems - initial API and implementation
10
 *     Ericsson		      - Support for multi-process for Linux, GDB 7.2
11
 *******************************************************************************/
12
13
package org.eclipse.cdt.dsf.gdb.service;
14
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Hashtable;
18
import java.util.LinkedList;
19
import java.util.Map;
20
import java.util.Set;
21
22
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
23
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
24
import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
25
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
26
import org.eclipse.cdt.dsf.concurrent.Sequence;
27
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
28
import org.eclipse.cdt.dsf.datamodel.DMContexts;
29
import org.eclipse.cdt.dsf.datamodel.IDMContext;
30
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
31
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
32
import org.eclipse.cdt.dsf.debug.service.IProcesses;
33
import org.eclipse.cdt.dsf.debug.service.IRunControl;
34
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
35
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
36
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
37
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
38
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
39
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
40
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
41
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext;
42
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
43
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
44
import org.eclipse.cdt.dsf.mi.service.command.events.MIRunningEvent;
45
import org.eclipse.cdt.dsf.mi.service.command.events.MISignalEvent;
46
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
47
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
48
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
49
import org.eclipse.cdt.dsf.service.DsfSession;
50
51
/**
52
 * Version of the non-stop runControl for GDB 7.2
53
 * This class handles multi-process for Linux which requires
54
 * us to interrupt different processes at the same time to be
55
 * able to set breakpoints.
56
 * This class was created for bug 337893
57
 * @since 4.0
58
 */
59
public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS
60
{
61
62
	private ICommandControlService fConnection;
63
	private CommandFactory fCommandFactory;
64
65
	/** 
66
	 * Set of threads for which the next MIRunning event should be silenced.
67
	 */
68
	private Set<IMIExecutionDMContext> fDisableNextRunningEventDmc = new HashSet<IMIExecutionDMContext>();
69
	/** 
70
	 * Set of threads for which the next MISignal (MIStopped) event should be silenced.
71
	 */
72
	private Set<IMIExecutionDMContext> fDisableNextSignalEventDmc = new HashSet<IMIExecutionDMContext>();
73
	/** 
74
	 * Map that stores the silenced MIStopped event for the specified thread, in case we need to use it for a failure.
75
	 */
76
	private Map<IMIExecutionDMContext,MIStoppedEvent> fSilencedSignalEvent = new HashMap<IMIExecutionDMContext, MIStoppedEvent>();
77
78
	///////////////////////////////////////////////////////////////////////////
79
	// Initialization and shutdown
80
	///////////////////////////////////////////////////////////////////////////
81
82
	public GDBRunControl_7_2_NS(DsfSession session) {
83
		super(session);
84
	}
85
86
	@Override
87
	public void initialize(final RequestMonitor rm) {
88
		super.initialize(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
89
			@Override
90
			protected void handleSuccess() {
91
				doInitialize(rm);
92
			}
93
		});
94
	}
95
96
	private void doInitialize(final RequestMonitor rm) {
97
		register(new String[]{ IRunControl.class.getName(), 
98
				IRunControl2.class.getName(),
99
				IMIRunControl.class.getName(),
100
				GDBRunControl_7_0_NS.class.getName(),
101
				GDBRunControl_7_2_NS.class.getName(),
102
		}, 
103
		new Hashtable<String,String>());
104
		fConnection = getServicesTracker().getService(ICommandControlService.class);
105
		fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
106
		getSession().addServiceEventListener(this, null);
107
		rm.done();
108
	}
109
110
	@Override
111
	public void shutdown(final RequestMonitor rm) {
112
		unregister();
113
		getSession().removeServiceEventListener(this);
114
		super.shutdown(rm);
115
	}
116
117
	private Map<IDMContext, ExecuteWithTargetAvailableOperation> execWithTargetAvailMap = new HashMap<IDMContext, ExecuteWithTargetAvailableOperation>();
118
119
	@Override
120
	public void executeWithTargetAvailable(IDMContext ctx, final Sequence.Step[] steps, final RequestMonitor rm) {
121
		ExecuteWithTargetAvailableOperation operation = execWithTargetAvailMap.get(ctx);
122
		if (operation == null) {
123
			operation = new ExecuteWithTargetAvailableOperation(ctx);
124
			execWithTargetAvailMap.put(ctx, operation);
125
		}
126
		operation.executeWithTargetAvailable(steps, rm);
127
	}
128
129
	/* ******************************************************************************
130
	 * Section to support making operations even when the target is unavailable.
131
	 *
132
	 * Although one would expect to be able to make commands all the time when
133
	 * in non-stop mode, it turns out that GDB has trouble with some commands
134
	 * like breakpoints.  The safe way to do it is to make sure we have at least
135
	 * one thread suspended.
136
	 * 
137
	 * Basically, we must make sure one thread is suspended before making
138
	 * certain operations (currently breakpoints).  If that is not the case, we must 
139
	 * first suspend one thread, then perform the specified operations,
140
	 * and finally resume that thread..
141
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
142
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
143
	 * 
144
	 * Note that for multi-process on Linux, the correct container must be suspended for 
145
     * the breakpoint to be inserted on that container.  This means that we need to be
146
     * able to interrupt multiple processes at the same time to insert a breakpoint
147
     * in each one of them.
148
     * See http://bugs.eclipse.org/337893
149
	 * ******************************************************************************/
150
151
	protected class ExecuteWithTargetAvailableOperation {
152
		/**
153
		 * Utility class to store the parameters of the executeWithTargetAvailable() operations.
154
		 */
155
		public class TargetAvailableOperationInfo {
156
			public Sequence.Step[] steps;
157
			public RequestMonitor rm;
158
159
			public TargetAvailableOperationInfo(Step[] steps, RequestMonitor rm) {
160
				super();
161
				this.steps = steps;
162
				this.rm = rm;
163
			}
164
		};
165
166
		public IDMContext fCtx;
167
		// Keep track of if the target was available or not when we started the operation
168
		public boolean fTargetAvailable;
169
		// The container that needs to be suspended to perform the steps of the operation
170
		public IContainerDMContext fContainerDmcToSuspend;
171
		// The thread that we will actually suspend to make the container suspended.
172
		public IMIExecutionDMContext fExecutionDmcToSuspend;
173
174
		// Do we currently have an executeWithTargetAvailable() operation ongoing?
175
		public boolean fOngoingOperation;
176
		// Are we currently executing steps passed into executeWithTargetAvailable()?
177
		// This allows us to know if we can add more steps to execute or if we missed
178
		// our opportunity
179
		public boolean fCurrentlyExecutingSteps;
180
181
		// MultiRequestMonitor that allows us to track all the different steps we are
182
		// executing.  Once all steps are executed, we can complete this MultiRM and
183
		// allow the global sequence to continue.
184
		// Note that we couldn't use a CountingRequestMonitor because that type of RM
185
		// needs to know in advance how many subRms it will track; the MultiRM allows us
186
		// to receive more steps to execute continuously, and be able to upate the MultiRM.
187
		public MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
188
		// The number of batches of steps that are still being executing for potentially
189
		// concurrent executeWithTargetAvailable() operations.
190
		// Once this gets to zero, we know we have executed all the steps we were aware of
191
		// and we can complete the operation.
192
		public int fNumStepsStillExecuting;
193
		// Queue of executeWithTargetAvailable() operations that need to be processed.
194
		public LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
195
196
		public ExecuteWithTargetAvailableOperation(IDMContext ctx) {
197
			fCtx = ctx;
198
		}
199
200
		/**
201
		 * This method takes care of executing a batch of steps that were passed to
202
		 * ExecuteWithTargetAvailable().  The method is used to track the progress
203
		 * of all these batches of steps, so that we know exactly when all of them
204
		 * have been completed and the global sequence can be completed.
205
		 */
206
		protected void executeSteps(final TargetAvailableOperationInfo info) {
207
			fNumStepsStillExecuting++;
208
209
			// This RM propagates any error to the original rm of the actual steps.
210
			// Even in case of errors for these steps, we want to continue the overall sequence
211
			RequestMonitor stepsRm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
212
				@Override
213
				protected void handleCompleted() {
214
					info.rm.setStatus(getStatus());
215
					// It is important to call rm.done() right away.
216
					// This is because some other operation we are performing might be waiting
217
					// for this one to be done.  If we try to wait for the entire sequence to be
218
					// done, then we will never finish because one monitor will never show as
219
					// done, waiting for the second one.
220
					info.rm.done();
221
222
					fExecuteQueuedOpsStepMonitor.requestMonitorDone(this);
223
					fNumStepsStillExecuting--;
224
					if (fNumStepsStillExecuting == 0) {
225
						fExecuteQueuedOpsStepMonitor.doneAdding();
226
					}
227
				}
228
			};
229
230
			fExecuteQueuedOpsStepMonitor.add(stepsRm);
231
232
			getExecutor().execute(new Sequence(getExecutor(), stepsRm) {
233
				@Override public Step[] getSteps() { return info.steps; }
234
			});	
235
		}
236
237
		public void executeWithTargetAvailable(final Sequence.Step[] steps, final RequestMonitor rm) {
238
			if (!fOngoingOperation) {
239
				// We are the first operation of this kind currently requested
240
				// so we need to start the sequence
241
				fOngoingOperation = true;
242
243
				// We always go through our queue, even if we only have a single call to this method
244
				fOperationsPending.add(new TargetAvailableOperationInfo(steps, rm));
245
246
				// Steps that need to be executed to perform the operation
247
				final Step[] sequenceSteps = new Step[] {
248
						new IsTargetAvailableStep(),
249
						new MakeTargetAvailableStep(),
250
						new ExecuteQueuedOperationsStep(),
251
						new RestoreTargetStateStep(),
252
				};
253
254
				// Once all the sequence is completed, we need to see if we have received
255
				// another request that we now need to process
256
				RequestMonitor sequenceCompletedRm = new RequestMonitor(getExecutor(), null) {
257
					@Override
258
					protected void handleCompleted() {
259
						fOngoingOperation = false;
260
261
						if (fOperationsPending.size() > 0) {
262
							// Darn, more operations came in.  Trigger their processing
263
							// by calling executeWithTargetAvailable() on the last one
264
							TargetAvailableOperationInfo info = fOperationsPending.removeLast();
265
							executeWithTargetAvailable(info.steps, info.rm);
266
						}
267
						// no other rm.done() needs to be called, they have all been handled already
268
					}
269
				};
270
271
				getExecutor().execute(new Sequence(getExecutor(), sequenceCompletedRm) {
272
					@Override public Step[] getSteps() { return sequenceSteps; }
273
				});
274
			} else {
275
				// We are currently already executing such an operation
276
				// If we are still in the process of executing steps, let's include this new set of steps.
277
				// This is important because some steps may depend on these new ones.
278
				if (fCurrentlyExecutingSteps) {
279
					executeSteps(new TargetAvailableOperationInfo(steps, rm));
280
				} else {
281
					// Too late to execute the new steps, so queue them for later
282
					fOperationsPending.add(new TargetAvailableOperationInfo(steps, rm));
283
				}
284
			}
285
		}
286
287
288
		/**
289
		 * This part of the sequence verifies if the execution context of interest
290
		 * is suspended or not.
291
		 */
292
		public class IsTargetAvailableStep extends Sequence.Step {
293
			@Override
294
			public void execute(final RequestMonitor rm) {
295
				fContainerDmcToSuspend = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
296
				if (fContainerDmcToSuspend != null) {
297
					fTargetAvailable = isSuspended(fContainerDmcToSuspend);
298
					rm.done();
299
					return;
300
				}
301
302
				// If we get here, we have to get the list of processes to know if any of
303
				// them is suspended.
304
				ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
305
				IProcesses processControl = getServicesTracker().getService(IProcesses.class);
306
				processControl.getProcessesBeingDebugged(
307
						controlDmc,
308
						new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
309
							@Override
310
							protected void handleSuccess() {
311
								assert getData() != null;
312
313
								if (getData().length == 0) {
314
									// Happens at startup, starting with GDB 7.0.
315
									// This means the target is available
316
									fTargetAvailable = true;
317
								} else {
318
									fTargetAvailable = false;
319
									// Choose the first process as the one to suspend if needed
320
									fContainerDmcToSuspend = (IContainerDMContext)(getData()[0]);
321
									for (IDMContext containerDmc : getData()) {
322
										if (isSuspended((IContainerDMContext)containerDmc)) {
323
											fTargetAvailable = true;
324
											break;
325
										}
326
									}
327
								}
328
								rm.done();
329
							}
330
						});
331
			}
332
		};
333
334
		/**
335
		 * If the execution context of interest is not suspended, this step
336
		 * will interrupt it.
337
		 */
338
		public class MakeTargetAvailableStep extends Sequence.Step {
339
			@Override
340
			public void execute(final RequestMonitor rm) {
341
				if (!fTargetAvailable) {
342
					// Instead of suspending the entire process, let's find its first thread and use that
343
					IProcesses processControl = getServicesTracker().getService(IProcesses.class);
344
					processControl.getProcessesBeingDebugged(
345
							fContainerDmcToSuspend,
346
							new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
347
								@Override
348
								protected void handleSuccess() {
349
									assert getData() != null;
350
									assert getData().length > 0;
351
352
									fExecutionDmcToSuspend = (IMIExecutionDMContext)getData()[0];
353
354
									assert !fDisableNextRunningEventDmc.contains(fExecutionDmcToSuspend);
355
									assert !fDisableNextSignalEventDmc.contains(fExecutionDmcToSuspend);
356
357
									// Don't broadcast the next stopped signal event
358
									fDisableNextSignalEventDmc.add(fExecutionDmcToSuspend);
359
360
									suspend(fExecutionDmcToSuspend,
361
											new RequestMonitor(getExecutor(), rm) {
362
										@Override
363
										protected void handleFailure() {
364
											// We weren't able to suspend, so abort the operation
365
											fDisableNextSignalEventDmc.remove(fExecutionDmcToSuspend);
366
											super.handleFailure();
367
										};
368
									});
369
								}
370
							});
371
				} else {
372
					rm.done();
373
				}
374
			}
375
			@Override
376
			public void rollBack(RequestMonitor rm) {
377
				Sequence.Step restoreStep = new RestoreTargetStateStep();
378
				restoreStep.execute(rm);
379
			}
380
		};
381
382
		/**
383
		 * This step of the sequence takes care of executing all the steps that
384
		 * were passed to ExecuteWithTargetAvailable().
385
		 */
386
		public class ExecuteQueuedOperationsStep extends Sequence.Step {
387
			@Override
388
			public void execute(final RequestMonitor rm) {
389
				fCurrentlyExecutingSteps = true;
390
391
				// It is important to use an ImmediateExecutor for this RM, to make sure we don't risk getting a new
392
				// call to ExecuteWithTargetAvailable() when we just finished executing the steps.
393
				fExecuteQueuedOpsStepMonitor = new MultiRequestMonitor<RequestMonitor>(ImmediateExecutor.getInstance(), rm) {
394
					@Override
395
					protected void handleCompleted() {
396
						assert fOperationsPending.size() == 0;
397
398
						// We don't handle errors here.  Instead, we have already propagated any
399
						// errors to each rm for each set of steps
400
401
						fCurrentlyExecutingSteps = false;
402
						// Continue the sequence
403
						rm.done();
404
					}
405
				};
406
				// Tell the RM that we need to confirm when we are done adding sub-rms
407
				fExecuteQueuedOpsStepMonitor.requireDoneAdding();
408
409
				// All pending operations are independent of each other so we can
410
				// run them concurrently.
411
				while (fOperationsPending.size() > 0) {
412
					executeSteps(fOperationsPending.poll());				
413
				}
414
			}
415
		};
416
417
		/**
418
		 * If the sequence had to interrupt the execution context of interest,
419
		 * this step will resume it again to reach the same state as when we started.
420
		 */
421
		public class RestoreTargetStateStep extends Sequence.Step {
422
			@Override
423
			public void execute(final RequestMonitor rm) {
424
				if (!fTargetAvailable) {
425
					assert !fDisableNextRunningEventDmc.contains(fExecutionDmcToSuspend);
426
					fDisableNextRunningEventDmc.add(fExecutionDmcToSuspend);
427
428
					// Can't use the resume() call because we 'silently' stopped
429
					// so resume() will not know we are actually stopped
430
					fConnection.queueCommand(
431
							fCommandFactory.createMIExecContinue(fExecutionDmcToSuspend),
432
							new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
433
								@Override
434
								protected void handleSuccess() {
435
									fSilencedSignalEvent.remove(fExecutionDmcToSuspend);
436
									super.handleSuccess();
437
								}
438
439
								@Override
440
								protected void handleFailure() {
441
									// Darn, we're unable to restart the target.  Must cleanup!
442
									fDisableNextRunningEventDmc.remove(fExecutionDmcToSuspend);
443
444
									// We must also sent the Stopped event that we had kept silent
445
									MIStoppedEvent event = fSilencedSignalEvent.remove(fExecutionDmcToSuspend);
446
									if (event != null) {
447
										eventDispatched(event);
448
									} else {
449
										// Maybe the stopped event didn't arrive yet.
450
										// We don't want to silence it anymore
451
										fDisableNextSignalEventDmc.remove(fExecutionDmcToSuspend);
452
									}
453
454
									super.handleFailure();
455
								}
456
							});
457
458
				} else {
459
					// We didn't suspend the thread, so we don't need to resume it
460
					rm.done();
461
				}
462
			}
463
		};
464
465
	}
466
	/* ******************************************************************************
467
	 * End of section to support operations even when the target is unavailable.
468
	 * ******************************************************************************/
469
470
	///////////////////////////////////////////////////////////////////////////
471
	// Event handlers
472
	///////////////////////////////////////////////////////////////////////////
473
474
	/**
475
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
476
	 * @noreference This method is not intended to be referenced by clients.
477
	 */
478
	@Override
479
	@DsfServiceEventHandler
480
	public void eventDispatched(final MIRunningEvent e) {
481
		if (fDisableNextRunningEventDmc.remove(e.getDMContext())) {
482
			// Don't broadcast the running event
483
			return;
484
		}
485
        getSession().dispatchEvent(new ResumedEvent(e.getDMContext(), e), getProperties());
486
	}
487
488
	/**
489
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
490
	 * @noreference This method is not intended to be referenced by clients.
491
	 */
492
	@Override
493
	@DsfServiceEventHandler
494
	public void eventDispatched(final MIStoppedEvent e) {
495
		if (getRunToLineActiveOperation() != null) {
496
			// First check if it is the right thread that stopped
497
			IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
498
			if (getRunToLineActiveOperation().getThreadContext().equals(threadDmc)) {
499
				int bpId = 0;
500
				if (e instanceof MIBreakpointHitEvent) {
501
					bpId = ((MIBreakpointHitEvent)e).getNumber();
502
				}
503
				String fileLocation = e.getFrame().getFile() + ":" + e.getFrame().getLine();  //$NON-NLS-1$
504
				String addrLocation = e.getFrame().getAddress();
505
				// Here we check three different things to see if we are stopped at the right place
506
				// 1- The actual location in the file.  But this does not work for breakpoints that
507
				//    were set on non-executable lines
508
				// 2- The address where the breakpoint was set.  But this does not work for breakpoints
509
				//    that have multiple addresses (GDB returns <MULTIPLE>.)  I think that is for multi-process
510
				// 3- The breakpoint id that was hit.  But this does not work if another breakpoint
511
				//    was also set on the same line because GDB may return that breakpoint as being hit.
512
				//
513
				// So this works for the large majority of cases.  The case that won't work is when the user
514
				// does a runToLine to a line that is non-executable AND has another breakpoint AND
515
				// has multiple addresses for the breakpoint.  I'm mean, come on!
516
				if (fileLocation.equals(getRunToLineActiveOperation().getFileLocation()) ||
517
						addrLocation.equals(getRunToLineActiveOperation().getAddrLocation()) ||
518
						bpId == getRunToLineActiveOperation().getBreakointId()) {
519
					// We stopped at the right place.  All is well.
520
					setRunToLineActiveOperation(null);
521
				} else {
522
					// The right thread stopped but not at the right place yet
523
					if (getRunToLineActiveOperation().shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
524
						fConnection.queueCommand(
525
								fCommandFactory.createMIExecContinue(getRunToLineActiveOperation().getThreadContext()),
526
								new DataRequestMonitor<MIInfo>(getExecutor(), null));
527
528
						// Don't send the stop event since we are resuming again.
529
						return;
530
					} else {
531
						// Stopped for any other reasons.  Just remove our temporary one
532
						// since we don't want it to hit later
533
						//
534
						// Note that in Non-stop, we don't cancel a run-to-line when a new
535
						// breakpoint is inserted.  This is because the new breakpoint could
536
						// be for another thread altogether and should not affect the current thread.
537
						IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(getRunToLineActiveOperation().getThreadContext(),
538
								IBreakpointsTargetDMContext.class);
539
540
						fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {getRunToLineActiveOperation().getBreakointId()}),
541
								new DataRequestMonitor<MIInfo>(getExecutor(), null));
542
						setRunToLineActiveOperation(null);
543
					}
544
				}
545
			}
546
		}
547
		
548
		IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
549
		if (e instanceof MISignalEvent && fDisableNextSignalEventDmc.remove(threadDmc)) {			
550
			fSilencedSignalEvent.put(threadDmc, e);
551
552
			// Don't broadcast the stopped event
553
			return;
554
		}
555
556
		IDMEvent<?> event = null;
557
		MIBreakpointDMContext bp = null;
558
		if (e instanceof MIBreakpointHitEvent) {
559
			int bpId = ((MIBreakpointHitEvent)e).getNumber();
560
			IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class);
561
			if (bpsTarget != null && bpId >= 0) {
562
				bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] {bpsTarget}, bpId); 
563
				event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent)e, bp);
564
			}
565
		}
566
		if (event == null) {
567
			event = new SuspendedEvent(e.getDMContext(), e);
568
		}
569
570
		getSession().dispatchEvent(event, getProperties());
571
	}
572
}
(-)src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactoryNS.java (-1 / +4 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2008, 2009 Ericsson and others.
2
 * Copyright (c) 2008, 2011 Ericsson and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 26-31 Link Here
26
	
26
	
27
	@Override
27
	@Override
28
	protected IRunControl createRunControlService(DsfSession session) {
28
	protected IRunControl createRunControlService(DsfSession session) {
29
		if (GDB_7_2_VERSION.compareTo(getVersion()) <= 0) {
30
			return new GDBRunControl_7_2_NS(session);
31
		}
29
		return new GDBRunControl_7_0_NS(session);
32
		return new GDBRunControl_7_0_NS(session);
30
	}
33
	}
31
}
34
}

Return to bug 337893