PageRenderTime 26ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/client_vNext/Framework/Debugger/WireProtocol/Controller.cs

#
C# | 412 lines | 311 code | 85 blank | 16 comment | 36 complexity | e779a857580a6ed4b4bea09df695f96f MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, MIT, MPL-2.0-no-copyleft-exception
  1. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. // This file is part of the Microsoft .NET Micro Framework Porting Kit Code Samples and is unsupported.
  3. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files except in compliance with the License.
  6. // You may obtain a copy of the License at:
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing
  12. // permissions and limitations under the License.
  13. //
  14. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  15. using System;
  16. using System.Collections;
  17. using System.IO;
  18. using System.Text;
  19. using System.Reflection;
  20. using System.Threading;
  21. using System.Runtime.Serialization;
  22. using System.Runtime.CompilerServices;
  23. using DEBUG=System.Diagnostics.Debug;
  24. namespace Microsoft.SPOT.Debugger.WireProtocol
  25. {
  26. public class Controller : IControllerLocal
  27. {
  28. internal byte[] marker_Debugger = Encoding.UTF8.GetBytes( Packet.MARKER_DEBUGGER_V1 );
  29. internal byte[] marker_Packet = Encoding.UTF8.GetBytes( Packet.MARKER_PACKET_V1 );
  30. private string m_marker;
  31. private IControllerHostLocal m_app;
  32. private Stream m_port;
  33. private int m_lastOutboundMessage;
  34. private DateTime m_lastActivity = DateTime.UtcNow;
  35. private int m_nextEndpointId;
  36. private FifoBuffer m_inboundData;
  37. private Thread m_inboundDataThread;
  38. private Thread m_stateMachineThread;
  39. private bool m_fProcessExit;
  40. private ManualResetEvent m_evtShutdown;
  41. private State m_state;
  42. private CLRCapabilities m_capabilities;
  43. private WaitHandle[] m_waitHandlesRead;
  44. public Controller( string marker, IControllerHostLocal app )
  45. {
  46. m_marker = marker;
  47. m_app = app;
  48. Random random = new Random();
  49. m_lastOutboundMessage = random.Next( 65536 );
  50. m_nextEndpointId = random.Next( int.MaxValue );
  51. m_state = new State( this );
  52. //default capabilities
  53. m_capabilities = new CLRCapabilities();
  54. }
  55. internal Converter CreateConverter()
  56. {
  57. return new Converter( m_capabilities );
  58. }
  59. private Thread CreateThread( ThreadStart ts )
  60. {
  61. Thread th = new Thread( ts );
  62. th.IsBackground = true;
  63. th.Start();
  64. return th;
  65. }
  66. public DateTime LastActivity
  67. {
  68. get
  69. {
  70. return m_lastActivity;
  71. }
  72. }
  73. public bool IsPortConnected
  74. {
  75. [MethodImplAttribute( MethodImplOptions.Synchronized )]
  76. get
  77. {
  78. return (m_port != null);
  79. }
  80. }
  81. public Packet NewPacket()
  82. {
  83. if(!m_state.IsRunning)
  84. throw new ArgumentException( "Controller not started, cannot create message" );
  85. Packet bp = new Packet();
  86. SetSignature( bp, m_marker );
  87. bp.m_seq = (ushort)Interlocked.Increment( ref m_lastOutboundMessage );
  88. return bp;
  89. }
  90. public bool QueueOutput(MessageRaw raw)
  91. {
  92. SendRawBuffer(raw.m_header);
  93. if (raw.m_payload != null)
  94. SendRawBuffer(raw.m_payload);
  95. return true;
  96. }
  97. [MethodImplAttribute( MethodImplOptions.Synchronized )]
  98. public void ClosePort()
  99. {
  100. if( m_port == null )
  101. return;
  102. try
  103. {
  104. m_port.Dispose( );
  105. }
  106. finally
  107. {
  108. m_port = null;
  109. }
  110. }
  111. public void Start()
  112. {
  113. m_state.SetValue( State.Value.Starting, true );
  114. m_inboundData = new FifoBuffer();
  115. m_evtShutdown = new ManualResetEvent( false );
  116. m_waitHandlesRead = new WaitHandle[] { m_evtShutdown, m_inboundData.WaitHandle };
  117. m_inboundDataThread = CreateThread( new ThreadStart( this.ReceiveInput ) );
  118. m_stateMachineThread = CreateThread( new ThreadStart( this.Process ) );
  119. m_state.SetValue( State.Value.Started, false );
  120. }
  121. public void StopProcessing()
  122. {
  123. m_state.SetValue( State.Value.Stopping, false );
  124. m_evtShutdown.Set();
  125. if (m_inboundDataThread != null)
  126. {
  127. m_inboundDataThread.Join();
  128. m_inboundDataThread = null;
  129. }
  130. if (m_stateMachineThread != null)
  131. {
  132. m_stateMachineThread.Join();
  133. m_stateMachineThread = null;
  134. }
  135. }
  136. public void ResumeProcessing()
  137. {
  138. m_evtShutdown.Reset();
  139. m_state.SetValue(State.Value.Resume, false);
  140. if (m_inboundDataThread == null)
  141. {
  142. m_inboundDataThread = CreateThread(new ThreadStart(this.ReceiveInput));
  143. }
  144. if (m_stateMachineThread == null)
  145. {
  146. m_stateMachineThread = CreateThread(new ThreadStart(this.Process));
  147. }
  148. }
  149. public void Stop()
  150. {
  151. if (m_evtShutdown != null)
  152. {
  153. m_evtShutdown.Set();
  154. }
  155. if (m_state.SetValue(State.Value.Stopping, false))
  156. {
  157. ((IController)this).StopProcessing();
  158. ((IController)this).ClosePort();
  159. m_state.SetValue( State.Value.Stopped, false );
  160. }
  161. }
  162. public uint GetUniqueEndpointId()
  163. {
  164. int id = Interlocked.Increment( ref m_nextEndpointId );
  165. return (uint)id;
  166. }
  167. public CLRCapabilities Capabilities
  168. {
  169. get { return m_capabilities ; }
  170. set { m_capabilities = value; }
  171. }
  172. [MethodImplAttribute(MethodImplOptions.Synchronized)]
  173. public Stream OpenPort()
  174. {
  175. if(m_port == null)
  176. {
  177. m_port = App.OpenConnection();
  178. }
  179. return m_port;
  180. }
  181. internal IControllerHostLocal App
  182. {
  183. get
  184. {
  185. return m_app;
  186. }
  187. }
  188. internal int Read( byte[] buf, int offset, int count )
  189. {
  190. //wait on inbound data, or on exit....
  191. int countRequested = count;
  192. while (count > 0 && WaitHandle.WaitAny(m_waitHandlesRead) != 0)
  193. {
  194. System.Diagnostics.Debug.Assert(m_inboundData.Available > 0);
  195. int cBytesRead = m_inboundData.Read( buf, offset, count );
  196. offset += cBytesRead;
  197. count -= cBytesRead;
  198. }
  199. return countRequested - count;
  200. }
  201. internal void SetSignature( Packet bp, string sig )
  202. {
  203. byte[] buf = Encoding.UTF8.GetBytes( sig );
  204. Array.Copy( buf, 0, bp.m_signature, 0, buf.Length );
  205. }
  206. private void ProcessExit()
  207. {
  208. bool fExit = false;
  209. lock(this)
  210. {
  211. if(!m_fProcessExit)
  212. {
  213. m_fProcessExit = true;
  214. fExit = true;
  215. }
  216. }
  217. if(fExit)
  218. {
  219. App.ProcessExited();
  220. }
  221. }
  222. private void Process()
  223. {
  224. MessageReassembler msg = new MessageReassembler( this );
  225. while(m_state.IsRunning)
  226. {
  227. try
  228. {
  229. msg.Process();
  230. }
  231. catch(ThreadAbortException)
  232. {
  233. Stop();
  234. break;
  235. }
  236. catch
  237. {
  238. ClosePort();
  239. throw;
  240. }
  241. }
  242. }
  243. private void ReceiveInput()
  244. {
  245. byte[] buf = new byte[128];
  246. int invalidOperationRetry = 5;
  247. while(m_state.IsRunning)
  248. {
  249. try
  250. {
  251. Stream stream = OpenPort();
  252. IStreamAvailableCharacters streamAvail = stream as IStreamAvailableCharacters;
  253. int avail = 0;
  254. if (streamAvail != null)
  255. {
  256. avail = streamAvail.AvailableCharacters;
  257. if (avail == 0)
  258. {
  259. Thread.Yield();
  260. continue;
  261. }
  262. }
  263. if (avail == 0)
  264. avail = 1;
  265. if (avail > buf.Length)
  266. buf = new byte[avail];
  267. int read = stream.Read(buf, 0, avail);
  268. if (read > 0)
  269. {
  270. m_lastActivity = DateTime.UtcNow;
  271. m_inboundData.Write(buf, 0, read);
  272. }
  273. else if (read == 0)
  274. {
  275. Thread.Yield();
  276. }
  277. }
  278. catch (ProcessExitException)
  279. {
  280. ProcessExit();
  281. ClosePort();
  282. return;
  283. }
  284. catch (InvalidOperationException)
  285. {
  286. if(invalidOperationRetry <= 0)
  287. {
  288. ProcessExit();
  289. ClosePort();
  290. return;
  291. }
  292. invalidOperationRetry--;
  293. ClosePort();
  294. Thread.Yield();
  295. }
  296. catch (IOException)
  297. {
  298. ClosePort();
  299. Thread.Yield( );
  300. }
  301. catch
  302. {
  303. ClosePort();
  304. throw;
  305. }
  306. }
  307. }
  308. public void SendRawBuffer( byte[] buf )
  309. {
  310. try
  311. {
  312. Stream stream = OpenPort();
  313. stream.Write(buf, 0, buf.Length);
  314. stream.Flush();
  315. }
  316. catch (ProcessExitException)
  317. {
  318. ProcessExit();
  319. }
  320. catch
  321. {
  322. ClosePort();
  323. throw;
  324. }
  325. }
  326. }
  327. }