|
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 |