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/mi/service/MIRunControl.java (-34 / +281 lines)
Lines 12-24 Link Here
12
package org.eclipse.cdt.dsf.mi.service;
12
package org.eclipse.cdt.dsf.mi.service;
13
13
14
import java.util.HashMap;
14
import java.util.HashMap;
15
import java.util.LinkedList;
15
import java.util.Map;
16
import java.util.Map;
16
import java.util.Vector;
17
17
18
import org.eclipse.cdt.core.IAddress;
18
import org.eclipse.cdt.core.IAddress;
19
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
19
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
20
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
20
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
21
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
21
import org.eclipse.cdt.dsf.concurrent.Immutable;
22
import org.eclipse.cdt.dsf.concurrent.Immutable;
23
import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
22
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
24
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
23
import org.eclipse.cdt.dsf.concurrent.Sequence;
25
import org.eclipse.cdt.dsf.concurrent.Sequence;
24
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
26
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
Lines 907-946 Link Here
907
					rm.done();
909
					rm.done();
908
		}		
910
		}		
909
	}
911
	}
910
	
911
	/**
912
	 * @since 3.0
913
	 */
914
	public void executeWithTargetAvailable(IDMContext ctx, Sequence.Step[] steps, RequestMonitor rm) {
915
		Vector<Step> totalStepsVector = new Vector<Step>();
916
		totalStepsVector.add(new IsTargetAvailableStep(ctx));
917
		totalStepsVector.add(new MakeTargetAvailableStep());
918
		for (Step step : steps) {
919
			totalStepsVector.add(step);
920
		}
921
		totalStepsVector.add(new RestoreTargetStateStep());
922
		
923
		final Step[] totalSteps = totalStepsVector.toArray(new Step[totalStepsVector.size()]);
924
		getExecutor().execute(new Sequence(getExecutor(), rm) {
925
			@Override public Step[] getSteps() { return totalSteps; }
926
		});
927
	}
928
912
929
	/* ******************************************************************************
913
	/* ******************************************************************************
930
	 * Section to support making operations even when the target is unavailable.
914
	 * Section to support operations even when the target is unavailable.
931
	 *
915
	 *
932
	 * Basically, we must make sure the container is suspended before making
916
	 * Basically, we must make sure the container is suspended before making
933
	 * certain operations (currently breakpoints).  If we don't, we must first 
917
	 * certain operations (currently breakpoints).  If we don't, we must first 
934
	 * suspend the container, then perform the specified operations,
918
	 * suspend the container, then perform the specified operations,
935
	 * and finally resume the container.
919
	 * and finally resume the container.
936
	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=242943
920
	 * See http://bugs.eclipse.org/242943
937
	 * and https://bugs.eclipse.org/bugs/show_bug.cgi?id=282273
921
	 * and http://bugs.eclipse.org/282273
922
	 * 
923
	 * Note that for multi-process, the correct container must be suspended for the
924
	 * breakpoint to be inserted on that container.  Not a big deal though, since
925
	 * a breakpointDmc is mapped to a specific container.  Also, since we are in
926
	 * all-stop mode here, it does not really matter what we stop, everything will
927
	 * stop.
928
	 * See http://bugs.eclipse.org/337893
938
	 * 
929
	 * 
939
	 * ******************************************************************************/
930
	 * ******************************************************************************/
940
	private IContainerDMContext fContainerDmc  = null;
941
	private boolean fTargetAvailable = false;
942
931
943
	/**
932
	/**
933
	 * Utility class to store the parameters of the executeWithTargetAvailable() operations.
934
	 * @since 4.0
935
	 */
936
	protected static class TargetAvailableOperationInfo {
937
		public IDMContext ctx;
938
		public Sequence.Step[] steps;
939
		public RequestMonitor rm;
940
		
941
		public TargetAvailableOperationInfo(IDMContext ctx, Step[] steps, RequestMonitor rm) {
942
			super();
943
			this.ctx = ctx;
944
			this.steps = steps;
945
			this.rm = rm;
946
		}
947
	};
948
949
	// Keep track of if the target was available or not when we started the operation
950
	private boolean fTargetAvailable;
951
	// The execution context that need to be available.
952
	private IExecutionDMContext fExecutionDmc;
953
	// Do we currently have an executeWithTargetAvailable() operation ongoing?
954
	private boolean fOngoingOperation;
955
	// Are we currently executing steps passed into executeWithTargetAvailable()?
956
	// This allows us to know if we can add more steps to execute or if we missed
957
	// our opportunity
958
	private boolean fCurrentlyExecutingSteps;
959
	
