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 (-141 / +118 lines)
Lines 13-23 Link Here
13
package org.eclipse.cdt.dsf.gdb.service;
13
package org.eclipse.cdt.dsf.gdb.service;
14
14
15
import java.util.HashMap;
15
import java.util.HashMap;
16
import java.util.HashSet;
16
import java.util.Hashtable;
17
import java.util.Hashtable;
17
import java.util.LinkedList;
18
import java.util.LinkedList;
18
import java.util.Map;
19
import java.util.Map;
20
import java.util.Set;
19
21
20
import org.eclipse.cdt.core.IAddress;
22
import org.eclipse.cdt.core.IAddress;
23
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
21
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
24
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
22
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
25
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
23
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
26
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
Lines 43-49 Link Here
43
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
46
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
44
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
47
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
45
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
48
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
46
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
47
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
49
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
48
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
50
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
49
import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent;
51
import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent;
Lines 315-320 Link Here
315
317
316
	private ICommandControlService fConnection;
318
	private ICommandControlService fConnection;
317
	private CommandFactory fCommandFactory;
319
	private CommandFactory fCommandFactory;
320
	private IProcesses fProcessService;
318
	
321
	
319
	private boolean fTerminated = false;
322
	private boolean fTerminated = false;
320
323
Lines 334-350 Link Here
334
	}
337
	}
335
338
336
	/** 
339
	/** 
337
	 * Indicates that the next MIRunning event for this thread should be silenced.
340
	 * Set of threads for which the next MIRunning event should be silenced.
338
	 */
341
	 */
339
	private IMIExecutionDMContext fDisableNextRunningEventDmc;
342
	private Set<IMIExecutionDMContext> fDisableNextRunningEventDmcSet = new HashSet<IMIExecutionDMContext>();
340
	/** 
343
	/** 
341
	 * Indicates that the next MISignal (MIStopped) event for this thread should be silenced.
344
	 * Set of threads for which the next MISignal (MIStopped) event should be silenced.
342
	 */
345
	 */
343
	private IMIExecutionDMContext fDisableNextSignalEventDmc;
346
	private Set<IMIExecutionDMContext> fDisableNextSignalEventDmcSet = new HashSet<IMIExecutionDMContext>();
344
	/** 
347
	/** 
345
	 * Stores the silenced MIStopped event in case we need to use it for a failure.
348
	 * Map that stores the silenced MIStopped event for the specified thread, in case we need to use it for a failure.
346
	 */
349
	 */
347
	private MIStoppedEvent fSilencedSignalEvent;
350
	private Map<IMIExecutionDMContext,MIStoppedEvent> fSilencedSignalEventMap = new HashMap<IMIExecutionDMContext, MIStoppedEvent>();
348
351
349
	/**
352
	/**
350
	 * This variable allows us to know if run control operation
353
	 * This variable allows us to know if run control operation
Lines 379-384 Link Here
379
        	     new Hashtable<String,String>());
382
        	     new Hashtable<String,String>());
380
		fConnection = getServicesTracker().getService(ICommandControlService.class);
383
		fConnection = getServicesTracker().getService(ICommandControlService.class);
381
		fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
384
		fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
385
		fProcessService = getServicesTracker().getService(IProcesses.class);
386
		
382
		getSession().addServiceEventListener(this, null);
387
		getSession().addServiceEventListener(this, null);
383
		rm.done();
388
		rm.done();
384
	}
389
	}
Lines 943-948 Link Here
943
	 * and finally resume that thread..
948
	 * and finally resume that thread..
944
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
949
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
945
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
950
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
951
	 * 
952
 	 * Note that for multi-process, we need to interrupt all processes
953
 	 * that share the same binary before doing a breakpoint operation on any of
954
 	 * those processes.  For simplicity, the logic below interrupts one thread of
955
 	 * every process being debugged, without differentiating on the executable.
956
 	 * Although it may seem wasteful to interrupt all processes when not necessary,
957
 	 * in truth it is not so much; when making a breakpoint operation in Eclipse, that
958
 	 * operation is propagated to all processes anyway, so they will all need to be
959
 	 * interrupted.  The case where we are wasteful is when we start or stop debugging
960
 	 * a process (starting a process, attaching to one, auto-attaching to one,
961
 	 * detaching from one, terminating one); in those cases, we only want to apply the
962
 	 * breakpoint operation to that one process and any other using the same binary.
963
 	 * The wastefulness is not such a big deal for that case, and is worth the simpler
964
 	 * solution.
965
 	 * Of course, it can always be improved later on. 
966
	 * See http://bugs.eclipse.org/337893
946
	 * ******************************************************************************/
967
	 * ******************************************************************************/
947
	
968
	
948
	/**
969
	/**
Lines 962-973 Link Here
962
		}
983
		}
963
	};
984
	};
964
	
985
	
965
	// Keep track of if the target was available or not when we started the operation
986
	// The set of threads that we will actually be suspended to make the containers suspended.
966
	private boolean fTargetAvailable;
987
	private Set<IMIExecutionDMContext> fExecutionDmcToSuspendSet = new HashSet<IMIExecutionDMContext>();
967
	// The container that needs to be suspended to perform the steps of the operation
968
	private IContainerDMContext fContainerDmcToSuspend;
969
	// The thread that we will actually suspend to make the container suspended.
970
	private IMIExecutionDMContext fExecutionDmcToSuspend;
971
988
972
	// Do we currently have an executeWithTargetAvailable() operation ongoing?
989
	// Do we currently have an executeWithTargetAvailable() operation ongoing?
973
	private boolean fOngoingOperation;
990
	private boolean fOngoingOperation;
Lines 981-987 Link Here
981
	// allow the global sequence to continue.
998
	// allow the global sequence to continue.
982
	// Note that we couldn't use a CountingRequestMonitor because that type of RM
999
	// Note that we couldn't use a CountingRequestMonitor because that type of RM
983
	// needs to know in advance how many subRms it will track; the MultiRM allows us
1000
	// needs to know in advance how many subRms it will track; the MultiRM allows us
984
	// to receive more steps to execute continuously, and be able to upate the MultiRM.
1001
	// to receive more steps to execute continuously, and be able to update the MultiRM.
985
	private MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
1002
	private MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
986
	// The number of batches of steps that are still being executing for potentially
1003
	// The number of batches of steps that are still being executing for potentially
987
	// concurrent executeWithTargetAvailable() operations.
1004
	// concurrent executeWithTargetAvailable() operations.
Lines 991-1037 Link Here
991
	// Queue of executeWithTargetAvailable() operations that need to be processed.
1008
	// Queue of executeWithTargetAvailable() operations that need to be processed.
992
	private LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
1009
	private LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
993
	
1010
	
994
	/**
995
	 * Returns whether the target is available to perform operations
996
	 * @since 4.0
997
	 */
