]> granicus.if.org Git - python/commitdiff
Shutdown subprocess debugger and associated Proxies/Adapters when closing
authorKurt B. Kaiser <kbk@shore.net>
Wed, 26 Jun 2002 02:32:09 +0000 (02:32 +0000)
committerKurt B. Kaiser <kbk@shore.net>
Wed, 26 Jun 2002 02:32:09 +0000 (02:32 +0000)
the Idle debugger.

M PyShell.py       : Call RemoteDebugger.close_remote_debugger()
M RemoteDebugger.py: Add close_remote_debugger(); further polish code used
                     to start the debugger sections.
M rpc.py           : Add comments on Idlefork methods register(), unregister()
                     comment out unused methods
M run.py           : Add stop_the_debugger(); polish code

Lib/idlelib/PyShell.py
Lib/idlelib/RemoteDebugger.py
Lib/idlelib/rpc.py
Lib/idlelib/run.py

index 6fb7f6904ca14d88dd01ffe9b63cadb35eb615ec..4771d2e3a2289fccc95965473afe76b0437a735a 100644 (file)
@@ -25,6 +25,7 @@ from configHandler import idleConf
 import idlever
 
 import rpc
+import RemoteDebugger
 
 # XX hardwire this for now, remove later  KBK 09Jun02
 use_subprocess = 1 # Set to 1 to spawn subprocess for command execution
@@ -89,8 +90,7 @@ linecache.checkcache = linecache_checkcache
 
 
 class PyShellEditorWindow(EditorWindow):
-
-    # Regular text edit window when a shell is present
+    "Regular text edit window when a shell is present"
     # XXX ought to merge with regular editor window
 
     def __init__(self, *args):
@@ -532,6 +532,8 @@ class PyShell(OutputWindow):
         if db:
             self.interp.setdebugger(None)
             db.close()
+            if self.interp.rpcclt:
+                RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
             self.resetoutput()
             self.console.write("[DEBUG OFF]\n")
             sys.ps1 = ">>> "
@@ -551,7 +553,6 @@ class PyShell(OutputWindow):
         self.set_debugger_indicator()
 
     def open_remote_debugger(self):
-        import RemoteDebugger
         gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self)
         self.interp.setdebugger(gui)
         sys.ps1 = "[DEBUG ON]\n>>> "
@@ -559,7 +560,7 @@ class PyShell(OutputWindow):
         self.set_debugger_indicator()
 
     def beginexecuting(self):
-        # Helper for ModifiedInterpreter
+        "Helper for ModifiedInterpreter"
         self.resetoutput()
         self.executing = 1
         ##self._cancel_check = self.cancel_check
index 84a51a5b5b8b6b2c471d1459d52239f685436b46..33072393192017c57b1417df2260c6c632a439c4 100644 (file)
@@ -52,6 +52,7 @@ class GUIProxy:
         self.oid = gui_adap_oid
 
     def interaction(self, message, frame, info=None):
+        # calls rpc.SocketIO.remotecall() via run.MyHandler instance
         self.conn.remotecall(self.oid, "interaction",
                              (message, wrap_frame(frame), wrap_info(info)),
                              {})
@@ -156,20 +157,21 @@ class IdbAdapter:
 #----------end class IdbAdapter----------
 
 
-def start_debugger(conn, gui_adap_oid):
+def start_debugger(rpchandler, gui_adap_oid):
     """Start the debugger and its RPC link in the Python subprocess
 
     Start the subprocess side of the split debugger and set up that side of the
     RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
-    objects and linking them together.  Register the IdbAdapter to handle RPC
-    requests from the split debugger GUI via the IdbProxy.
+    objects and linking them together.  Register the IdbAdapter with the
+    RPCServer to handle RPC requests from the split debugger GUI via the
+    IdbProxy.
 
     """
-    gui_proxy = GUIProxy(conn, gui_adap_oid)
+    gui_proxy = GUIProxy(rpchandler, gui_adap_oid)
     idb = Debugger.Idb(gui_proxy)
     idb_adap = IdbAdapter(idb)
     idb_adap_oid = "idb_adapter"
-    conn.register(idb_adap_oid, idb_adap)
+    rpchandler.register(idb_adap_oid, idb_adap)
     return idb_adap_oid
 
 
@@ -315,25 +317,39 @@ class IdbProxy:
         msg = self.call("clear_all_file_breaks", filename)
         
 
-def start_remote_debugger(conn, pyshell):
+def start_remote_debugger(rpcclt, pyshell):
     """Start the subprocess debugger, initialize the debugger GUI and RPC link
 
     Request the RPCServer start the Python subprocess debugger and link.  Set
     up the Idle side of the split debugger by instantiating the IdbProxy,
     debugger GUI, and debugger GUIAdapter objects and linking them together.
 
-    Register the GUIAdapter to handle debugger GUI interaction requests coming
-    from the subprocess debugger via the GUIProxy.
+    Register the GUIAdapter with the RPCClient to handle debugger GUI
+    interaction requests coming from the subprocess debugger via the GUIProxy.
 
     The IdbAdapter will pass execution and environment requests coming from the
     Idle debugger GUI to the subprocess debugger via the IdbProxy.
 
     """
     gui_adap_oid = "gui_adapter"
-    idb_adap_oid = conn.remotecall("exec", "start_the_debugger",\
+    idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
                                    (gui_adap_oid,), {})
