1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

Buf fix in MIInferior.

This commit is contained in:
Alain Magloire 2002-08-20 04:30:08 +00:00
parent 1c66d960ea
commit fa183e80b0
6 changed files with 242 additions and 182 deletions

View file

@ -10,8 +10,8 @@ import java.io.IOException;
import org.eclipse.cdt.debug.mi.core.event.MIEvent;
/**
* Transmission command thread blocks on the command Queue
* and wake cmd are available and push them to gdb out channel.
* Event Thread blocks on the event Queue, wakes up
* when events are available and notify all the observers.
*/
public class EventThread extends Thread {
@ -22,29 +22,24 @@ public class EventThread extends Thread {
session = s;
}
public void run () {
try {
while (true) {
public void run() {
// signal by the session of time to die.
while (session.getChannelOutputStream() != null) {
MIEvent event = null;
Queue eventQueue = session.getEventQueue();
// removeItem() will block until an item is available.
try {
event = (MIEvent)eventQueue.removeItem();
event = (MIEvent) eventQueue.removeItem();
} catch (InterruptedException e) {
// signal by the session of time to die.
if (session.getChannelOutputStream() == null) {
throw new IOException();
}
//e.printStackTrace();
}
try {
if (event != null) {
session.notifyObservers(event);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
//e.printStackTrace();
}
}
}

View file

@ -3,36 +3,47 @@ package org.eclipse.cdt.debug.mi.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import org.eclipse.cdt.debug.mi.core.command.CLICommand;
import org.eclipse.cdt.debug.mi.core.command.CommandFactory;
import org.eclipse.cdt.debug.mi.core.command.MIExecAbort;
import org.eclipse.cdt.debug.mi.core.command.MIGDBExit;
import org.eclipse.cdt.debug.mi.core.command.MIGDBShowExitCode;
import org.eclipse.cdt.debug.mi.core.event.MIExitEvent;
import org.eclipse.cdt.debug.mi.core.event.MIInferiorExitEvent;
import org.eclipse.cdt.debug.mi.core.output.MIGDBShowExitCodeInfo;
/**
* @author alain
*
* To change this generated comment edit the template variable "typecomment":
* Window>Preferences>Java>Templates.
* To enable and disable the creation of type comments go to
* Window>Preferences>Java>Code Generation.
*/
public class MIInferior extends Process {
public final static int SUSPENDED = 1;
public final static int RUNNING = 2;
public final static int TERMINATED = 4;
final static int SUSPENDED = 1;
final static int RUNNING = 2;
final static int TERMINATED = 4;
boolean connected = false;
int state = 0;
MISession session;
OutputStream out;
PipedInputStream in;
PipedOutputStream inPiped;
PipedInputStream err;
PipedOutputStream errPiped;
MIInferior(MISession mi) {
session = mi;
}
/**
* @see java.lang.Process#getOutputStream()
*/
public OutputStream getOutputStream() {
if (out == null) {
out = new OutputStream() {
StringBuffer buf = new StringBuffer();
public void write(int b) throws IOException {
@ -57,11 +68,6 @@ public class MIInferior extends Process {
}
};
}
/**
* @see java.lang.Process#getOutputStream()
*/
public OutputStream getOutputStream() {
return out;
}
@ -69,15 +75,30 @@ public class MIInferior extends Process {
* @see java.lang.Process#getInputStream()
*/
public InputStream getInputStream() {
return session.getTargetStream();
if (in == null) {
try {
inPiped = new PipedOutputStream();
in = new PipedInputStream(inPiped);
} catch (IOException e) {
}
}
return in;
}
/**
* @see java.lang.Process#getErrorStream()
*/
public InputStream getErrorStream() {
// FIXME the same as output??
return session.getTargetStream();
// FIXME: We do not have any err stream from gdb/mi
// so this gdb err channel instead.
if (err == null) {
try {
errPiped = new PipedOutputStream();
err = new PipedInputStream(errPiped);
} catch (IOException e) {
}
}
return err;
}
/**
@ -96,7 +117,7 @@ public class MIInferior extends Process {
* @see java.lang.Process#exitValue()
*/
public int exitValue() {
if (isTerminated()) {
if (isTerminated() && !session.isTerminated()) {
CommandFactory factory = session.getCommandFactory();
MIGDBShowExitCode code = factory.createMIGDBShowExitCode();
try {
@ -114,29 +135,15 @@ public class MIInferior extends Process {
* @see java.lang.Process#destroy()
*/
public void destroy() {
/*
if (!isTerminated()) {
CommandFactory factory = session.getCommandFactory();
MIExecAbort abort = factory.createMIExecAbort();
try {
session.postCommand(abort);
setTerminated();
session.getRxThread().fireEvent(new MIInferiorExitEvent());
} catch (MIException e) {
}
}
*/
if (!isTerminated()) {
if (!isSuspended())
{
// interrupt execution
}
CommandFactory factory = session.getCommandFactory();
MIGDBExit exit = factory.createMIGDBExit();
try {
session.postCommand(exit);
} catch (MIException e) {
}
setTerminated();
}
}
@ -152,6 +159,18 @@ public class MIInferior extends Process {
return state == TERMINATED;
}
public boolean isConnected() {
return connected;
}
public synchronized void setConnected() {
connected = true;
}
public synchronized void setDisConnected() {
connected = false;
}
public synchronized void setSuspended() {
state = SUSPENDED;
}
@ -162,6 +181,31 @@ public class MIInferior extends Process {
public synchronized void setTerminated() {
state = TERMINATED;
// Close the streams.
try {
if (inPiped != null) {
inPiped.close();
inPiped = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (errPiped != null) {
errPiped.close();
errPiped = null;
}
} catch (IOException e) {
e.printStackTrace();
}
notifyAll();
}
public OutputStream getPipedOutputStream() {
return inPiped;
}
public OutputStream getPipedErrorStream() {
return errPiped;
}
}

View file

@ -51,10 +51,10 @@ public class MIPlugin extends Plugin {
String[]args = new String[]{"gdb", "-q", "-i", "mi", program};
Process gdb = Runtime.getRuntime().exec(args);
MISession session = createMISession(gdb.getInputStream(), gdb.getOutputStream());
/*
///*
try {
CommandFactory factory = session.getCommandFactory();
MIBreakInsert bkpt= factory.createMIBreakInsert(true, false, null, 0, "main");
MIBreakInsert bkpt= factory.createMIBreakInsert(true, false, null, 0, "routine");
session.postCommand(bkpt);
MIInfo info = bkpt.getMIInfo();
if (info == null) {
@ -63,7 +63,7 @@ public class MIPlugin extends Plugin {
} catch (MIException e) {
throw new IOException("Failed to attach");
}
*/
//*/
return new CSession(session);
}

View file

@ -15,6 +15,7 @@ import org.eclipse.cdt.debug.mi.core.command.Command;
import org.eclipse.cdt.debug.mi.core.command.CommandFactory;
import org.eclipse.cdt.debug.mi.core.command.MIGDBExit;
import org.eclipse.cdt.debug.mi.core.command.MIGDBSet;
import org.eclipse.cdt.debug.mi.core.output.MIInfo;
import org.eclipse.cdt.debug.mi.core.output.MIOutput;
import org.eclipse.cdt.debug.mi.core.output.MIParser;
@ -39,10 +40,6 @@ public class MISession extends Observable {
PipedInputStream miInPipe;
PipedOutputStream miOutPipe;
PipedInputStream targetInPipe;
PipedOutputStream targetOutPipe;
PipedInputStream logInPipe;
PipedOutputStream logOutPipe;
CommandFactory factory;
@ -61,59 +58,62 @@ public class MISession extends Observable {
public MISession(InputStream i, OutputStream o) {
inChannel = i;
outChannel = o;
factory = new CommandFactory();
parser = new MIParser();
txQueue = new CommandQueue();
rxQueue = new CommandQueue();
eventQueue = new Queue();
txThread = new TxThread(this);
rxThread = new RxThread(this);
eventThread = new EventThread(this);
txThread.start();
rxThread.start();
eventThread.start();
try {
miOutPipe = new PipedOutputStream();
miInPipe = new PipedInputStream(miOutPipe);
targetOutPipe = new PipedOutputStream();
targetInPipe = new PipedInputStream(targetOutPipe);
logOutPipe = new PipedOutputStream();
logInPipe = new PipedInputStream(logOutPipe);
} catch (IOException e) {
}
inferior = new MIInferior(this);
try {
postCommand(new MIGDBSet(new String[]{"confirm", "off"}));
// Disable a certain number of irritations from gdb.
// Like confirmation and screen size.
MIInfo info;
MIGDBSet confirm = new MIGDBSet(new String[]{"confirm", "off"});
postCommand(confirm);
info = confirm.getMIInfo();
MIGDBSet width = new MIGDBSet(new String[]{"width", "99999999"});
postCommand(width);
info = confirm.getMIInfo();
MIGDBSet height = new MIGDBSet(new String[]{"height", "99999999"});
postCommand(height);
info = confirm.getMIInfo();
} catch (MIException e) {
// FIXME: Do not catch the exception but pass it up.
}
}
/**
* get Console Stream.
* get MI Console Stream.
*/
public InputStream getMIStream() {
if (miInPipe == null) {
try {
miOutPipe = new PipedOutputStream();
miInPipe = new PipedInputStream(miOutPipe);
} catch (IOException e) {
}
}
return miInPipe;
}
/**
* Get Target Stream.
*/
public InputStream getTargetStream() {
return targetInPipe;
}
/**
* Get Log Stream
*/
public InputStream getLogStream() {
return logInPipe;
}
/**
* For example the CDI/MI adapters uses the command
* For example the CDI/MI bridge uses the command
* factory to create MI commands this allow overloading.
*/
public CommandFactory getCommandFactory() {
@ -121,21 +121,21 @@ public class MISession extends Observable {
}
/**
* Set a new factory to use in CDI/MI adapters.
* Set a new factory to use for command.
*/
public void setCommandFactory(CommandFactory f) {
factory = f;
}
/**
* Return the MI main parser.
* Return the MI parser.
*/
public MIParser getMIParser() {
return parser;
}
/**
* Reset the parser.
* Reset the MI parser.
*/
public void setMIParser(MIParser p) {
parser = p;
@ -156,6 +156,7 @@ public class MISession extends Observable {
}
/**
* equivalent to:
* postCommand(cmd, 10 secs)
*/
public void postCommand(Command cmd) throws MIException {
@ -163,13 +164,14 @@ public class MISession extends Observable {
}
/**
* Sends a command to gdb.
* Sends a command to gdb, and wait(timeout) for a response.
*/
public void postCommand(Command cmd, long timeout) throws MIException {
static int number = 1;
public synchronized void postCommand(Command cmd, long timeout) throws MIException {
MIPlugin.getDefault().debugLog(cmd.toString());
MIPlugin.getDefault().debugLog(number++ + " " + cmd.toString());
// Test if we in a sane state.
// Test if we are in a sane state.
if (!txThread.isAlive() || !rxThread.isAlive()) {
throw new MIException("{R,T}xThread terminated");
}
@ -178,8 +180,6 @@ public class MISession extends Observable {
// Wait for the response or timedout
synchronized (cmd) {
// Do not wait for command if time out is 0
if (timeout > 0) {
// RxThread will set the MIOutput on the cmd
// when the response arrive.
while (cmd.getMIOutput() == null) {
@ -193,38 +193,44 @@ public class MISession extends Observable {
}
}
}
}
/**
* Return the inferior "Process".
*/
public MIInferior getMIInferior() {
return inferior;
}
/**
* Check if the gdb session is terminated.
*/
public boolean isTerminated() {
return (!txThread.isAlive() || !rxThread.isAlive());
}
/**
* Close the MISession.
* Terminate the MISession.
*/
public void terminate() {
// Destroy any MI Inferior
// Destroy any MI Inferior(Process)
inferior.destroy();
// send the exit.
// send the exit(-gdb-exit).
try {
MIGDBExit exit = factory.createMIGDBExit();
postCommand(exit);
} catch (MIException e) {
}
// Explicitely close the channels
// Close the input GDB prompt
try {
inChannel.close();
} catch (IOException e) {
}
inChannel = null;
// Close the output GDB prompt
try {
outChannel.close();
} catch (IOException e) {
@ -232,30 +238,39 @@ public class MISession extends Observable {
// This is __needed__ to stop the txThread and eventThread.
outChannel = null;
// Make sure all threads are gone.
// Kill the Transmition thread.
try {
if (txThread.isAlive()) {
txThread.interrupt();
}
txThread.join();
txThread.join(cmdTimeout);
} catch (InterruptedException e) {
}
// Kill the Receiving Thread.
try {
if (rxThread.isAlive()) {
rxThread.interrupt();
}
rxThread.join();
rxThread.join(cmdTimeout);
} catch (InterruptedException e) {
}
// Kill the event Thread.
try {
if (eventThread.isAlive()) {
eventThread.interrupt();
}
eventThread.join();
eventThread.join(cmdTimeout);
} catch (InterruptedException e) {
}
// Destroy the MI console stream.
try {
miOutPipe.close();
miInPipe = null;
} catch (IOException e) {
}
}
/**
@ -271,14 +286,6 @@ public class MISession extends Observable {
return miOutPipe;
}
OutputStream getTargetPipe() {
return targetOutPipe;
}
OutputStream getLogPipe() {
return logOutPipe;
}
CommandQueue getTxQueue() {
return txQueue;
}

View file

@ -44,15 +44,17 @@ import org.eclipse.cdt.debug.mi.core.output.MITargetStreamOutput;
import org.eclipse.cdt.debug.mi.core.output.MIValue;
/**
* Receiving thread of gdb, read the input channel.
* Receiving thread of gdb response output.
*/
public class RxThread extends Thread {
final MISession session;
List oobList;
public RxThread(MISession s) {
super("MI RX Thread");
session = s;
oobList = new ArrayList();
}
/*
@ -62,7 +64,6 @@ public class RxThread extends Thread {
public void run () {
BufferedReader reader =
new BufferedReader(new InputStreamReader(session.getChannelInputStream()));
StringBuffer buffer = new StringBuffer();
try {
while (true) {
String line;
@ -121,20 +122,33 @@ MIPlugin.getDefault().debugLog(line);
fireEvent(event);
} else if ("exit".equals(state)) {
session.getMIInferior().setTerminated();
fireEvent(new MIExitEvent());
MIEvent event = new MIExitEvent();
fireEvent(event);
} else if ("connected".equals(state)) {
session.getMIInferior().setConnected();
}
// Clear the accumulate oobList on each new Result Command
// response.
MIOOBRecord [] oobRecords =
(MIOOBRecord[])oobList.toArray(new MIOOBRecord[0]);
oobList.clear();
// Notify the waiting command.
if (cmd != null) {
synchronized (cmd) {
// Set the accumulate console Stream
response.setMIOOBRecords(oobRecords);
cmd.setMIOutput(response);
cmd.notifyAll();
}
}
// Some result record contains informaton specific to oob.
// This will happen when CLI-Command is use, for example
// doing "run" will block and return a breakpointhit
processMIOOBRecord(rr, list);
}
// Process OOBs
@ -162,21 +176,18 @@ MIPlugin.getDefault().debugLog(line);
void processMIOOBRecord(MIAsyncRecord async, List list) {
if (async instanceof MIExecAsyncOutput) {
MIExecAsyncOutput exec = (MIExecAsyncOutput)async;
MIEvent e = null;
// Change of state.
String state = exec.getAsyncClass();
if ("stopped".equals(state)) {
MIEvent e = null;
session.getMIInferior().setSuspended();
}
MIResult[] results = exec.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
MIValue val = results[i].getMIValue();
if (var.equals("reason")) {
if (val instanceof MIConst) {
String reason = ((MIConst)val).getString();
String reason =((MIConst)val).getString();
e = createEvent(reason, exec);
if (e != null) {
list.add(e);
@ -193,6 +204,7 @@ MIPlugin.getDefault().debugLog(line);
list.add(e);
}
}
}
} else if (async instanceof MIStatusAsyncOutput) {
// Nothing done .. but what about +download??
} else if (async instanceof MINotifyAsyncOutput) {
@ -214,8 +226,11 @@ MIPlugin.getDefault().debugLog(line);
}
}
}
// Accumulate the Console Stream Output response for parsing.
// Some commands will put valuable info in the Console Stream.
oobList.add(stream);
} else if (stream instanceof MITargetStreamOutput) {
OutputStream target = session.getTargetPipe();
OutputStream target = session.getMIInferior().getPipedOutputStream();
if (target != null) {
MITargetStreamOutput out = (MITargetStreamOutput)stream;
String str = out.getString();
@ -228,7 +243,7 @@ MIPlugin.getDefault().debugLog(line);
}
}
} else if (stream instanceof MILogStreamOutput) {
OutputStream log = session.getLogPipe();
OutputStream log = session.getMIInferior().getPipedErrorStream();
if (log != null) {
MILogStreamOutput out = (MILogStreamOutput)stream;
String str = out.getString();
@ -310,13 +325,13 @@ MIPlugin.getDefault().debugLog(line);
event = new MIFunctionFinishedEvent(rr);
}
} else if ("exited-normally".equals(reason)) {
// session.getMIInferior().setTerminated();
session.getMIInferior().setTerminated();
event = new MIInferiorExitEvent();
} else if ("exited-signalled".equals(reason)) {
// session.getMIInferior().setTerminated();
session.getMIInferior().setTerminated();
event = new MIInferiorExitEvent();
} else if ("exited".equals(reason)) {
// session.getMIInferior().setTerminated();
session.getMIInferior().setTerminated();
event = new MIInferiorExitEvent();
}
return event;

View file

@ -28,17 +28,14 @@ public class TxThread extends Thread {
public void run () {
try {
while (true) {
// signal by the session of time to die.
while (session.getChannelOutputStream() != null) {
Command cmd = null;
CommandQueue txQueue = session.getTxQueue();
// removeCommand() will block until a command is available.
try {
cmd = txQueue.removeCommand();
} catch (InterruptedException e) {
// signal by the session of time to die.
if (session.getChannelOutputStream() == null) {
throw new IOException();
}
//e.printStackTrace();
}
@ -55,10 +52,12 @@ public class TxThread extends Thread {
// shove in the pipe
String str = cmd.toString();
OutputStream out = session.getChannelOutputStream();
if (out != null) {
out.write(str.getBytes());
out.flush();
}
}
}
} catch (IOException e) {
//e.printStackTrace();
}