998
	protected boolean isTargetAvailable() {
999
		return fTargetAvailable;
1000
	}
1001
1002
	/** @since 4.0 */
1003
	protected void setTargetAvailable(boolean available) {
1004
		fTargetAvailable = available;
1005
	}
1006
1007
	/**
1008
	 * Returns the container context that needs to be suspended to perform the
1009
	 * required operation.
1010
	 * @since 4.0
1011
	 */
1012
	protected IContainerDMContext getContainerToSuspend() {
1013
		return fContainerDmcToSuspend;
1014
	}
1015
1016
	/** @since 4.0 */
1017
	protected void setContainerToSuspend(IContainerDMContext context) {
1018
		fContainerDmcToSuspend = context;
1019
	}
1020
1021
	/**
1022
	 * Returns the container context that needs to be suspended to perform the
1023
	 * required operation.
1024
	 * @since 4.0
1025
	 */
1026
	protected IMIExecutionDMContext getExecutionToSuspend() {
1027
		return fExecutionDmcToSuspend;
1028
	}
1029
1030
	/** @since 4.0 */
1031
	protected void setExecutionToSuspend(IMIExecutionDMContext context) {
1032
		fExecutionDmcToSuspend = context;
1033
	}
1034
1035
	/** 
1011
	/** 
1036
	 * Returns whether there is currently an ExecuteWithTargetAvailable() operation ongoing. 
1012
	 * Returns whether there is currently an ExecuteWithTargetAvailable() operation ongoing. 
1037
	 * @since 4.0 
1013
	 * @since 4.0 
Lines 1191-1198 Link Here
1191
	
1167
	
1192
	
1168
	
1193
	/**
1169
	/**
1194
	 * This part of the sequence verifies if the execution context of interest
1170
	 * This part of the sequence looks for all threads that will need to be suspended.
1195
	 * is suspended or not.
1196
	 * @since 3.0
1171
	 * @since 3.0
1197
	 */
1172
	 */
1198
	protected class IsTargetAvailableStep extends Sequence.Step {
1173
	protected class IsTargetAvailableStep extends Sequence.Step {
Lines 1202-1287 Link Here
1202
			fCtx = ctx;
1177
			fCtx = ctx;
1203
		}
1178
		}
1204
		
1179
		
1180
		private void getThreadToSuspend(IContainerDMContext containerDmc, final RequestMonitor rm) {
1181
			// If the process is running, get its first thread which we will need to suspend
1182
			fProcessService.getProcessesBeingDebugged(
1183
					containerDmc,
1184
					new DataRequestMonitor<IDMContext[]>(ImmediateExecutor.getInstance(), rm) {
1185
						@Override
1186
						protected void handleSuccess() {
1187
							IDMContext[] threads = getData();
1188
							if (threads != null && threads.length > 0) {
1189
								// Choose the first thread as the one to suspend
1190
								fExecutionDmcToSuspendSet.add((IMIExecutionDMContext)threads[0]);
1191
							}
1192
							rm.done();
1193
						}
1194
					});
1195
		}
1196
1205
		@Override
1197
		@Override
1206
		public void execute(final RequestMonitor rm) {
1198
		public void execute(final RequestMonitor rm) {
1207
			// In non-stop, for single address-space multi-process,
1199
			// Clear any old data before we start
1208
			// we need any one of the processes to be suspended.
1200
			fExecutionDmcToSuspendSet.clear();
1209
			// Note that even if we can obtain a container dmc from fCtx
1201
			
1210
			// we will have issues because that context is probably not
1202
			// Get all processes being debugged to see which one are running
1211
			// fully formed (missing groupId and procId).  So, we just
1203
			// and need to be interrupted
1212
			// make it easy on ourselves and fetch the containers directly
1204
			fProcessService.getProcessesBeingDebugged(
1213
			ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
1205
					fConnection.getContext(),
1214
			IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1206
					new DataRequestMonitor<IDMContext[]>(ImmediateExecutor.getInstance(), rm) {
1215
			processControl.getProcessesBeingDebugged(
1216
					controlDmc,
1217
					new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
1218
						@Override
1207
						@Override
1219
						protected void handleSuccess() {
1208
						protected void handleSuccess() {
1220
							assert getData() != null;
1209
							assert getData() != null;
1221
							
1210
1222
							if (getData().length == 0) {
1211
							if (getData().length == 0) {
1223
								// Happens at startup, starting with GDB 7.0.
1212
								// Happens at startup, starting with GDB 7.0.
1224
								// This means the target is available
1213
								// This means the target is available.  Nothing to do.
1225
								fTargetAvailable = true;
1214
								rm.done();
1226
							} else {
1215
							} else {
1227
								fTargetAvailable = false;
1216
								// Go through every process to see if it is running.
1228
								// Choose the first process as the one to suspend if needed
1217
								// If it is running, get its first thread so we can interrupt it.
1229
								fContainerDmcToSuspend = (IContainerDMContext)(getData()[0]);
1218
								CountingRequestMonitor crm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), rm);
1230
								for (IDMContext containerDmc : getData()) {
1219
								
1231
									if (isSuspended((IContainerDMContext)containerDmc)) {
1220
								int numThreadsToSuspend = 0;
1232
										fTargetAvailable = true;
1221
								for (IDMContext dmc : getData()) {
1233
										break;
1222
									IContainerDMContext containerDmc = (IContainerDMContext)dmc;
1223
									if (!isSuspended(containerDmc)) {
1224
										numThreadsToSuspend++;
1225
										getThreadToSuspend(containerDmc, crm);
1234
									}
1226
									}
1235
								}
1227
								}
1228
								crm.setDoneCount(numThreadsToSuspend);
1236
							}
1229
							}
1237
							rm.done();
1238
						}
1230
						}
1239
					});
1231
					});
