Cosmos/source2/VSIP/Cosmos.VS.Windows/PipeThread.cs
Sentinel209_cp 731a1a00ac
2011-07-04 23:32:48 +00:00

139 lines
5.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Windows.Threading;
using System.Windows;
using Cosmos.Compiler.Debug;
using System.Threading;
using Cosmos.Cosmos_VS_Windows;
namespace Cosmos.VS.Debug
{
class PipeThread
{
static protected bool KillThread = false;
static protected NamedPipeServerStream mPipe;
static public event Action<byte, byte[]> DataPacketReceived;
protected const string PipeName = @"Cosmos\DebugWindows";
static public void Stop()
{
PipeThread.KillThread = true;
if (mPipe.IsConnected)
{
mPipe.Close();
}
else
{
// Kick it out of the WaitForConnection
var xPipe = new NamedPipeClientStream(".", PipeThread.PipeName, PipeDirection.Out);
xPipe.Connect(100);
}
}
// See comment in ctor as to why we have to make this new ReadByte replacement
static byte ReadByte()
{
byte[] xByte = new byte[1];
if (mPipe.Read(xByte, 0, 1) == 0)
{
throw new Exception("Pipe has been closed.");
}
return xByte[0];
}
static public void ThreadStartServer()
{
try
{
// Some idiot MS intern must have written the blocking part of pipes. There is no way to
// cancel WaitForConnection, or ReadByte. (pipes introduced in 3.5, I thought one time I read
// that 4.0 added an abort option, but I cannot find it)
// If you set Async as the option, but use sync calls, .Close can kind of kill them.
// It causes exceptions to be raised in WaitForConnection and ReadByte (possibly due to another
// issue with threads and exceptions without handlers, maybe check again later), but they just
// loop over and over on it... READ however with the async option WILL exit with 0....
// Its like VB1 and adding to sorted listboxes over all again... no one dogfooded this stuff.
// And yes we could use async.. but its SOOO much messier and far more complicated than it ever
// should be.
//
// Here is an interesting approach using async and polling... If need be we can go that way:
// http://stackoverflow.com/questions/2700472/how-to-terminate-a-managed-thread-blocked-in-unmanaged-code
while (!KillThread)
{ // Loop again to allow mult incoming connections between debug sessions
using (mPipe = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous))
{
mPipe.WaitForConnection();
byte xCmd;
int xSize;
while (mPipe.IsConnected && !KillThread)
{
xCmd = ReadByte();
xSize = ReadByte() << 8;
xSize = xSize | ReadByte();
byte[] xMsg = new byte[xSize];
mPipe.Read(xMsg, 0, xSize);
DataPacketReceived(xCmd, xMsg);
}
}
}
}
catch
{
// Threads MUST have an exception handler
// Otherwise there are side effects when an exception occurs
}
}
}
class PipeCallback
{
static public void InitPipe()
{
PipeThread.DataPacketReceived += new Action<byte, byte[]>(PipeThread_DataPacketReceived);
var xServerThread = new Thread(PipeThread.ThreadStartServer);
xServerThread.Start();
}
static void PipeThread_DataPacketReceived(byte aCmd, byte[] aMsg)
{
switch (aCmd)
{
case DwMsgType.Noop:
break;
case DwMsgType.Stack:
break;
case DwMsgType.Frame:
break;
case DwMsgType.Registers:
RegistersTW.mUC.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate()
{
RegistersTW.mUC.Update(aMsg);
});
break;
case DwMsgType.Quit:
//Close();
break;
case DwMsgType.AssemblySource:
AssemblyTW.mUC.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate()
{
AssemblyTW.mUC.Update(aMsg);
});
break;
}
}
}
}