mirror of
https://github.com/python/cpython.git
synced 2024-11-25 19:03:49 +08:00
Shutdown subprocess debugger and associated Proxies/Adapters when closing
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
This commit is contained in:
parent
fdc34315f7
commit
ffd3a4217a
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
# 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
|
||||
|
||||
def register(self, oid, object):
|
||||
self.objtable[oid] = object
|
||||
# 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.
|
||||
|
||||
def unregister(self, oid):
|
||||
try:
|
||||
del self.objtable[oid]
|
||||
except KeyError:
|
||||
pass
|
||||
# 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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user