1240
		}
1232
		}
1241
	};
1233
	};
1242
1234
1243
	/**
1235
	/**
1244
	 * If the execution context of interest is not suspended, this step
1236
	 * Suspended all the threads we have selected.
1245
	 * will interrupt it.
1246
	 * @since 3.0
1237
	 * @since 3.0
1247
	 */
1238
	 */
1248
	protected class MakeTargetAvailableStep extends Sequence.Step {
1239
	protected class MakeTargetAvailableStep extends Sequence.Step {
1249
		@Override
1240
		@Override
1250
		public void execute(final RequestMonitor rm) {
1241
		public void execute(final RequestMonitor rm) {
1251
			if (!isTargetAvailable()) {
1242
			// Interrupt every first thread of the running processes
1252
				// Instead of suspending the entire process, let's find its first thread and use that
1243
			CountingRequestMonitor crm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), rm);
1253
				IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1244
			crm.setDoneCount(fExecutionDmcToSuspendSet.size());
1254
				processControl.getProcessesBeingDebugged(
1245
			
1255
						fContainerDmcToSuspend,
1246
			for (final IMIExecutionDMContext thread : fExecutionDmcToSuspendSet) {
1256
						new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
1247
				assert !fDisableNextRunningEventDmcSet.contains(thread);
1257
							@Override
1248
				assert !fDisableNextSignalEventDmcSet.contains(thread);
1258
							protected void handleSuccess() {
1249
1259
								assert getData() != null;
1250
				// Don't broadcast the next stopped signal event
1260
								assert getData().length > 0;
1251
				fDisableNextSignalEventDmcSet.add(thread);
1261
							
1252
1262
								fExecutionDmcToSuspend = (IMIExecutionDMContext)getData()[0];
1253
				suspend(thread,
1263
							
1254
						new RequestMonitor(ImmediateExecutor.getInstance(), crm) {
1264
								assert fDisableNextRunningEventDmc == null;
1255
					@Override
1265
								assert fDisableNextSignalEventDmc == null;
1256
					protected void handleFailure() {
1266
								
1257
						// We weren't able to suspend, so abort the operation
1267
								// Don't broadcast the next stopped signal event
1258
						fDisableNextSignalEventDmcSet.remove(thread);
1268
								fDisableNextSignalEventDmc = fExecutionDmcToSuspend;
1259
						super.handleFailure();
1269
								
1260
					};
1270
								suspend(fExecutionDmcToSuspend,
1261
				});
1271
										new RequestMonitor(getExecutor(), rm) {
1272
									@Override
1273
									protected void handleFailure() {
1274
										// We weren't able to suspend, so abort the operation
1275
										fDisableNextSignalEventDmc = null;
1276
										super.handleFailure();
1277
									};
1278
								});
1279
							}
1280
						});
1281
			} else {
1282
				rm.done();
1283
			}
1262
			}
1284
		}
1263
		}
1264
1285
		@Override
1265
		@Override
