[Lldb-commits] [lldb] r212923 - Modified gdb-remote tests to run with automatically-chosen ports.

Todd Fiala todd.fiala at gmail.com
Sun Jul 13 23:24:45 PDT 2014


Author: tfiala
Date: Mon Jul 14 01:24:44 2014
New Revision: 212923

URL: http://llvm.org/viewvc/llvm-project?rev=212923&view=rev
Log:
Modified gdb-remote tests to run with automatically-chosen ports.

Now that llgs supports communicating the 0-port choose-a-port
mechanism and can communicate that back to a caller via the
--named-pipe option (at parity with debugserver), we use this
mechanism to always start llgs and debugserver gdb-remote
protocol tests without needing to use some port arbitration
mechanism.  This eliminates some potential intermittent failures vs. the
previous random port and collision-avoidance strategy used.

Removed:
    lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py
Modified:
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
    lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
    lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=212923&r1=212922&r2=212923&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Mon Jul 14 01:24:44 2014
@@ -36,8 +36,8 @@
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/NativeRegisterContext.h"
-#include "../../../Host/common/NativeProcessProtocol.h"
-#include "../../../Host/common/NativeThreadProtocol.h"
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
 
 // Project includes
 #include "Utility/StringExtractorGDBRemote.h"
@@ -3041,24 +3041,38 @@ GDBRemoteCommunicationServer::Handle_qfT
     if (!IsGdbServer())
         return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented");
 
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
     // Fail if we don't have a current process.
     if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
-        return SendErrorResponse (68);
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp");
+        return SendOKResponse ();
+    }
 
     StreamGDBRemote response;
     response.PutChar ('m');
 
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s() starting thread iteration", __FUNCTION__);
+
     NativeThreadProtocolSP thread_sp;
     uint32_t thread_index;
     for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index);
          thread_sp;
          ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
     {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID);
         if (thread_index > 0)
             response.PutChar(',');
         response.Printf ("%" PRIx64, thread_sp->GetID ());
     }
 
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s() finished thread iteration", __FUNCTION__);
+
     return SendPacketNoLock(response.GetData(), response.GetSize());
 }
 