-    idb_proxy = IdbProxy(conn, idb_adap_oid)
+    idb_proxy = IdbProxy(rpcclt, idb_adap_oid)
     gui = Debugger.Debugger(pyshell, idb_proxy)
-    gui_adap = GUIAdapter(conn, gui)
-    conn.register(gui_adap_oid, gui_adap)
+    gui_adap = GUIAdapter(rpcclt, gui)
+    rpcclt.register(gui_adap_oid, gui_adap)
     return gui
+
+def close_remote_debugger(rpcclt):
+    """Shut down subprocess debugger and Idle side of debugger RPC link
+
+    Request that the RPCServer shut down the subprocess debugger and link.
+    Unregister the GUIAdapter, which will cause a GC on the Idle process
+    debugger and RPC link objects.  (The second reference to the debugger GUI
+    is deleted in PyShell.close_remote_debugger().)
+
+    """    
+    idb_adap_oid = "idb_adapter"
+    rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {})
+    gui_adap_oid = "gui_adapter"
+    rpcclt.unregister(gui_adap_oid)
index 35a2678c7df29933c5f920536d1fa786323c22b3..60a6335ea11cfc3b039c5aef821efd68c732efe4 100644 (file)
@@ -55,25 +55,48 @@ class RPCServer(SocketServer.TCPServer):
     def __init__(self, addr, handlerclass=None):
         if handlerclass is None:
             handlerclass = RPCHandler
-        self.objtable = objecttable 
+# XXX KBK 25Jun02 Not used in Idlefork, see register/unregister note below.
+#        self.objtable = objecttable 
         SocketServer.TCPServer.__init__(self, addr, handlerclass)
 
-    def verify_request(self, request, client_address):
-        host, port = client_address
-        if host != "127.0.0.1":
-            print "Disallowed host:", host
-            return 0
-        else:
-            return 1
-
-    def register(self, oid, object):
-        self.objtable[oid] = object
-
-    def unregister(self, oid):
-        try:
-            del self.objtable[oid]
-        except KeyError:
-            pass
+    # XXX KBK 25Jun02 Following method is not used (yet)
+#      def verify_request(self, request, client_address):
+#          host, port = client_address
+#          if host != "127.0.0.1":
+#              print "Disallowed host:", host
+#              return 0
+#          else:
+#              return 1
+
+# XXX KBK 25Jun02 The handlerclass is expected to provide register/unregister
+#                 methods.  In Idle, RPCServer is instantiated with
+#                 handlerclass MyHandler, which in turn inherits the
+#                 register/unregister methods from the mix-in class SocketIO.
+#                 It is true that this is asymmetric with the RPCClient's use
+#                 of register/unregister, but I guess that's how a SocketServer
+#                 is supposed to work.
+
+#                 Exactly how this gets set up is convoluted.  When the
+#                 TCPServer is instantiated, it creates an instance of
+#                 run.MyHandler and calls its handle() method.  handle()
+#                 instantiates a run.Executive, passing it a reference to the
+#                 MyHandler object.  That reference is saved as an attribute of
+#                 the Executive instance.  The Executive methods have access to
+#                 the reference and can pass it on to entities that they
+#                 command (e.g. RemoteDebugger.Debugger.start_debugger()).  The
+#                 latter, in turn, can call MyHandler(SocketIO)
+#                 register/unregister methods via the reference to register and
+#                 unregister themselves.  Whew.
+
+    # The following two methods are not currently used in Idlefork.
+#      def register(self, oid, object):
+#          self.objtable[oid] = object
+
+#      def unregister(self, oid):
+#          try:
+#              del self.objtable[oid]
+#          except KeyError:
+#              pass
 
 
 objecttable = {}
@@ -198,11 +221,6 @@ class SocketIO:
                         pass
                     else:
                         raise getattr(__import__(mod), name)(*args)
-# XXX KBK 15Jun02  mod is False here, also want to raise remaining exceptions
-#           else:
-#               if mod:
-#                   name = mod + "." + name
-#               raise name, args
             raise name, args
         if how == "ERROR":
             raise RuntimeError, what
index cfb318cef46b08b2a34a53ae4e85a9c874115c4d..9f26c1690f144ccaf504a8c40fa6f0dd604feda2 100644 (file)
@@ -23,7 +23,7 @@ class MyHandler(rpc.RPCHandler):
 class Executive:
 
     def __init__(self, rpchandler):
-        self.conn = rpchandler
+        self.rpchandler = rpchandler
         import __main__
         self.locals = __main__.__dict__
 
@@ -32,14 +32,18 @@ class Executive:
 
     def start_the_debugger(self, gui_adap_oid):
         import RemoteDebugger
-        return RemoteDebugger.start_debugger(self.conn, gui_adap_oid)
+        return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
+
+    def stop_the_debugger(self, idb_adap_oid):
+        "Unregister the Idb Adapter.  Link objects and Idb then subject to GC"
+        self.rpchandler.unregister(idb_adap_oid)
 
     def stackviewer(self, flist_oid=None):
         if not hasattr(sys, "last_traceback"):
             return None
         flist = None
         if flist_oid is not None:
-            flist = self.conn.get_remote_proxy(flist_oid)
+            flist = self.rpchandler.get_remote_proxy(flist_oid)
         import RemoteObjectBrowser
         import StackViewer
         tb = sys.last_traceback