1286
		public void rollBack(RequestMonitor rm) {
1266
		public void rollBack(RequestMonitor rm) {
1287
		    Sequence.Step restoreStep = new RestoreTargetStateStep();
1267
		    Sequence.Step restoreStep = new RestoreTargetStateStep();
Lines 1333-1378 Link Here
1333
	protected class RestoreTargetStateStep extends Sequence.Step {
1313
	protected class RestoreTargetStateStep extends Sequence.Step {
1334
		@Override
1314
		@Override
1335
		public void execute(final RequestMonitor rm) {
1315
		public void execute(final RequestMonitor rm) {
1336
			if (!isTargetAvailable()) {
1316
			// Resume every thread we had interrupted
1337
				assert fDisableNextRunningEventDmc == null;
1317
			CountingRequestMonitor crm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), rm);
1338
				fDisableNextRunningEventDmc = fExecutionDmcToSuspend;
1318
			crm.setDoneCount(fExecutionDmcToSuspendSet.size());
1339
				
1319
			
1320
			for (final IMIExecutionDMContext thread : fExecutionDmcToSuspendSet) {
1321
1322
				assert !fDisableNextRunningEventDmcSet.contains(thread);
1323
				fDisableNextRunningEventDmcSet.add(thread);
1324
1340
				// Can't use the resume() call because we 'silently' stopped
1325
				// Can't use the resume() call because we 'silently' stopped
1341
				// so resume() will not know we are actually stopped
1326
				// so resume() will not know we are actually stopped
1342
				fConnection.queueCommand(
1327
				fConnection.queueCommand(
1343
						fCommandFactory.createMIExecContinue(fExecutionDmcToSuspend),
1328
						fCommandFactory.createMIExecContinue(thread),
1344
						new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
1329
						new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), crm) {
1345
							@Override
1330
							@Override
1346
							protected void handleSuccess() {
1331
							protected void handleSuccess() {
1347
								fSilencedSignalEvent = null;
1332
								fSilencedSignalEventMap.remove(thread);
1348
								super.handleSuccess();
1333
								super.handleSuccess();
1349
							}
1334
							}
1350
1335
1351
							@Override
1336
							@Override
1352
							protected void handleFailure() {
1337
							protected void handleFailure() {
1353
								// Darn, we're unable to restart the target.  Must cleanup!
1338
								// Darn, we're unable to restart the target.  Must cleanup!
1354
								fDisableNextRunningEventDmc = null;
1339
								fDisableNextRunningEventDmcSet.remove(thread);
1355
								
1340
1356
								// We must also sent the Stopped event that we had kept silent
1341
								// We must also sent the Stopped event that we had kept silent
1357
								if (fSilencedSignalEvent != null) {
1342
								MIStoppedEvent event = fSilencedSignalEventMap.remove(thread);
1358
									eventDispatched(fSilencedSignalEvent);
1343
								if (event != null) {
1359
									fSilencedSignalEvent = null;
1344
									eventDispatched(event);
1360
								} else {
1345
								} else {
1361
									// Maybe the stopped event didn't arrive yet.
1346
									// Maybe the stopped event didn't arrive yet.
1362
									// We don't want to silence it anymore
1347
									// We don't want to silence it anymore
1363
									fDisableNextSignalEventDmc = null;
1348
									fDisableNextSignalEventDmcSet.remove(thread);
1364
								}
1349
								}
1365
1350
1366
								super.handleFailure();
1351
								super.handleFailure();
1367
							}
1352
							}
1368
						});
1353
						});
1369
1370
			} else {
1371
				// We didn't suspend the thread, so we don't need to resume it
1372
				rm.done();
1373
			}
1354
			}
1374
		}
1355
		}
1375
	 };
1356
	};
1376
1357
1377
	 /* ******************************************************************************
1358
	 /* ******************************************************************************
1378
	  * End of section to support operations even when the target is unavailable.
1359
	  * End of section to support operations even when the target is unavailable.
Lines 1388-1401 Link Here
1388
     */
1369
     */
1389
	@DsfServiceEventHandler
1370
	@DsfServiceEventHandler
1390
	public void eventDispatched(final MIRunningEvent e) {
1371
	public void eventDispatched(final MIRunningEvent e) {
1391
		if (fDisableNextRunningEventDmc != null &&
1372
		if (fDisableNextRunningEventDmcSet.remove(e.getDMContext())) {
1392
			fDisableNextRunningEventDmc.equals(e.getDMContext())) {
1393
1394
			fDisableNextRunningEventDmc = null;
1395
			
1396
			// Don't broadcast the running event
1373
			// Don't broadcast the running event
1397
			return;
1374
			return;
1398
		}
1375
		}
1376
1399
        getSession().dispatchEvent(new ResumedEvent(e.getDMContext(), e), getProperties());
1377
        getSession().dispatchEvent(new ResumedEvent(e.getDMContext(), e), getProperties());
1400
	}
1378
	}
1401
1379
Lines 1457-1467 Link Here
1457
    			}
1435
    			}
1458
    		}
1436
    		}
1459
    	}
1437
    	}
1460
		if (fDisableNextSignalEventDmc != null && e instanceof MISignalEvent &&
1438
    	
1461
			fDisableNextSignalEventDmc.equals(e.getDMContext())) {
1439
		IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
1462
			
1440
		if (e instanceof MISignalEvent && fDisableNextSignalEventDmcSet.remove(threadDmc)) {			
1463
			fDisableNextSignalEventDmc = null;
1441
			fSilencedSignalEventMap.put(threadDmc, e);
1464
			fSilencedSignalEvent = e;
1465
1442
1466
			// Don't broadcast the stopped event
1443
			// Don't broadcast the stopped event
1467
			return;
1444
			return;
(-)src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_2_NS.java (-498 / +10 lines)
Lines 1-62 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2011 Wind River Systems and others.
2
 * Copyright (c) 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
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
7
 * 
8
 * Contributors:
8
 * Contributors:
9
 *     Wind River Systems - initial API and implementation
9
 *     Ericsson - initial API and implementation
10
 *     Ericsson		      - Support for multi-process for Linux, GDB 7.2
11
 *******************************************************************************/
10
 *******************************************************************************/
12
11
13
package org.eclipse.cdt.dsf.gdb.service;
12
package org.eclipse.cdt.dsf.gdb.service;
14
13
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Hashtable;
14
import java.util.Hashtable;
18
import java.util.LinkedList;
19
import java.util.Map;
20
import java.util.Set;
21
15
22
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
16
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
23
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
17
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
24
import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
25
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
18
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;
19
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;
20
import org.eclipse.cdt.dsf.debug.service.IRunControl;
34
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
21
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
35
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
22
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.gdb.internal.GdbPlugin;
23
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
38
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
24
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
39
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
25
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
40
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
26
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
41
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
27
import org.eclipse.cdt.dsf.mi.service.IMIRunControl;
42
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext;
43
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
28
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
44
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
45
import org.eclipse.cdt.dsf.mi.service.command.events.MIRunningEvent;
46
import org.eclipse.cdt.dsf.mi.service.command.events.MISignalEvent;
47
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
48
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
29
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
49
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
50
import org.eclipse.cdt.dsf.service.DsfSession;
30
import org.eclipse.cdt.dsf.service.DsfSession;
51
import org.eclipse.core.runtime.IStatus;
31
import org.eclipse.core.runtime.IStatus;
52
import org.eclipse.core.runtime.Status;
32
import org.eclipse.core.runtime.Status;
53
33
54
/**
34
/**
55
 * Version of the non-stop runControl for GDB 7.2
35
 * Version of the non-stop runControl for GDB 7.2.
56
 * This class handles multi-process for Linux which requires
36
 * 
57
 * us to interrupt different processes at the same time to be
58
 * able to set breakpoints.
59
 * This class was created for bug 337893
60
 * @since 4.0
37
 * @since 4.0
61
 */
38
 */
62
public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS
39
public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS
Lines 65-85 Link Here
65
	private ICommandControlService fConnection;
42
	private ICommandControlService fConnection;
66
	private CommandFactory fCommandFactory;
43
	private CommandFactory fCommandFactory;
67
44
68
	/** 
69
	 * Set of threads for which the next MIRunning event should be silenced.
70
	 */
71
	private Set<IMIExecutionDMContext> fDisableNextRunningEventDmc = new HashSet<IMIExecutionDMContext>();
72
	/** 
73
	 * Set of threads for which the next MISignal (MIStopped) event should be silenced.
74
	 */
75
	private Set<IMIExecutionDMContext> fDisableNextSignalEventDmc = new HashSet<IMIExecutionDMContext>();
76
	/** 
77
	 * Map that stores the silenced MIStopped event for the specified thread, in case we need to use it for a failure.
78
	 */
79
	private Map<IMIExecutionDMContext,MIStoppedEvent> fSilencedSignalEvent = new HashMap<IMIExecutionDMContext, MIStoppedEvent>();
80
81
	private Map<IDMContext, ExecuteWithTargetAvailableOperation> execWithTargetAvailMap = new HashMap<IDMContext, ExecuteWithTargetAvailableOperation>();
82
83
	///////////////////////////////////////////////////////////////////////////
45
	///////////////////////////////////////////////////////////////////////////
84
	// Initialization and shutdown
46
	// Initialization and shutdown
85
	///////////////////////////////////////////////////////////////////////////
47
	///////////////////////////////////////////////////////////////////////////
Lines 119-124 Link Here
119
		super.shutdown(rm);
81
		super.shutdown(rm);
120
	}
82
	}
