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 (-36 / +305 lines)
Lines 14-26 Link Here
14
14
15
import java.util.HashMap;
15
import java.util.HashMap;
16
import java.util.Hashtable;
16
import java.util.Hashtable;
17
import java.util.LinkedList;
17
import java.util.Map;
18
import java.util.Map;
18
import java.util.Vector;
19
19
20
import org.eclipse.cdt.core.IAddress;
20
import org.eclipse.cdt.core.IAddress;
21
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
21
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
22
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
22
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
23
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
23
import org.eclipse.cdt.dsf.concurrent.Immutable;
24
import org.eclipse.cdt.dsf.concurrent.Immutable;
25
import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
24
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
26
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
25
import org.eclipse.cdt.dsf.concurrent.Sequence;
27
import org.eclipse.cdt.dsf.concurrent.Sequence;
26
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
28
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
Lines 898-922 Link Here
898
		threadState.fStateChangeDetails = event.getDetails();		
900
		threadState.fStateChangeDetails = event.getDetails();		
899
	}
901
	}
900
902
901
	
902
	/**
903
	 * @since 3.0
904
	 */
905
	public void executeWithTargetAvailable(IDMContext ctx, Sequence.Step[] steps, RequestMonitor rm) {
906
		Vector<Step> totalStepsVector = new Vector<Step>();
907
		totalStepsVector.add(new IsTargetAvailableStep(ctx));
908
		totalStepsVector.add(new MakeTargetAvailableStep());
909
		for (Step step : steps) {
910
			totalStepsVector.add(step);
911
		}
912
		totalStepsVector.add(new RestoreTargetStateStep());
913
		
914
		final Step[] totalSteps = totalStepsVector.toArray(new Step[totalStepsVector.size()]);
915
		getExecutor().execute(new Sequence(getExecutor(), rm) {
916
			@Override public Step[] getSteps() { return totalSteps; }
917
		});
918
	}
919
920
	/* ******************************************************************************
903
	/* ******************************************************************************
921
	 * Section to support making operations even when the target is unavailable.
904
	 * Section to support making operations even when the target is unavailable.
922
	 *
905
	 *
Lines 925-945 Link Here
925
	 * like breakpoints.  The safe way to do it is to make sure we have at least
908
	 * like breakpoints.  The safe way to do it is to make sure we have at least
926
	 * one thread suspended.
909
	 * one thread suspended.
927
	 * 
910
	 * 
928
	 * Basically, we must make sure one container is suspended before making
911
	 * Basically, we must make sure one thread is suspended before making
929
	 * certain operations (currently breakpoints).  If that is not the case, we must 
912
	 * certain operations (currently breakpoints).  If that is not the case, we must 
930
	 * first suspend one thread, then perform the specified operations,
913
	 * first suspend one thread, then perform the specified operations,
931
	 * and finally resume that thread..
914
	 * and finally resume that thread..
932
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
915
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
933
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
916
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
934
	 * 
935
	 * ******************************************************************************/
917
	 * ******************************************************************************/
936
	private IContainerDMContext fContainerDmcToSuspend  = null;
918
	
937
	private IMIExecutionDMContext fExecutionDmcToSuspend  = null;
919
	/**
938
	private boolean fTargetAvailable = false;
920
	 * Utility class to store the parameters of the executeWithTargetAvailable() operations.
921
	 * @since 4.0
922
	 */
923
	protected static class TargetAvailableOperationInfo {
924
		public IDMContext ctx;
925
		public Sequence.Step[] steps;
926
		public RequestMonitor rm;
927
		
928
		public TargetAvailableOperationInfo(IDMContext ctx, Step[] steps, RequestMonitor rm) {
929
			super();
930
			this.ctx = ctx;
931
			this.steps = steps;
932
			this.rm = rm;
933
		}
934
	};
935
	
936
	// Keep track of if the target was available or not when we started the operation
937
	private boolean fTargetAvailable;
938
	// The container that needs to be suspended to perform the steps of the operation
939
	private IContainerDMContext fContainerDmcToSuspend;