960
	// MultiRequestMonitor that allows us to track all the different steps we are
961
	// executing.  Once all steps are executed, we can complete this MultiRM and
962
	// allow the global sequence to continue.
963
	// Note that we couldn't use a CountingRequestMonitor because that type of RM
964
	// needs to know in advance how many subRms it will track; the MultiRM allows us
965
	// to receive more steps to execute continuously, and be able to upate the MultiRM.
966
	private MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
967
	// The number of batches of steps that are still being executing for potentially
968
	// concurrent executeWithTargetAvailable() operations.
969
	// Once this gets to zero, we know we have executed all the steps we were aware of
970
	// and we can complete the operation.
971
	private int fNumStepsStillExecuting;
972
	// Queue of executeWithTargetAvailable() operations that need to be processed.
973
	private LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
974
	
975
	/**
944
	 * Returns whether the target is available to perform operations
976
	 * Returns whether the target is available to perform operations
945
	 * @since 3.0
977
	 * @since 3.0
946
	 */
978
	 */
Lines 948-962 Link Here
948
		return fTargetAvailable;
980
		return fTargetAvailable;
949
	}
981
	}
950
982
983
	/** @since 4.0 */
984
	protected void setTargetAvailable(boolean available) {
985
		fTargetAvailable = available;
986
	}
987
	
951
	/**
988
	/**
952
	 * Returns whether the target must be suspended before performing the breakpoint operation
989
	 * Returns the execution context that needs to be suspended to perform the
990
	 * required operation.
953
	 * @since 3.0
991
	 * @since 3.0
954
	 */
992
	 */
955
	protected IExecutionDMContext getContextToSuspend() {
993
	protected IExecutionDMContext getContextToSuspend() {
956
		return fContainerDmc;
994
		return fExecutionDmc;
995
	}
996
997
	/** @since 4.0 */
998
	protected void setContextToSuspend(IExecutionDMContext context) {
999
		fExecutionDmc = context;
1000
	}
1001
1002
	/** 
1003
	 * Returns whether there is currently an ExecuteWithTargetAvailable() operation ongoing. 
1004
	 * @since 4.0 
1005
	 */
1006
	protected boolean isTargetAvailableOperationOngoing() {
1007
		return fOngoingOperation;
1008
	}
1009
	
1010
	/** @since 4.0 */
1011
	protected void setTargetAvailableOperationOngoing(boolean ongoing) {
1012
		fOngoingOperation = ongoing;
1013
	}
1014
	
1015
	/**
1016
	 * Returns whether we are current in the process of executing the steps
1017
	 * that were passed to ExecuteWithTargetAvailable().
1018
	 * When this value is true, we can send more steps to be executed.
1019
	 * @since 4.0 
1020
	 */
1021
	protected boolean isCurrentlyExecutingSteps() {
1022
		return fCurrentlyExecutingSteps;
1023
	}
1024
1025
	/** @since 4.0 */
1026
	protected void setCurrentlyExecutingSteps(boolean executing) {
1027
		fCurrentlyExecutingSteps = executing;
1028
	}
1029
1030
	/**
1031
	 * Returns the requestMonitor that will be run once all steps sent to
1032
	 * ExecuteWithTargetAvailable() have been executed. 
1033
	 * @since 4.0 
1034
	 */
1035
	protected MultiRequestMonitor<RequestMonitor> getExecuteQueuedStepsRM() {
1036
		return fExecuteQueuedOpsStepMonitor;
1037
	}
1038
	
1039
	/** @since 4.0 */
1040
	protected void setExecuteQueuedStepsRM(MultiRequestMonitor<RequestMonitor> rm) {
1041
		fExecuteQueuedOpsStepMonitor = rm;
1042
	}
1043
1044
1045
	/**
1046
	 * Returns the number of batches of steps sent to ExecuteWithTargetAvailable()
1047
	 * that are still executing.  Once this number reaches zero, we can complete
1048
	 * the overall ExecuteWithTargetAvailable() operation.
1049
	 * @since 4.0 
1050
	 */
1051
	protected int getNumStepsStillExecuting() {
1052
		return fNumStepsStillExecuting;
1053
	}
1054
1055
	/** @since 4.0 */
1056
	protected void setNumStepsStillExecuting(int num) {
1057
		fNumStepsStillExecuting = num;
1058
	}
1059
1060
	/**
1061
	 * Returns the queue of executeWithTargetAvailable() operations that still need to be processed
1062
	 * @since 4.0
1063
	 */
1064
	protected LinkedList<TargetAvailableOperationInfo> getOperationsPending() {
1065
		return fOperationsPending;
957
	}
1066
	}