Removed: lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py?rev=212922&view=auto
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/commandline/TestStubNamedPipe.py (removed)
@@ -1,90 +0,0 @@
-import unittest2
-
-# Add the directory above ours to the python library path since we
-# will import from there.
-import os.path
-import sys
-sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
-
-import gdbremote_testcase
-import os
-import select
-import tempfile
-import time
-from lldbtest import *
-
-class TestStubNamedPipeTestCase(gdbremote_testcase.GdbRemoteTestCaseBase):
-    def create_named_pipe(self):
-        temp_dir = tempfile.mkdtemp()
-        named_pipe_path = os.path.join(temp_dir, "stub_port_number")
-        try:
-            os.mkfifo(named_pipe_path)
-        except OSError, e:
-            # print "Failed to create named pipe: %s" % e
-            raise e
-        return named_pipe_path
-
-    def get_port_from_named_pipe(self):
-        # Set port to 0
-        self.port = 0
-
-        # Don't turn on any kind of logging
-        self.debug_monitor_extra_args = ""
-
-        # Create the named pipe that we're reading on.
-        self.named_pipe_path = self.create_named_pipe()
-        self.assertIsNotNone(self.named_pipe_path)
-        # print "using named pipe:{}".format(self.named_pipe_path)
-        try:
-            # print "launching server..."
-            server = self.launch_debug_monitor()
-            # print "server launched..."
-            self.assertIsNotNone(server)
-            self.assertTrue(server.isalive())
-            server.expect("(debugserver|lldb-gdbserver)", timeout=10)
-
-            # print "about to open named pipe..."
-            # Open the read side of the pipe in non-blocking mode.  This will return right away, ready or not.
-            fd = os.open(self.named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
-            named_pipe = os.fdopen(fd, "r")
-            self.assertIsNotNone(named_pipe)
-
-            # print "waiting on content from the named pipe..."
-            # Wait for something to read with a max timeout.
-            (ready_readers, _, _) = select.select([fd], [], [], 5)
-            self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
-            self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
-
-            try:
-                # Read the port from the named pipe.
-                stub_port_raw = named_pipe.read()
-                self.assertIsNotNone(stub_port_raw)
-                self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
-
-                # Trim null byte, convert to int.
-                stub_port_raw = stub_port_raw[:-1]
-                stub_port = int(stub_port_raw)
-                self.assertTrue(stub_port > 0)
-            finally:
-                named_pipe.close()
-            # print "stub is listening on port: {} (from text '{}')".format(stub_port, stub_port_raw)
-        finally:
-            temp_dir = os.path.dirname(self.named_pipe_path)
-            try:
-                os.remove(self.named_pipe_path)
-            except:
-                # Not required.
-                None
-            os.rmdir(temp_dir)
-
-    @debugserver_test
-    def test_get_port_from_named_pipe_debugserver(self):
-        self.init_debugserver_test()
-        self.set_inferior_startup_launch()
-        self.get_port_from_named_pipe()
-
-    @llgs_test
-    def test_get_port_from_named_pipe_llgs(self):
-        self.init_llgs_test()
-        self.set_inferior_startup_launch()
-        self.get_port_from_named_pipe()

Modified: lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py?rev=212923&r1=212922&r2=212923&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py Mon Jul 14 01:24:44 2014
@@ -3,7 +3,8 @@ Base class for gdb-remote test cases.
 """
 
 import errno
-import unittest2
+import os
+import os.path
 import pexpect
 import platform
 import random
@@ -13,11 +14,12 @@ import signal
 import socket
 import subprocess
 import sys
+import tempfile
 import time
+import unittest2
 from lldbtest import *
 from lldbgdbserverutils import *
 import logging
-import os.path
 
 class GdbRemoteTestCaseBase(TestBase):
 
@@ -51,6 +53,8 @@ class GdbRemoteTestCaseBase(TestBase):
         self.set_inferior_startup_launch()
         self.port = self.get_next_port()
         self.named_pipe_path = None
+        self.named_pipe = None
+        self.named_pipe_fd = None
 
     def get_next_port(self):
         return 12000 + random.randint(0,3999)
@@ -58,17 +62,86 @@ class GdbRemoteTestCaseBase(TestBase):
     def reset_test_sequence(self):
         self.test_sequence = GdbRemoteTestSequence(self.logger)
 
-    def init_llgs_test(self):
+    def create_named_pipe(self):
+        # Create a temp dir and name for a pipe.
+        temp_dir = tempfile.mkdtemp()
+        named_pipe_path = os.path.join(temp_dir, "stub_port_number")
+
+        # Create the named pipe.
+        os.mkfifo(named_pipe_path)
+
+        # Open the read side of the pipe in non-blocking mode.  This will return right away, ready or not.
+        named_pipe_fd = os.open(named_pipe_path, os.O_RDONLY | os.O_NONBLOCK)
+
+        # Create the file for the named pipe.  Note this will follow semantics of
+        # a non-blocking read side of a named pipe, which has different semantics
+        # than a named pipe opened for read in non-blocking mode.
+        named_pipe = os.fdopen(named_pipe_fd, "r")
+        self.assertIsNotNone(named_pipe)
+
+        def shutdown_named_pipe():
+            # Close the pipe.
+            try:
+                named_pipe.close()
+            except:
+                print "failed to close named pipe"
+                None
+
+            # Delete the pipe.
+            try:
+                os.remove(named_pipe_path)
+            except:
+                print "failed to delete named pipe: {}".format(named_pipe_path)
+                None
+
+            # Delete the temp directory.
+            try:
+                os.rmdir(temp_dir)
+            except:
+                print "failed to delete temp dir: {}, directory contents: '{}'".format(temp_dir, os.listdir(temp_dir))
+                None
+
+        # Add the shutdown hook to clean up the named pipe.
+        self.addTearDownHook(shutdown_named_pipe)
+
+        # Clear the port so the stub selects a port number.
+        self.port = 0
+
+        return (named_pipe_path, named_pipe, named_pipe_fd)
+
+    def get_stub_port_from_named_socket(self, read_timeout_seconds=5):
+        # Wait for something to read with a max timeout.
+        (ready_readers, _, _) = select.select([self.named_pipe_fd], [], [], read_timeout_seconds)
+        self.assertIsNotNone(ready_readers, "write side of pipe has not written anything - stub isn't writing to pipe.")
+        self.assertNotEqual(len(ready_readers), 0, "write side of pipe has not written anything - stub isn't writing to pipe.")
+
+        # Read the port from the named pipe.
+        stub_port_raw = self.named_pipe.read()
+        self.assertIsNotNone(stub_port_raw)
+        self.assertNotEqual(len(stub_port_raw), 0, "no content to read on pipe")
+
+        # Trim null byte, convert to int.
+        stub_port_raw = stub_port_raw[:-1]
+        stub_port = int(stub_port_raw)
+        self.assertTrue(stub_port > 0)
+
+        return stub_port
+
+    def init_llgs_test(self, use_named_pipe=True):
         self.debug_monitor_exe = get_lldb_gdbserver_exe()
         if not self.debug_monitor_exe:
             self.skipTest("lldb_gdbserver exe not found")
         self.debug_monitor_extra_args = " -c 'log enable -T -f process-{}.log lldb break process thread' -c 'log enable -T -f packets-{}.log gdb-remote packets'".format(self.id(), self.id(), self.id())
+        if use_named_pipe:
+            (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
 
-    def init_debugserver_test(self):
+    def init_debugserver_test(self, use_named_pipe=True):
         self.debug_monitor_exe = get_debugserver_exe()
         if not self.debug_monitor_exe:
             self.skipTest("debugserver exe not found")
         self.debug_monitor_extra_args = " --log-file=/tmp/packets-{}.log --log-flags=0x800000".format(self._testMethodName)
+        if use_named_pipe:
+            (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe()
 
     def create_socket(self):
         sock = socket.socket()
@@ -89,7 +162,10 @@ class GdbRemoteTestCaseBase(TestBase):
 
         self.addTearDownHook(shutdown_socket)
 
-        sock.connect(('localhost', self.port))
+        connect_info = ("localhost", self.port)
+        # print "connecting to stub on {}:{}".format(connect_info[0], connect_info[1])
+        sock.connect(connect_info)
+
         return sock
 
     def set_inferior_startup_launch(self):
@@ -108,6 +184,13 @@ class GdbRemoteTestCaseBase(TestBase):
 
         # Start the server.
         server = pexpect.spawn(commandline)
+        self.assertIsNotNone(server)
+        server.expect(r"(debugserver|lldb-gdbserver)", timeout=10)
+
+        # If we're receiving the stub's listening port from the named pipe, do that here.
+        if self.named_pipe:
+            self.port = self.get_stub_port_from_named_socket()
+            # print "debug server listening on {}".format(self.port)
 
         # Turn on logging for what the child sends back.
         if self.TraceOn():
@@ -116,6 +199,27 @@ class GdbRemoteTestCaseBase(TestBase):
         return server
 
     def connect_to_debug_monitor(self, attach_pid=None):
+        if self.named_pipe:
+            # Create the stub.
+            server = self.launch_debug_monitor(attach_pid=attach_pid)
+            self.assertIsNotNone(server)
+
+            def shutdown_debug_monitor():
+                try:
+                    server.close()
+                except:
+                    logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0]))
+            self.addTearDownHook(shutdown_debug_monitor)
+
+            # Schedule debug monitor to be shut down during teardown.
+            logger = self.logger
+
+            # Attach to the stub and return a socket opened to it.
+            self.sock = self.create_socket()
+            return server
+
+        # We're using a random port algorithm to try not to collide with other ports,
+        # and retry a max # times.
         attempts = 0
         MAX_ATTEMPTS = 20
 

Modified: lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py?rev=212923&r1=212922&r2=212923&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/lldbgdbserverutils.py Mon Jul 14 01:24:44 2014
@@ -195,7 +195,11 @@ def expect_lldb_gdbserver_replay(
                 # This is an entry to send to the remote debug monitor.
                 send_packet = sequence_entry.get_send_packet()
                 if logger:
-                    logger.info("sending packet to remote: %s" % send_packet)
+                    if len(send_packet) == 1 and send_packet[0] == chr(3):
+                        packet_desc = "^C"
+                    else:
+                        packet_desc = send_packet
+                    logger.info("sending packet to remote: {}".format(packet_desc))
                 sock.sendall(send_packet)
             else:
                 # This is an entry expecting to receive content from the remote debug monitor.





More information about the lldb-commits mailing list