940
	// The thread that we will actually suspend to make the container suspended.
941
	private IMIExecutionDMContext fExecutionDmcToSuspend;
942
943
	// Do we currently have an executeWithTargetAvailable() operation ongoing?
944
	private boolean fOngoingOperation;
945
	// Are we currently executing steps passed into executeWithTargetAvailable()?
946
	// This allows us to know if we can add more steps to execute or if we missed
947
	// our opportunity
948
	private boolean fCurrentlyExecutingSteps;
949
	
950
	// MultiRequestMonitor that allows us to track all the different steps we are
951
	// executing.  Once all steps are executed, we can complete this MultiRM and
952
	// allow the global sequence to continue.
953
	// Note that we couldn't use a CountingRequestMonitor because that type of RM
954
	// needs to know in advance how many subRms it will track; the MultiRM allows us
955
	// to receive more steps to execute continuously, and be able to upate the MultiRM.
956
	private MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
957
	// The number of batches of steps that are still being executing for potentially
958
	// concurrent executeWithTargetAvailable() operations.
959
	// Once this gets to zero, we know we have executed all the steps we were aware of
960
	// and we can complete the operation.
961
	private int fNumStepsStillExecuting;
962
	// Queue of executeWithTargetAvailable() operations that need to be processed.
963
	private LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
964
	
965
	/**
966
	 * Returns whether the target is available to perform operations
967
	 * @since 4.0
968
	 */
969
	protected boolean isTargetAvailable() {
970
		return fTargetAvailable;
971
	}
972
973
	/** @since 4.0 */
974
	protected void setTargetAvailable(boolean available) {
975
		fTargetAvailable = available;
976
	}
977
978
	/**
979
	 * Returns the container context that needs to be suspended to perform the
980
	 * required operation.
981
	 * @since 4.0
982
	 */
983
	protected IContainerDMContext getContainerToSuspend() {
984
		return fContainerDmcToSuspend;
985
	}
986
987
	/** @since 4.0 */
988
	protected void setContainerToSuspend(IContainerDMContext context) {
989
		fContainerDmcToSuspend = context;
990
	}
991
992
	/**
993
	 * Returns the container context that needs to be suspended to perform the
994
	 * required operation.
995
	 * @since 4.0
996
	 */
997
	protected IMIExecutionDMContext getExecutionToSuspend() {
998
		return fExecutionDmcToSuspend;
999
	}
1000
1001
	/** @since 4.0 */
1002
	protected void setExecutionToSuspend(IMIExecutionDMContext context) {
1003
		fExecutionDmcToSuspend = context;
1004
	}
1005
1006
	/** 
1007
	 * Returns whether there is currently an ExecuteWithTargetAvailable() operation ongoing. 
1008
	 * @since 4.0 
1009
	 */
1010
	protected boolean isTargetAvailableOperationOngoing() {
1011
		return fOngoingOperation;
1012
	}
1013
	
1014
	/** @since 4.0 */
1015
	protected void setTargetAvailableOperationOngoing(boolean ongoing) {
1016
		fOngoingOperation = ongoing;
1017
	}
1018
	
1019
	/**
1020
	 * Returns whether we are current in the process of executing the steps
1021
	 * that were passed to ExecuteWithTargetAvailable().
1022
	 * When this value is true, we can send more steps to be executed.
1023
	 * @since 4.0 
1024
	 */
1025
	protected boolean isCurrentlyExecutingSteps() {
1026
		return fCurrentlyExecutingSteps;
1027
	}
1028
1029
	/** @since 4.0 */
1030
	protected void setCurrentlyExecutingSteps(boolean executing) {
1031
		fCurrentlyExecutingSteps = executing;
1032
	}
1033
1034
	/**
1035
	 * Returns the requestMonitor that will be run once all steps sent to
1036
	 * ExecuteWithTargetAvailable() have been executed. 
1037
	 * @since 4.0 
1038
	 */
1039
	protected MultiRequestMonitor<RequestMonitor> getExecuteQueuedStepsRM() {
1040
		return fExecuteQueuedOpsStepMonitor;
1041
	}