958
1067
959
	/**
1068
	/**
1069
	 * This method takes care of executing a batch of steps that were passed to
1070
	 * ExecuteWithTargetAvailable().  The method is used to track the progress
1071
	 * of all these batches of steps, so that we know exactly when all of them
1072
	 * have been completed and the global sequence can be completed.
1073
	 * @since 4.0
1074
	 */
1075
	protected void executeSteps(final TargetAvailableOperationInfo info) {
1076
		fNumStepsStillExecuting++;
1077
		
1078
		// This RM propagates any error to the original rm of the actual steps.
1079
		// Even in case of errors for these steps, we want to continue the overall sequence
1080
		RequestMonitor stepsRm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
1081
			@Override
1082
			protected void handleCompleted() {
1083
				info.rm.setStatus(getStatus());
1084
				// It is important to call rm.done() right away.
1085
				// This is because some other operation we are performing might be waiting
1086
				// for this one to be done.  If we try to wait for the entire sequence to be
1087
				// done, then we will never finish because one monitor will never show as
1088
				// done, waiting for the second one.
1089
				info.rm.done();
1090
1091
				fExecuteQueuedOpsStepMonitor.requestMonitorDone(this);
1092
				fNumStepsStillExecuting--;
1093
				if (fNumStepsStillExecuting == 0) {
1094
					fExecuteQueuedOpsStepMonitor.doneAdding();
1095
				}
1096
			}
1097
		};
1098
1099
		fExecuteQueuedOpsStepMonitor.add(stepsRm);
1100
1101
		getExecutor().execute(new Sequence(getExecutor(), stepsRm) {
1102
			@Override public Step[] getSteps() { return info.steps; }
1103
		});	
1104
	}
1105
	
1106
	/**
1107
	 * @since 3.0
1108
	 */
1109
	public void executeWithTargetAvailable(IDMContext ctx, final Sequence.Step[] steps, final RequestMonitor rm) {
1110
		if (!fOngoingOperation) {
1111
			// We are the first operation of this kind currently requested
1112
			// so we need to start the sequence
1113
			fOngoingOperation = true;
1114
1115
			// We always go through our queue, even if we only have a single call to this method
1116
			fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
1117
			
1118
			// Steps that need to be executed to perform the operation
1119
			final Step[] sequenceSteps = new Step[] {
1120
					new IsTargetAvailableStep(ctx),
1121
					new MakeTargetAvailableStep(),
1122
					new ExecuteQueuedOperationsStep(),
1123
					new RestoreTargetStateStep(),
1124
			};
1125
			
1126
			// Once all the sequence is completed, we need to see if we have received
1127
			// another request that we now need to process
1128
			RequestMonitor sequenceCompletedRm = new RequestMonitor(getExecutor(), null) {
1129
				@Override
1130
				protected void handleCompleted() {
1131
					 fOngoingOperation = false;
1132
					 
1133
					 if (fOperationsPending.size() > 0) {
1134
						 // Darn, more operations came in.  Trigger their processing
1135
						 // by calling executeWithTargetAvailable() on the last one
1136
						 TargetAvailableOperationInfo info = fOperationsPending.removeLast();
1137
						 executeWithTargetAvailable(info.ctx, info.steps, info.rm);
1138
					 }
1139
					 // no other rm.done() needs to be called, they have all been handled already
1140
				}
1141
			};
1142
			
1143
			getExecutor().execute(new Sequence(getExecutor(), sequenceCompletedRm) {
1144
				@Override public Step[] getSteps() { return sequenceSteps; }
1145
			});
1146
		} else {
1147
			// We are currently already executing such an operation
1148
			// If we are still in the process of executing steps, let's include this new set of steps.
1149
			// This is important because some steps may depend on these new ones.
1150
			if (fCurrentlyExecutingSteps) {
1151
				executeSteps(new TargetAvailableOperationInfo(ctx, steps, rm));
1152
			} else {
1153
				// Too late to execute the new steps, so queue them for later
1154
				fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
1155
			}
1156
		}
1157
	}
1158
	
1159
	
1160
	/**
1161
	 * This part of the sequence verifies if the execution context of interest
1162
	 * is suspended or not.
960
	 * @since 3.0
1163
	 * @since 3.0
961
	 */
1164
	 */