121
83
84
	// Now that the flag --thread-group is globally supported
85
	// by GDB 7.2, we have to make sure not to use it twice.
86
	// Bug 340262
122
	@Override
87
	@Override
123
	public void suspend(final IExecutionDMContext context, final RequestMonitor rm) {
88
	public void suspend(final IExecutionDMContext context, final RequestMonitor rm) {
124
		assert context != null;
89
		assert context != null;
Lines 145-150 Link Here
145
		});
110
		});
146
	}
111
	}
147
112
113
	// Now that the flag --thread-group is globally supported
114
	// by GDB 7.2, we have to make sure not to use it twice.
115
	// Bug 340262
148
	@Override
116
	@Override
149
	public void resume(final IExecutionDMContext context, final RequestMonitor rm) {
117
	public void resume(final IExecutionDMContext context, final RequestMonitor rm) {
150
		assert context != null;
118
		assert context != null;
Lines 201-660 Link Here
201
	private void doResumeContainer(IMIContainerDMContext context, final RequestMonitor rm) {
169
	private void doResumeContainer(IMIContainerDMContext context, final RequestMonitor rm) {
202
		fConnection.queueCommand(fCommandFactory.createMIExecContinue(context), new DataRequestMonitor<MIInfo>(getExecutor(), rm));
170
		fConnection.queueCommand(fCommandFactory.createMIExecContinue(context), new DataRequestMonitor<MIInfo>(getExecutor(), rm));
203
	}
171
	}
204
	
205
	@Override
206
	public void executeWithTargetAvailable(IDMContext ctx, final Sequence.Step[] steps, final RequestMonitor rm) {
207
		ExecuteWithTargetAvailableOperation operation = execWithTargetAvailMap.get(ctx);
208
		if (operation == null) {
209
			operation = new ExecuteWithTargetAvailableOperation(ctx);
210
			execWithTargetAvailMap.put(ctx, operation);
211
		}
212
		operation.executeWithTargetAvailable(steps, rm);
213
	}
214
215
	/* ******************************************************************************
216
	 * Section to support making operations even when the target is unavailable.
217
	 *
218
	 * Although one would expect to be able to make commands all the time when
219
	 * in non-stop mode, it turns out that GDB has trouble with some commands
220
	 * like breakpoints.  The safe way to do it is to make sure we have at least
221
	 * one thread suspended.
222
	 * 
223
	 * Basically, we must make sure one thread is suspended before making
224
	 * certain operations (currently breakpoints).  If that is not the case, we must 
225
	 * first suspend one thread, then perform the specified operations,
226
	 * and finally resume that thread..
227
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
228
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
229
	 * 
230
	 * Note that for multi-process on Linux, the correct container must be suspended for 
231
     * the breakpoint to be inserted on that container.  This means that we need to be
232
     * able to interrupt multiple processes at the same time to insert a breakpoint
233
     * in each one of them.
234
     * See http://bugs.eclipse.org/337893
235
	 * ******************************************************************************/
236
237
	protected class ExecuteWithTargetAvailableOperation {
238
		/**
239
		 * Utility class to store the parameters of the executeWithTargetAvailable() operations.
240
		 */
241
		public class TargetAvailableOperationInfo {
242
			public Sequence.Step[] steps;
243
			public RequestMonitor rm;
244
245
			public TargetAvailableOperationInfo(Step[] steps, RequestMonitor rm) {
246
				super();
247
				this.steps = steps;
248
				this.rm = rm;
249
			}
250
		};
251
252
		public IDMContext fCtx;
253
		// Keep track of if the target was available or not when we started the operation
254
		public boolean fTargetAvailable;
255
		// The container that needs to be suspended to perform the steps of the operation
256
		public IContainerDMContext fContainerDmcToSuspend;
257
		// The thread that we will actually suspend to make the container suspended.
258
		public IMIExecutionDMContext fExecutionDmcToSuspend;
259
260
		// Do we currently have an executeWithTargetAvailable() operation ongoing?
261
		public boolean fOngoingOperation;
262
		// Are we currently executing steps passed into executeWithTargetAvailable()?
263
		// This allows us to know if we can add more steps to execute or if we missed
264
		// our opportunity
265
		public boolean fCurrentlyExecutingSteps;
266
267
		// MultiRequestMonitor that allows us to track all the different steps we are
268
		// executing.  Once all steps are executed, we can complete this MultiRM and
269
		// allow the global sequence to continue.
270
		// Note that we couldn't use a CountingRequestMonitor because that type of RM
271
		// needs to know in advance how many subRms it will track; the MultiRM allows us
272
		// to receive more steps to execute continuously, and be able to upate the MultiRM.
273
		public MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
274
		// The number of batches of steps that are still being executing for potentially
275
		// concurrent executeWithTargetAvailable() operations.
276
		// Once this gets to zero, we know we have executed all the steps we were aware of
277
		// and we can complete the operation.
278
		public int fNumStepsStillExecuting;
279
		// Queue of executeWithTargetAvailable() operations that need to be processed.
280
		public LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
281
282
		public ExecuteWithTargetAvailableOperation(IDMContext ctx) {
283
			fCtx = ctx;
284
		}
285
286
		/**
287
		 * This method takes care of executing a batch of steps that were passed to
288
		 * ExecuteWithTargetAvailable().  The method is used to track the progress
289
		 * of all these batches of steps, so that we know exactly when all of them
290
		 * have been completed and the global sequence can be completed.
291
		 */
292
		protected void executeSteps(final TargetAvailableOperationInfo info) {
293
			fNumStepsStillExecuting++;
294
295
			// This RM propagates any error to the original rm of the actual steps.
296
			// Even in case of errors for these steps, we want to continue the overall sequence
297
			RequestMonitor stepsRm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
298
				@Override
299
				protected void handleCompleted() {
300
					info.rm.setStatus(getStatus());
301
					// It is important to call rm.done() right away.
302
					// This is because some other operation we are performing might be waiting
303
					// for this one to be done.  If we try to wait for the entire sequence to be
304
					// done, then we will never finish because one monitor will never show as
305
					// done, waiting for the second one.
306
					info.rm.done();
307
308
					fExecuteQueuedOpsStepMonitor.requestMonitorDone(this);
309
					fNumStepsStillExecuting--;
310
					if (fNumStepsStillExecuting == 0) {
311
						fExecuteQueuedOpsStepMonitor.doneAdding();
312
					}
313
				}
314
			};
315
316
			fExecuteQueuedOpsStepMonitor.add(stepsRm);
317
318
			getExecutor().execute(new Sequence(getExecutor(), stepsRm) {
319
				@Override public Step[] getSteps() { return info.steps; }
320
			});	
321
		}
322
323
		public void executeWithTargetAvailable(final Sequence.Step[] steps, final RequestMonitor rm) {
324
			if (!fOngoingOperation) {
325
				// We are the first operation of this kind currently requested
326
				// so we need to start the sequence
327
				fOngoingOperation = true;
328
329
				// We always go through our queue, even if we only have a single call to this method
330
				fOperationsPending.add(new TargetAvailableOperationInfo(steps, rm));
331
332
				// Steps that need to be executed to perform the operation
333
				final Step[] sequenceSteps = new Step[] {
334
						new IsTargetAvailableStep(),
335
						new MakeTargetAvailableStep(),
336
						new ExecuteQueuedOperationsStep(),
337
						new RestoreTargetStateStep(),
338
				};
339
340
				// Once all the sequence is completed, we need to see if we have received
341
				// another request that we now need to process
342
				RequestMonitor sequenceCompletedRm = new RequestMonitor(getExecutor(), null) {
343
					@Override
344
					protected void handleCompleted() {
345
						fOngoingOperation = false;
346
347
						if (fOperationsPending.size() > 0) {
348
							// Darn, more operations came in.  Trigger their processing
349
							// by calling executeWithTargetAvailable() on the last one
350
							TargetAvailableOperationInfo info = fOperationsPending.removeLast();
351
							executeWithTargetAvailable(info.steps, info.rm);
352
						} else {
353
							execWithTargetAvailMap.remove(fCtx);
354
						}
355
						// no other rm.done() needs to be called, they have all been handled already
356
					}
357
				};
358
359
				getExecutor().execute(new Sequence(getExecutor(), sequenceCompletedRm) {
360
					@Override public Step[] getSteps() { return sequenceSteps; }
361
				});
362
			} else {
363
				// We are currently already executing such an operation
364
				// If we are still in the process of executing steps, let's include this new set of steps.
365
				// This is important because some steps may depend on these new ones.
366
				if (fCurrentlyExecutingSteps) {
367
					executeSteps(new TargetAvailableOperationInfo(steps, rm));
368
				} else {
369
					// Too late to execute the new steps, so queue them for later
370
					fOperationsPending.add(new TargetAvailableOperationInfo(steps, rm));
371
				}
372
			}
373
		}
374
375
376
		/**
377
		 * This part of the sequence verifies if the execution context of interest
378
		 * is suspended or not.
379
		 */
380
		public class IsTargetAvailableStep extends Sequence.Step {
381
			@Override
382
			public void execute(final RequestMonitor rm) {
383
				fContainerDmcToSuspend = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
384
				if (fContainerDmcToSuspend != null) {
385
					fTargetAvailable = isSuspended(fContainerDmcToSuspend);
386
					rm.done();
387
					return;
388
				}
389
390
				// If we get here, we have to get the list of processes to know if any of
391
				// them is suspended.
392
				ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
393
				IProcesses processControl = getServicesTracker().getService(IProcesses.class);
394
				processControl.getProcessesBeingDebugged(
395
						controlDmc,
396
						new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
397
							@Override
398
							protected void handleSuccess() {
399
								assert getData() != null;
400
401
								if (getData().length == 0) {
402
									// Happens at startup, starting with GDB 7.0.
403
									// This means the target is available
404
									fTargetAvailable = true;
405
								} else {
406
									fTargetAvailable = false;
407
									// Choose the first process as the one to suspend if needed
408
									fContainerDmcToSuspend = (IContainerDMContext)(getData()[0]);
409
									for (IDMContext containerDmc : getData()) {
410
										if (isSuspended((IContainerDMContext)containerDmc)) {
411
											fTargetAvailable = true;
412
											break;
413
										}
414
									}
415
								}
416
								rm.done();
417
							}
418
						});
419
			}
420
		};
421
422
		/**
423
		 * If the execution context of interest is not suspended, this step
424
		 * will interrupt it.
425
		 */
426
		public class MakeTargetAvailableStep extends Sequence.Step {
427
			@Override
428
			public void execute(final RequestMonitor rm) {
429
				if (!fTargetAvailable) {
430
					// Instead of suspending the entire process, let's find its first thread and use that
431
					IProcesses processControl = getServicesTracker().getService(IProcesses.class);
432
					processControl.getProcessesBeingDebugged(
433
							fContainerDmcToSuspend,
434
							new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
435
								@Override
436
								protected void handleSuccess() {
437
									assert getData() != null;
438
									assert getData().length > 0;
439
440
									fExecutionDmcToSuspend = (IMIExecutionDMContext)getData()[0];
441
442
									assert !fDisableNextRunningEventDmc.contains(fExecutionDmcToSuspend);
443
									assert !fDisableNextSignalEventDmc.contains(fExecutionDmcToSuspend);
444
445
									// Don't broadcast the next stopped signal event
446
									fDisableNextSignalEventDmc.add(fExecutionDmcToSuspend);
447
448
									suspend(fExecutionDmcToSuspend,
449
											new RequestMonitor(getExecutor(), rm) {
450
										@Override
451
										protected void handleFailure() {
452
											// We weren't able to suspend, so abort the operation
453
											fDisableNextSignalEventDmc.remove(fExecutionDmcToSuspend);
454
											super.handleFailure();
455
										};
456
									});
457
								}
458
							});
459
				} else {
460
					rm.done();
461
				}
462
			}
463
			@Override
464
			public void rollBack(RequestMonitor rm) {
465
				Sequence.Step restoreStep = new RestoreTargetStateStep();
466
				restoreStep.execute(rm);
467
			}
468
		};