1042
	
1043
	/** @since 4.0 */
1044
	protected void setExecuteQueuedStepsRM(MultiRequestMonitor<RequestMonitor> rm) {
1045
		fExecuteQueuedOpsStepMonitor = rm;
1046
	}
1047
1048
1049
	/**
1050
	 * Returns the number of batches of steps sent to ExecuteWithTargetAvailable()
1051
	 * that are still executing.  Once this number reaches zero, we can complete
1052
	 * the overall ExecuteWithTargetAvailable() operation.
1053
	 * @since 4.0 
1054
	 */
1055
	protected int getNumStepsStillExecuting() {
1056
		return fNumStepsStillExecuting;
1057
	}
1058
1059
	/** @since 4.0 */
1060
	protected void setNumStepsStillExecuting(int num) {
1061
		fNumStepsStillExecuting = num;
1062
	}
1063
1064
	/**
1065
	 * Returns the queue of executeWithTargetAvailable() operations that still need to be processed
1066
	 * @since 4.0
1067
	 */
1068
	protected LinkedList<TargetAvailableOperationInfo> getOperationsPending() {
1069
		return fOperationsPending;
1070
	}
1071
1072
	/**
1073
	 * This method takes care of executing a batch of steps that were passed to
1074
	 * ExecuteWithTargetAvailable().  The method is used to track the progress
1075
	 * of all these batches of steps, so that we know exactly when all of them
1076
	 * have been completed and the global sequence can be completed.
1077
	 * @since 4.0
1078
	 */
1079
	protected void executeSteps(final TargetAvailableOperationInfo info) {
1080
		fNumStepsStillExecuting++;
1081
		
1082
		// This RM propagates any error to the original rm of the actual steps.
1083
		// Even in case of errors for these steps, we want to continue the overall sequence
1084
		RequestMonitor stepsRm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
1085
			@Override
1086
			protected void handleCompleted() {
1087
				info.rm.setStatus(getStatus());
1088
				// It is important to call rm.done() right away.
1089
				// This is because some other operation we are performing might be waiting
1090
				// for this one to be done.  If we try to wait for the entire sequence to be
1091
				// done, then we will never finish because one monitor will never show as
1092
				// done, waiting for the second one.
1093
				info.rm.done();
1094
1095
				fExecuteQueuedOpsStepMonitor.requestMonitorDone(this);
1096
				fNumStepsStillExecuting--;
1097
				if (fNumStepsStillExecuting == 0) {
1098
					fExecuteQueuedOpsStepMonitor.doneAdding();
1099
				}
1100
			}
1101
		};
1102
1103
		fExecuteQueuedOpsStepMonitor.add(stepsRm);
939
1104
1105
		getExecutor().execute(new Sequence(getExecutor(), stepsRm) {
1106
			@Override public Step[] getSteps() { return info.steps; }
1107
		});	
1108
	}
1109
	
940
	/**
1110
	/**
941
	 * @since 3.0
1111
	 * @since 3.0
942
	 */
1112
	 */
