Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreutarass2010-05-24 20:24:34 -0400
committereutarass2010-05-24 20:24:34 -0400
commit4a7fc472f6353e2e96c4abd3a0c557aaca7883c7 (patch)
tree0de1d8cedb42de0a3c6da28f3b34350660d4ab99 /plugins
parentae26672d31bd5767a7c2feeed1070da3b581c825 (diff)
downloadorg.eclipse.tcf-4a7fc472f6353e2e96c4abd3a0c557aaca7883c7.tar.gz
org.eclipse.tcf-4a7fc472f6353e2e96c4abd3a0c557aaca7883c7.tar.xz
org.eclipse.tcf-4a7fc472f6353e2e96c4abd3a0c557aaca7883c7.zip
TCF Agent: fixed Memory Map changed events on Linux, added Memory Map for Windows
TCF Debugger: added module names in stack frame labels TCF Debugger: added error handling in remote process console IO
Diffstat (limited to 'plugins')
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java4
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java4
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java4
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java42
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java7
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java69
-rw-r--r--plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java45
-rw-r--r--plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java40
8 files changed, 190 insertions, 25 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
index 5da304c9f..255082609 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java
@@ -150,6 +150,10 @@ public class TCFAnnotationManager {
public void onProcessOutput(TCFLaunch launch, String process_id, int stream_id, byte[] data) {
}
+
+ public void onProcessStreamError(TCFLaunch launch, String process_id,
+ int stream_id, Exception error, int lost_size) {
+ }
};
private final ISelectionListener selection_listener = new ISelectionListener() {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
index 36b70a054..9edcc23ba 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExecContext.java
@@ -152,4 +152,8 @@ public class TCFChildrenExecContext extends TCFChildren {
mem_children.add(n);
n.setMemoryContext(context);
}
+
+ void onMemoryMapChanged() {
+ for (TCFNode n : getNodes()) ((TCFNodeExecContext)n).onMemoryMapChanged();
+ }
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
index 12a0fb71e..89f1b2227 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java
@@ -51,6 +51,10 @@ public class TCFChildrenStackTrace extends TCFChildren {
for (TCFNode n : getNodes()) ((TCFNodeStackFrame)n).onRegistersChanged();
}
+ void onMemoryMapChanged() {
+ for (TCFNode n : getNodes()) ((TCFNodeStackFrame)n).onMemoryMapChanged();
+ }
+
void onRegisterValueChanged() {
for (TCFNode n : getNodes()) ((TCFNodeStackFrame)n).onRegisterValueChanged();
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
index b6a3baff0..e62943a6c 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java
@@ -94,6 +94,7 @@ import org.eclipse.tm.tcf.protocol.IErrorReport;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.ILineNumbers;
import org.eclipse.tm.tcf.services.IMemory;
+import org.eclipse.tm.tcf.services.IMemoryMap;
import org.eclipse.tm.tcf.services.IProcesses;
import org.eclipse.tm.tcf.services.IRegisters;
import org.eclipse.tm.tcf.services.IRunControl;
@@ -112,7 +113,8 @@ import org.eclipse.ui.texteditor.ITextEditor;
/**
* TCFModel represents remote target state as it is known to host.
* The main job of the model is caching remote data,
- * keeping the cache in a coherent state, and feeding UI with up-to-date data.
+ * keeping the cache in a coherent state,
+ * and feeding UI with up-to-date data.
*/
public class TCFModel implements IElementContentProvider, IElementLabelProvider,
IModelProxyFactory, IColumnPresentationFactory, ISourceDisplay, ISuspendTrigger {
@@ -159,7 +161,12 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
if (len < 0) break;
Protocol.invokeAndWait(new Runnable() {
public void run() {
- launch.writeProcessInputStream(buf, 0, len);
+ try {
+ launch.writeProcessInputStream(buf, 0, len);
+ }
+ catch (Exception x) {
+ onProcessStreamError(null, 0, x, 0);
+ }
}
});
}
@@ -327,7 +334,7 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
public void contextSuspended(final String context, String pc, String reason, Map<String,Object> params) {
TCFNode node = getNode(context);
if (node instanceof TCFNodeExecContext) {
- final TCFNodeExecContext exe = (TCFNodeExecContext)node;
+ TCFNodeExecContext exe = (TCFNodeExecContext)node;
exe.onContextSuspended(pc, reason, params);
}
setDebugViewSelection(context);
@@ -336,6 +343,17 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
};
+ private final IMemoryMap.MemoryMapListener mmap_listenr = new IMemoryMap.MemoryMapListener() {
+
+ public void changed(String context) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ TCFNodeExecContext exe = (TCFNodeExecContext)node;
+ exe.onMemoryMapChanged();
+ }
+ }
+ };
+
private final IRegisters.RegistersListener reg_listener = new IRegisters.RegistersListener() {
public void contextChanged() {
@@ -430,6 +448,8 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
if (mem != null) mem.addListener(mem_listener);
IRunControl run = launch.getService(IRunControl.class);
if (run != null) run.addListener(run_listener);
+ IMemoryMap mmap = launch.getService(IMemoryMap.class);
+ if (mmap != null) mmap.addListener(mmap_listenr);
IRegisters reg = launch.getService(IRegisters.class);
if (reg != null) reg.addListener(reg_listener);
IProcesses prs = launch.getService(IProcesses.class);
@@ -501,6 +521,22 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider,
}
}
+ void onProcessStreamError(String process_id, int stream_id, Exception x, int lost_size) {
+ StringBuffer bf = new StringBuffer();
+ bf.append("Debugger console IO error");
+ if (process_id != null) {
+ bf.append(". Process ID ");
+ bf.append(process_id);
+ }
+ bf.append(". Stream ");
+ bf.append(stream_id);
+ if (lost_size > 0) {
+ bf.append(". Lost data size ");
+ bf.append(lost_size);
+ }
+ Activator.log(bf.toString(), x);
+ }
+
void onContextActionsStart(String id) {
running_actions.add(id);
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
index 283664ff6..24849da0c 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModelManager.java
@@ -63,6 +63,13 @@ public class TCFModelManager {
TCFModel model = models.get(launch);
if (model != null) model.onProcessOutput(process_id, stream_id, data);
}
+
+ public void onProcessStreamError(TCFLaunch launch, String process_id,
+ int stream_id, Exception error, int lost_size) {
+ assert Protocol.isDispatchThread();
+ TCFModel model = models.get(launch);
+ if (model != null) model.onProcessStreamError(process_id, stream_id, error, lost_size);
+ }
};
private final ILaunchesListener debug_launch_listener = new ILaunchesListener() {
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
index 0e759bca2..e619f089f 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java
@@ -29,6 +29,7 @@ import org.eclipse.tm.internal.tcf.debug.ui.ImageCache;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IMemory;
+import org.eclipse.tm.tcf.services.IMemoryMap;
import org.eclipse.tm.tcf.services.IProcesses;
import org.eclipse.tm.tcf.services.IRunControl;
import org.eclipse.tm.tcf.util.TCFDataCache;
@@ -44,6 +45,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner {
private final TCFDataCache<IMemory.MemoryContext> mem_context;
private final TCFDataCache<IRunControl.RunControlContext> run_context;
+ private final TCFDataCache<MemoryRegion[]> memory_map;
private final TCFDataCache<IProcesses.ProcessContext> prs_context;
private final TCFDataCache<TCFContextState> state;
private final TCFDataCache<BigInteger> address; // Current PC as BigInteger
@@ -56,6 +58,40 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner {
private static int seq_cnt;
+ /**
+ * Wrapper class for IMemoryMap.MemoryRegion.
+ * The class help to search memory region by address by
+ * providing contains() method.
+ */
+ public static class MemoryRegion {
+
+ private final BigInteger addr_start;
+ private final BigInteger addr_end;
+
+ public final IMemoryMap.MemoryRegion region;
+
+ private MemoryRegion(IMemoryMap.MemoryRegion region) {
+ this.region = region;
+ Number addr = region.getAddress();
+ Number size = region.getSize();
+ if (addr == null || size == null) {
+ addr_start = null;
+ addr_end = null;
+ }
+ else {
+ addr_start = addr instanceof BigInteger ? (BigInteger)addr : new BigInteger(addr.toString());
+ addr_end = addr_start.add(size instanceof BigInteger ? (BigInteger)size : new BigInteger(size.toString()));
+ }
+ }
+
+ public boolean contains(BigInteger addr) {
+ return
+ addr_start != null && addr_end != null &&
+ addr_start.compareTo(addr) <= 0 &&
+ addr_end.compareTo(addr) > 0;
+ }
+ }
+
TCFNodeExecContext(TCFNode parent, final String id) {
super(parent, id);
seq_no = seq_cnt++;
@@ -118,6 +154,29 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner {
return false;
}
};
+ memory_map = new TCFDataCache<MemoryRegion[]>(channel) {
+ @Override
+ protected boolean startDataRetrieval() {
+ assert command == null;
+ IMemoryMap mmap = model.getLaunch().getService(IMemoryMap.class);
+ if (mmap == null) {
+ set(null, null, null);
+ return true;
+ }
+ command = mmap.get(id, new IMemoryMap.DoneGet() {
+ public void doneGet(IToken token, Exception error, IMemoryMap.MemoryRegion[] map) {
+ MemoryRegion[] arr = null;
+ if (map != null) {
+ int i = 0;
+ arr = new MemoryRegion[map.length];
+ for (IMemoryMap.MemoryRegion r : map) arr[i++] = new MemoryRegion(r);
+ }
+ set(token, error, arr);
+ }
+ });
+ return false;
+ }
+ };
state = new TCFDataCache<TCFContextState>(channel) {
@Override
protected boolean startDataRetrieval() {
@@ -199,6 +258,10 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner {
mem_context.reset(ctx);
}
+ TCFDataCache<MemoryRegion[]> getMemoryMap() {
+ return memory_map;
+ }
+
public void addSymbol(TCFNodeSymbol s) {
assert symbols.get(s.id) == null;
symbols.put(s.id, s);
@@ -475,6 +538,12 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner {
assert !disposed;
}
+ void onMemoryMapChanged() {
+ memory_map.reset();
+ children_exec.onMemoryMapChanged();
+ children_stack.onMemoryMapChanged();
+ }
+
void onRegistersChanged() {
children_stack.onRegistersChanged();
addModelDelta(IModelDelta.CONTENT);
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
index d137d1144..55daf5988 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java
@@ -28,8 +28,8 @@ import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.ILineNumbers;
import org.eclipse.tm.tcf.services.IMemory;
+import org.eclipse.tm.tcf.services.IRunControl;
import org.eclipse.tm.tcf.services.IStackTrace;
-import org.eclipse.tm.tcf.services.ILineNumbers.CodeArea;
import org.eclipse.tm.tcf.util.TCFDataCache;
public class TCFNodeStackFrame extends TCFNode {
@@ -124,7 +124,7 @@ public class TCFNodeStackFrame extends TCFNode {
final BigInteger n1 = n0.add(BigInteger.valueOf(1));
final IMemory.MemoryContext ctx = mem_ctx;
command = ln.mapToSource(parent.id, n0, n1, new ILineNumbers.DoneMapToSource() {
- public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
+ public void doneMapToSource(IToken token, Exception error, ILineNumbers.CodeArea[] areas) {
TCFSourceRef l = new TCFSourceRef();
l.context = ctx;
l.address = n0;
@@ -292,7 +292,7 @@ public class TCFNodeStackFrame extends TCFNode {
}
else {
TCFDataCache<TCFContextState> state_cache = ((TCFNodeExecContext)parent).getState();
- if (!state_cache.validate()) return false;
+ if (!state_cache.validate(done)) return false;
Throwable error = state_cache.getError();
if (error == null) error = stack_trace_cache.getError();
if (error == null) {
@@ -325,7 +325,9 @@ public class TCFNodeStackFrame extends TCFNode {
result.setLabel("...", 0);
}
else {
- String label = makeHexAddrString(l.context, l.address);
+ String module = getModuleName(l.address, done);
+ if (module == null) return false;
+ String label = makeHexAddrString(l.context, l.address) + module;
if (l.area != null && l.area.file != null) {
label += ": " + l.area.file + ", line " + l.area.start_line;
}
@@ -337,11 +339,32 @@ public class TCFNodeStackFrame extends TCFNode {
return true;
}
- private String makeHexAddrString(IMemory.MemoryContext m, Number n) {
- BigInteger i = null;
- if (n instanceof BigInteger) i = (BigInteger)n;
- else i = new BigInteger(n.toString());
- String s = i.toString(16);
+ private String getModuleName(BigInteger pc, Runnable done) {
+ TCFDataCache<IRunControl.RunControlContext> parent_dc = ((TCFNodeExecContext)parent).getRunContext();
+ if (!parent_dc.validate(done)) return null;
+ IRunControl.RunControlContext parent_ctx = parent_dc.getData();
+ if (parent_ctx == null) return "";
+ String prs_id = parent_ctx.getProcessID();
+ if (prs_id == null) return "";
+ TCFNodeExecContext prs_node = (TCFNodeExecContext)model.getNode(prs_id);
+ TCFDataCache<TCFNodeExecContext.MemoryRegion[]> map_dc = prs_node.getMemoryMap();
+ if (!map_dc.validate(done)) return null;
+ TCFNodeExecContext.MemoryRegion[] map = map_dc.getData();
+ if (map == null) return "";
+ for (TCFNodeExecContext.MemoryRegion r : map) {
+ String fnm = r.region.getFileName();
+ if (fnm != null && r.contains(pc)) {
+ fnm = fnm.replace('\\', '/');
+ int x = fnm.lastIndexOf('/');
+ if (x >= 0) fnm = fnm.substring(x + 1);
+ return " [" + fnm + "]";
+ }
+ }
+ return "";
+ }
+
+ private String makeHexAddrString(IMemory.MemoryContext m, BigInteger n) {
+ String s = n.toString(16);
int sz = (m != null ? m.getAddressSize() : 4) * 2;
int l = sz - s.length();
if (l < 0) l = 0;
@@ -364,6 +387,10 @@ public class TCFNodeStackFrame extends TCFNode {
addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
}
+ void onMemoryMapChanged() {
+ addModelDelta(IModelDelta.STATE);
+ }
+
void onRegistersChanged() {
children_regs.onRegistersChanged();
addModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
index abfd4f531..997e51d50 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java
@@ -60,6 +60,10 @@ public class TCFLaunch extends Launch {
public void onContextActionsDone(TCFLaunch launch, String ctx_id, String result);
public void onProcessOutput(TCFLaunch launch, String process_id, int stream_id, byte[] data);
+
+ public void onProcessStreamError(
+ TCFLaunch launch, String process_id, int stream_id,
+ Exception error, int lost_size);
}
private abstract class LaunchStep implements Runnable {
@@ -459,20 +463,24 @@ public class TCFLaunch extends Launch {
final String peocess_id = process.getID();
final IStreams streams = getService(IStreams.class);
IStreams.DoneRead done = new IStreams.DoneRead() {
- boolean disconnected;
public void doneRead(IToken token, Exception error, int lost_size, byte[] data, boolean eos) {
- if (disconnected) return;
- // TODO: handle process output data loss
+ if (stream_ids.get(id) == null) return;
+ if (lost_size > 0) {
+ Exception x = new IOException("Process output data lost due buffer overflow");
+ for (Listener l : listeners) l.onProcessStreamError(TCFLaunch.this, peocess_id, no, x, lost_size);
+ }
if (data != null && data.length > 0) {
for (Listener l : listeners) l.onProcessOutput(TCFLaunch.this, peocess_id, no, data);
}
+ if (error != null) {
+ for (Listener l : listeners) l.onProcessStreamError(TCFLaunch.this, peocess_id, no, error, 0);
+ }
if (eos || error != null) {
- disconnected = true;
- // TODO: report error reading process output
disconnectStream(id);
- return;
}
- streams.read(id, 0x1000, this);
+ else {
+ streams.read(id, 0x1000, this);
+ }
}
};
streams.read(id, 0x1000, done);
@@ -539,15 +547,21 @@ public class TCFLaunch extends Launch {
return process;
}
- public void writeProcessInputStream(byte[] buf, int pos, int len) {
+ public void writeProcessInputStream(byte[] buf, int pos, final int len) throws Exception {
assert Protocol.isDispatchThread();
- if (channel.getState() != IChannel.STATE_OPEN) return;
- if (process_input_stream_id == null) return;
+ final String id = process_input_stream_id;
+ if (channel.getState() != IChannel.STATE_OPEN) throw new IOException("Connection closed");
+ if (process == null) throw new IOException("No target process");
+ final String prs = process.getID();
IStreams streams = getService(IStreams.class);
- if (streams == null) return;
- streams.write(process_input_stream_id, buf, pos, len, new IStreams.DoneWrite() {
+ if (streams == null) throw new IOException("Streams service not available");
+ if (stream_ids.get(id) == null) throw new IOException("Input stream not available");
+ streams.write(id, buf, pos, len, new IStreams.DoneWrite() {
public void doneWrite(IToken token, Exception error) {
- // TODO: stream write error handling
+ if (error == null) return;
+ if (stream_ids.get(id) == null) return;
+ for (Listener l : listeners) l.onProcessStreamError(TCFLaunch.this, prs, 0, error, len);
+ disconnectStream(id);
}
});
}

Back to the top