962
	protected class IsTargetAvailableStep extends Sequence.Step {
1165
	protected class IsTargetAvailableStep extends Sequence.Step {
Lines 968-978 Link Here
968
		
1171
		
969
		@Override
1172
		@Override
970
		public void execute(final RequestMonitor rm) {
1173
		public void execute(final RequestMonitor rm) {
971
			fContainerDmc = DMContexts.getAncestorOfType(fCtx, IContainerDMContext.class);
1174
			fExecutionDmc = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
972
			if (fContainerDmc != null) {
1175
			if (fExecutionDmc != null) {
973
				// In all-stop, if any process is suspended, then all of them are suspended
1176
				fTargetAvailable = isSuspended(fExecutionDmc);
974
				// so we only need to check this process.
975
				fTargetAvailable = isSuspended(fContainerDmc);
976
				rm.done();
1177
				rm.done();
977
				return;
1178
				return;
978
			}
1179
			}
Lines 987-998 Link Here
987
							assert getData() != null;
1188
							assert getData() != null;
988
							
1189
							
989
							if (getData().length == 0) {
1190
							if (getData().length == 0) {
990
								// Happens at startup, starting with GDB 7.0
1191
								// Happens at startup, starting with GDB 7.0.
991
								// This means the target is available
1192
								// This means the target is available
992
								fTargetAvailable = true;
1193
								fTargetAvailable = true;
993
							} else {
1194
							} else {
994
								fContainerDmc = (IContainerDMContext)(getData()[0]);
1195
								// In all-stop, if any process is suspended, then all of them are suspended
995
								fTargetAvailable = isSuspended(fContainerDmc);
1196
								// so we only need to check the first process.
1197
								fExecutionDmc = (IExecutionDMContext)(getData()[0]);
1198
								fTargetAvailable = isSuspended(fExecutionDmc);
996
							}
1199
							}
997
							rm.done();
1200
							rm.done();
998
						}
1201
						}
Lines 1001-1006 Link Here
1001
	};
1204
	};
1002
1205
1003
	/**
1206
	/**
1207
	 * If the execution context of interest is not suspended, this step
1208
	 * will interrupt it.
1004
	 * @since 3.0
1209
	 * @since 3.0
1005
	 */
1210
	 */
1006
	protected class MakeTargetAvailableStep extends Sequence.Step {
1211
	protected class MakeTargetAvailableStep extends Sequence.Step {
Lines 1033-1038 Link Here
1033
	};
1238
	};
1034
1239
1035
	/**
1240
	/**
1241
	 * This step of the sequence takes care of executing all the steps that
1242
	 * were passed to ExecuteWithTargetAvailable().
1243
	 * @since 4.0
1244
	 */
1245
	protected class ExecuteQueuedOperationsStep extends Sequence.Step {
1246
		@Override
1247
		public void execute(final RequestMonitor rm) {
1248
			fCurrentlyExecutingSteps = true;
1249
			
1250
			// It is important to use an ImmediateExecutor for this RM, to make sure we don't risk getting a new
1251
			// call to ExecuteWithTargetAvailable() when we just finished executing the steps.
1252
			fExecuteQueuedOpsStepMonitor = new MultiRequestMonitor<RequestMonitor>(ImmediateExecutor.getInstance(), rm) {
1253
				@Override
1254
				protected void handleCompleted() {
1255
					assert fOperationsPending.size() == 0;
1256
					
1257
					// We don't handle errors here.  Instead, we have already propagated any
1258
					// errors to each rm for each set of steps
1259
					
1260
					fCurrentlyExecutingSteps = false;
1261
					// Continue the sequence
1262
					rm.done();
1263
				}
1264
			};
1265
			// Tell the RM that we need to confirm when we are done adding sub-rms
1266
			fExecuteQueuedOpsStepMonitor.requireDoneAdding();
1267
						
1268
			// All pending operations are independent of each other so we can
1269
			// run them concurrently.
1270
			while (fOperationsPending.size() > 0) {
1271
				executeSteps(fOperationsPending.poll());				
1272
			}
1273
		}
1274
	};
1275
	
1276
	/**
1277
	 * If the sequence had to interrupt the execution context of interest,
1278
	 * this step will resume it again to reach the same state as when we started.
1036
	 * @since 3.0
1279
	 * @since 3.0
1037
	 */
1280
	 */
1038
	protected class RestoreTargetStateStep extends Sequence.Step {
1281
	protected class RestoreTargetStateStep extends Sequence.Step {
Lines 1078-1083 Link Here
1078
		}
1321
		}
1079
	 };
1322
	 };
1080
1323
1324
	 /* ******************************************************************************
1325
	  * End of section to support operations even when the target is unavailable.
1326
	  * ******************************************************************************/
1327
1081
	/**
1328
	/**
1082
	 * {@inheritDoc}
1329
	 * {@inheritDoc}
1083
     * @since 1.1
1330
     * @since 1.1

Return to bug 337893