1113
	public void executeWithTargetAvailable(IDMContext ctx, final Sequence.Step[] steps, final RequestMonitor rm) {
1114
		if (!fOngoingOperation) {
1115
			// We are the first operation of this kind currently requested
1116
			// so we need to start the sequence
1117
			fOngoingOperation = true;
1118
1119
			// We always go through our queue, even if we only have a single call to this method
1120
			fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
1121
			
1122
			// Steps that need to be executed to perform the operation
1123
			final Step[] sequenceSteps = new Step[] {
1124
					new IsTargetAvailableStep(ctx),
1125
					new MakeTargetAvailableStep(),
1126
					new ExecuteQueuedOperationsStep(),
1127
					new RestoreTargetStateStep(),
1128
			};
1129
			
1130
			// Once all the sequence is completed, we need to see if we have received
1131
			// another request that we now need to process
1132
			RequestMonitor sequenceCompletedRm = new RequestMonitor(getExecutor(), null) {
1133
				@Override
1134
				protected void handleCompleted() {
1135
					 fOngoingOperation = false;
1136
					 
1137
					 if (fOperationsPending.size() > 0) {
1138
						 // Darn, more operations came in.  Trigger their processing
1139
						 // by calling executeWithTargetAvailable() on the last one
1140
						 TargetAvailableOperationInfo info = fOperationsPending.removeLast();
1141
						 executeWithTargetAvailable(info.ctx, info.steps, info.rm);
1142
					 }
1143
					 // no other rm.done() needs to be called, they have all been handled already
1144
				}
1145
			};
1146
			
1147
			getExecutor().execute(new Sequence(getExecutor(), sequenceCompletedRm) {
1148
				@Override public Step[] getSteps() { return sequenceSteps; }
1149
			});
1150
		} else {
1151
			// We are currently already executing such an operation
1152
			// If we are still in the process of executing steps, let's include this new set of steps.
1153
			// This is important because some steps may depend on these new ones.
1154
			if (fCurrentlyExecutingSteps) {
1155
				executeSteps(new TargetAvailableOperationInfo(ctx, steps, rm));
1156
			} else {
1157
				// Too late to execute the new steps, so queue them for later
1158
				fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
1159
			}
1160
		}
1161
	}
1162
	
1163
	
1164
	/**
1165
	 * This part of the sequence verifies if the execution context of interest
1166
	 * is suspended or not.
1167
	 * @since 3.0
1168
	 */
943
	protected class IsTargetAvailableStep extends Sequence.Step {
1169
	protected class IsTargetAvailableStep extends Sequence.Step {
944
		final IDMContext fCtx;
1170
		final IDMContext fCtx;
945
		
1171
		
Lines 949-965 Link Here
949
		
1175
		
950
		@Override
1176
		@Override
951
		public void execute(final RequestMonitor rm) {
1177
		public void execute(final RequestMonitor rm) {
952
			fContainerDmcToSuspend = DMContexts.getAncestorOfType(fCtx, IContainerDMContext.class);
1178
			fContainerDmcToSuspend = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
953
			if (fContainerDmcToSuspend != null) {
1179
			if (fContainerDmcToSuspend != null) {
954
				// In non-stop, we don't actually need this particular process to be suspended,
1180
				String groupId = ((IMIContainerDMContext)fContainerDmcToSuspend).getGroupId();
955
				// all we need is one of any of the processes to be suspended.
1181
				if (groupId != null && groupId.length() > 0) {
956
				// However, for efficiency, we can first check if the process in question
1182
					// If we have a fully formed containerDmc, we can use it directly.
957
				// is suspended.
1183
					fTargetAvailable = isSuspended(fContainerDmcToSuspend);
958
				if (isSuspended(fContainerDmcToSuspend)) {
959
					fTargetAvailable = true;
960
					rm.done();
1184
					rm.done();
961
					return;
1185
					return;
962
				}
1186
				}
1187
				// else, the container is not fully formed, so let's fetch it below, since
1188
				// we know we are running single-process and there is only one process
963
			}
1189
			}
964
1190
965
			// If we get here, we have to get the list of processes to know if any of
1191
			// If we get here, we have to get the list of processes to know if any of
Lines 974-980 Link Here
974
							assert getData() != null;
1200
							assert getData() != null;
975
							
1201
							
976
							if (getData().length == 0) {
1202
							if (getData().length == 0) {
977
								// Happens at startup, starting with GDB 7.0
1203
								// Happens at startup, starting with GDB 7.0.
978
								// This means the target is available
1204
								// This means the target is available
979
								fTargetAvailable = true;
1205
								fTargetAvailable = true;
980
							} else {
1206
							} else {
Lines 995-1006 Link Here
995
	};
1221
	};
996
1222
997
	/**
1223
	/**
1224
	 * If the execution context of interest is not suspended, this step
1225
	 * will interrupt it.
998
	 * @since 3.0
1226
	 * @since 3.0
999
	 */
1227
	 */
1000
	protected class MakeTargetAvailableStep extends Sequence.Step {
1228
	protected class MakeTargetAvailableStep extends Sequence.Step {
1001
		@Override
1229
		@Override
1002
		public void execute(final RequestMonitor rm) {
1230
		public void execute(final RequestMonitor rm) {
1003
			if (!fTargetAvailable) {
1231
			if (!isTargetAvailable()) {
1004
				// Instead of suspending the entire process, let's find its first thread and use that
1232
				// Instead of suspending the entire process, let's find its first thread and use that
1005
				IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1233
				IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1006
				processControl.getProcessesBeingDebugged(
1234
				processControl.getProcessesBeingDebugged(
Lines 1028-1034 Link Here
1028
										super.handleFailure();
1256
										super.handleFailure();
1029
									};
1257
									};
1030
								});
1258
								});
1031
1032
							}
1259
							}
1033
						});
1260
						});