469
470
		/**
471
		 * This step of the sequence takes care of executing all the steps that
472
		 * were passed to ExecuteWithTargetAvailable().
473
		 */
474
		public class ExecuteQueuedOperationsStep extends Sequence.Step {
475
			@Override
476
			public void execute(final RequestMonitor rm) {
477
				fCurrentlyExecutingSteps = true;
478
479
				// It is important to use an ImmediateExecutor for this RM, to make sure we don't risk getting a new
480
				// call to ExecuteWithTargetAvailable() when we just finished executing the steps.
481
				fExecuteQueuedOpsStepMonitor = new MultiRequestMonitor<RequestMonitor>(ImmediateExecutor.getInstance(), rm) {
482
					@Override
483
					protected void handleCompleted() {
484
						assert fOperationsPending.size() == 0;
485
486
						// We don't handle errors here.  Instead, we have already propagated any
487
						// errors to each rm for each set of steps
488
489
						fCurrentlyExecutingSteps = false;
490
						// Continue the sequence
491
						rm.done();
492
					}
493
				};
494
				// Tell the RM that we need to confirm when we are done adding sub-rms
495
				fExecuteQueuedOpsStepMonitor.requireDoneAdding();
496
497
				// All pending operations are independent of each other so we can
498
				// run them concurrently.
499
				while (fOperationsPending.size() > 0) {
500
					executeSteps(fOperationsPending.poll());				
501
				}
502
			}
503
		};
