/// <summary> /// Sends a message and blocks until the response is complete or /// the timeout period passes. Dispose will be called on the resulting /// request. /// </summary> /// <param name="msg">The message to send.</param> /// <param name="hasData">Whether the response has data.</param> /// <param name="req">The request if completed.</param> /// <returns>True if sent and acknowledged. False otherwise.</returns> private bool SendRequest(Message msg, bool hasData, out Request req) { using (req = new Request(msg, new AutoResetEvent(false), hasData)) { return this.SendRequest(req); } }
/// <summary> /// Sends a message and blocks until the response is complete or /// the timeout period passes. /// </summary> /// <param name="msg">The message to send.</param> /// <param name="hasData">Whether the response has data.</param> /// <returns>True if sent and acknowledged. False otherwise.</returns> private bool SendRequest(Message msg, bool hasData) { Request _; return this.SendRequest(msg, hasData, out _); }
/// <summary> /// Synchronously sends a message to the connected GDB stub. This cannot /// be called while the message loop is active. /// </summary> /// <param name="msg">The message to send.</param> /// <returns>Receipt acknowledgemenet. True if no-ack enabled.</returns> private bool SendMessage(Message msg) { // Send data socket.Send(msg.GetMessageBytes()); // Receive confirmation if (this.confirmReceipt) { lock (this.buffer) { int recv = socket.Receive(this.buffer, 0, 1, SocketFlags.None); if (recv != 1) throw new IOException(); switch ((char)this.buffer[0]) { case '+': return true; case '-': return false; default: throw new IOException(); } } } else return true; }
/// <summary> /// Synchronously receives a message from the GDB stub. This cannot /// be called while the message loop is active. /// </summary> /// <returns>The received message.</returns> private Message ReceiveMessage() { lock (this.buffer) { try { var msg = new Message(this.buffer, 0, socket.Receive(this.buffer)); socket.Send(new byte[] { (byte)'+' }); return msg; } catch (FormatException) { socket.Send(new byte[] { (byte)'-' }); throw; } } }
private void MessageLoop(IAsyncResult token) { // End receive int received = this.socket.EndReceive(token); // Yup. This is a goto. For real. Deal with it. // If we've received nothing, skip all processing. if (received == 0) goto beginReceive; bool? ack = null; int offset = 0; // Look for +/- acknowledgements if (this.confirmReceipt) { for (int i = 0; i < received; i++) { if (buffer[i] == '+' || buffer[i] == '-') { // If we've already parsed an acknowledgement if (ack.HasValue) { throw new Exception("Double ack in GDB message loop. " + "Please report this to the development team."); } // Set ack accordingly ack = buffer[i] == '+'; // Increment offset offset++; } else break; } // Missing acknowledgements should result in timeouts in requests or // null ack values. } // Lock request queue Monitor.Enter(this.requests); // Set the acknowledgement if (ack != null && this.requests.Count != 0) { this.requests.Peek().Acknowledge(ack.Value); } // Now look for response data if (received - offset > 0) { try { var msg = new Message(this.buffer, offset, received); // Send acknowledgement if (this.confirmReceipt) { socket.Send(new byte[] { (byte)'+' }); } // Check for stop replies - we handle those differently if (msg.IsStopReply) { this.HandleStopReply(msg); } else // Handle request. Disconnect on error. { this.requests.Dequeue().HandleResponse(msg); } } catch (FormatException) { // Send acknowledgement if (this.confirmReceipt) { socket.Send(new byte[] { (byte)'-' }); } // Disconnect and throw Monitor.Exit(this.requests); this.Disconnect(); } catch { Monitor.Exit(this.requests); this.Disconnect(); throw; } } // Handle requests without response datak else if (ack != null && this.requests.Count != 0 && !this.requests.Peek().HasResponseData) { // Handle request. Disconnect on error. try { this.requests.Dequeue().HandleResponse(null); } catch { Monitor.Exit(this.requests); this.Disconnect(); throw; } } try { // Check for request to send if (requests.Count != 0 && !requests.Peek().Sent) { this.socket.Send(requests.Peek().Message.GetMessageBytes()); requests.Peek().Sent = true; } } finally { // Unlock request queue Monitor.Exit(this.requests); } // Begin receiving again beginReceive: this.socket.BeginReceive(this.buffer, 0, this.buffer.Length, SocketFlags.None, this.MessageLoop, null); }
private void HandleStopReply(Message msg) { if (msg.Data[0] == 'O') { // It's actually just console output if (this.ConsoleOutput != null) { // Use ThreadPool so that we don't interrupt the message loop thread ThreadPool.QueueUserWorkItem((o) => this.ConsoleOutput(msg.Data.Remove(0, 1))); } } else if (msg.Data[0] == 'F') { return; // Ignore system call requests } else // We have an actual stop reply { StopReply reply = new StopReply(msg.Data); if (reply.Reason == StopReason.Trap || reply.Reason == StopReason.Watchpoint) { if (this.Paused != null) { // Use ThreadPool so that we don't interrupt the message loop thread ThreadPool.QueueUserWorkItem((o) => this.Paused(reply)); } } else if (reply.Reason == StopReason.Termination) { if (this.Terminated != null) { // Use ThreadPool so that we don't interrupt the message loop thread ThreadPool.QueueUserWorkItem((o) => this.Terminated()); } } } }