1034
			} else {
1261
			} else {
Lines 1043-1054 Link Here
1043
	};
1270
	};
1044
1271
1045
	/**
1272
	/**
1273
	 * This step of the sequence takes care of executing all the steps that
1274
	 * were passed to ExecuteWithTargetAvailable().
1275
	 * @since 4.0
1276
	 */
1277
	protected class ExecuteQueuedOperationsStep extends Sequence.Step {
1278
		@Override
1279
		public void execute(final RequestMonitor rm) {
1280
			fCurrentlyExecutingSteps = true;
1281
			
1282
			// It is important to use an ImmediateExecutor for this RM, to make sure we don't risk getting a new
1283
			// call to ExecuteWithTargetAvailable() when we just finished executing the steps.
1284
			fExecuteQueuedOpsStepMonitor = new MultiRequestMonitor<RequestMonitor>(ImmediateExecutor.getInstance(), rm) {
1285
				@Override
1286
				protected void handleCompleted() {
1287
					assert fOperationsPending.size() == 0;
1288
					
1289
					// We don't handle errors here.  Instead, we have already propagated any
1290
					// errors to each rm for each set of steps
1291
					
1292
					fCurrentlyExecutingSteps = false;
1293
					// Continue the sequence
1294
					rm.done();
1295
				}
1296
			};
1297
			// Tell the RM that we need to confirm when we are done adding sub-rms
1298
			fExecuteQueuedOpsStepMonitor.requireDoneAdding();
1299
						
1300
			// All pending operations are independent of each other so we can
1301
			// run them concurrently.
1302
			while (fOperationsPending.size() > 0) {
1303
				executeSteps(fOperationsPending.poll());				
1304
			}
1305
		}
1306
	};
1307
	
1308
	/**
1309
	 * If the sequence had to interrupt the execution context of interest,
1310
	 * this step will resume it again to reach the same state as when we started.
1046
	 * @since 3.0
1311
	 * @since 3.0
1047
	 */
1312
	 */
1048
	protected class RestoreTargetStateStep extends Sequence.Step {
1313
	protected class RestoreTargetStateStep extends Sequence.Step {
1049
		@Override
1314
		@Override
1050
		public void execute(final RequestMonitor rm) {
1315
		public void execute(final RequestMonitor rm) {
1051
			if (!fTargetAvailable) {
1316
			if (!isTargetAvailable()) {
1052
				assert fDisableNextRunningEventDmc == null;
1317
				assert fDisableNextRunningEventDmc == null;
1053
				fDisableNextRunningEventDmc = fExecutionDmcToSuspend;
1318
				fDisableNextRunningEventDmc = fExecutionDmcToSuspend;
1054
				
1319
				
Lines 1089-1094 Link Here
1089
		}
1354
		}
1090
	 };
1355
	 };
1091
1356
1357
	 /* ******************************************************************************
1358
	  * End of section to support operations even when the target is unavailable.
1359
	  * ******************************************************************************/
1360
1092
	///////////////////////////////////////////////////////////////////////////
1361
	///////////////////////////////////////////////////////////////////////////
1093
	// Event handlers
1362
	// Event handlers
1094
	///////////////////////////////////////////////////////////////////////////
1363
	///////////////////////////////////////////////////////////////////////////

Return to bug 337893