504
505
		/**
506
		 * If the sequence had to interrupt the execution context of interest,
507
		 * this step will resume it again to reach the same state as when we started.
508
		 */
509
		public class RestoreTargetStateStep extends Sequence.Step {
510
			@Override
511
			public void execute(final RequestMonitor rm) {
512
				if (!fTargetAvailable) {
513
					assert !fDisableNextRunningEventDmc.contains(fExecutionDmcToSuspend);
514
					fDisableNextRunningEventDmc.add(fExecutionDmcToSuspend);
515
516
					// Can't use the resume() call because we 'silently' stopped
517
					// so resume() will not know we are actually stopped
518
					fConnection.queueCommand(
519
							fCommandFactory.createMIExecContinue(fExecutionDmcToSuspend),
520
							new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
521
								@Override
522
								protected void handleSuccess() {
523
									fSilencedSignalEvent.remove(fExecutionDmcToSuspend);
524
									super.handleSuccess();
525
								}
526
527
								@Override
528
								protected void handleFailure() {
529
									// Darn, we're unable to restart the target.  Must cleanup!
530
									fDisableNextRunningEventDmc.remove(fExecutionDmcToSuspend);
531
532
									// We must also sent the Stopped event that we had kept silent
533
									MIStoppedEvent event = fSilencedSignalEvent.remove(fExecutionDmcToSuspend);
534
									if (event != null) {
535
										eventDispatched(event);
536
									} else {
537
										// Maybe the stopped event didn't arrive yet.
538
										// We don't want to silence it anymore
539
										fDisableNextSignalEventDmc.remove(fExecutionDmcToSuspend);
540
									}
541
542
									super.handleFailure();
543
								}
544
							});
545
546
				} else {
547
					// We didn't suspend the thread, so we don't need to resume it
548
					rm.done();
549
				}
550
			}
551
		};
552
553
	}
554
	/* ******************************************************************************
555
	 * End of section to support operations even when the target is unavailable.
556
	 * ******************************************************************************/
557
558
	///////////////////////////////////////////////////////////////////////////
559
	// Event handlers
560
	///////////////////////////////////////////////////////////////////////////
561
562
	/**
563
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
564
	 * @noreference This method is not intended to be referenced by clients.
565
	 */
566
	@Override
567
	@DsfServiceEventHandler
568
	public void eventDispatched(final MIRunningEvent e) {
569
		if (fDisableNextRunningEventDmc.remove(e.getDMContext())) {
570
			// Don't broadcast the running event
571
			return;
572
		}
573
        getSession().dispatchEvent(new ResumedEvent(e.getDMContext(), e), getProperties());
574
	}
575
576
	/**
577
	 * @nooverride This method is not intended to be re-implemented or extended by clients.
578
	 * @noreference This method is not intended to be referenced by clients.
579
	 */
580
	@Override
581
	@DsfServiceEventHandler
582
	public void eventDispatched(final MIStoppedEvent e) {
583
		if (getRunToLineActiveOperation() != null) {
584
			// First check if it is the right thread that stopped
585
			IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
586
			if (getRunToLineActiveOperation().getThreadContext().equals(threadDmc)) {
587
				int bpId = 0;
588
				if (e instanceof MIBreakpointHitEvent) {
589
					bpId = ((MIBreakpointHitEvent)e).getNumber();
590
				}
591
				String fileLocation = e.getFrame().getFile() + ":" + e.getFrame().getLine();  //$NON-NLS-1$
592
				String addrLocation = e.getFrame().getAddress();
593
				// Here we check three different things to see if we are stopped at the right place
594
				// 1- The actual location in the file.  But this does not work for breakpoints that
595
				//    were set on non-executable lines
596
				// 2- The address where the breakpoint was set.  But this does not work for breakpoints
597
				//    that have multiple addresses (GDB returns <MULTIPLE>.)  I think that is for multi-process
598
				// 3- The breakpoint id that was hit.  But this does not work if another breakpoint
599
				//    was also set on the same line because GDB may return that breakpoint as being hit.
600
				//
601
				// So this works for the large majority of cases.  The case that won't work is when the user
602
				// does a runToLine to a line that is non-executable AND has another breakpoint AND
603
				// has multiple addresses for the breakpoint.  I'm mean, come on!
604
				if (fileLocation.equals(getRunToLineActiveOperation().getFileLocation()) ||
605
						addrLocation.equals(getRunToLineActiveOperation().getAddrLocation()) ||
606
						bpId == getRunToLineActiveOperation().getBreakointId()) {
607
					// We stopped at the right place.  All is well.
608
					setRunToLineActiveOperation(null);
609
				} else {
610
					// The right thread stopped but not at the right place yet
611
					if (getRunToLineActiveOperation().shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
612
						fConnection.queueCommand(
613
								fCommandFactory.createMIExecContinue(getRunToLineActiveOperation().getThreadContext()),
614
								new DataRequestMonitor<MIInfo>(getExecutor(), null));
615
616
						// Don't send the stop event since we are resuming again.
617
						return;
618
					} else {
619
						// Stopped for any other reasons.  Just remove our temporary one
620
						// since we don't want it to hit later
621
						//
622
						// Note that in Non-stop, we don't cancel a run-to-line when a new
623
						// breakpoint is inserted.  This is because the new breakpoint could
624
						// be for another thread altogether and should not affect the current thread.
625
						IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(getRunToLineActiveOperation().getThreadContext(),
626
								IBreakpointsTargetDMContext.class);
627
628
						fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {getRunToLineActiveOperation().getBreakointId()}),
629
								new DataRequestMonitor<MIInfo>(getExecutor(), null));
630
						setRunToLineActiveOperation(null);
631
					}
632
				}
633
			}
634
		}
635
		
636
		IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
637
		if (e instanceof MISignalEvent && fDisableNextSignalEventDmc.remove(threadDmc)) {			
638
			fSilencedSignalEvent.put(threadDmc, e);
639
640
			// Don't broadcast the stopped event
641
			return;
642
		}
643
644
		IDMEvent<?> event = null;
645
		MIBreakpointDMContext bp = null;
646
		if (e instanceof MIBreakpointHitEvent) {
647
			int bpId = ((MIBreakpointHitEvent)e).getNumber();
648
			IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class);
649
			if (bpsTarget != null && bpId >= 0) {
650
				bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] {bpsTarget}, bpId); 
651
				event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent)e, bp);
652
			}
653
		}
654
		if (event == null) {
655
			event = new SuspendedEvent(e.getDMContext(), e);
656
		}
657
658
		getSession().dispatchEvent(event, getProperties());
659
	}
660
}
172
}
(-)src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactoryNS.java (-1 / +1 lines)
Lines 15-21 Link Here
15
15
16
/**
16
/**
17
 * This variant is for non-stop (NS) multi-threaded debugging, a gdb capability
17
 * This variant is for non-stop (NS) multi-threaded debugging, a gdb capability
18
 * introduced in version 6.8.50. We provide a specialized NS implementation of
18
 * introduced in version 7.0. We provide a specialized NS implementation of
19
 * the run control service; that's the only specialization.
19
 * the run control service; that's the only specialization.
20
 */
20
 */
21
public class GdbDebugServicesFactoryNS extends GdbDebugServicesFactory {
21
public class GdbDebugServicesFactoryNS extends GdbDebugServicesFactory {

Return to bug 337893