mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00: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
4 changed files with 78 additions and 39 deletions
|
@ -25,6 +25,7 @@ from configHandler import idleConf
|
||||||
import idlever
|
import idlever
|
||||||
|
|
||||||
import rpc
|
import rpc
|
||||||
|
import RemoteDebugger
|
||||||
|
|
||||||
# XX hardwire this for now, remove later KBK 09Jun02
|
# XX hardwire this for now, remove later KBK 09Jun02
|
||||||
use_subprocess = 1 # Set to 1 to spawn subprocess for command execution
|
use_subprocess = 1 # Set to 1 to spawn subprocess for command execution
|
||||||
|
@ -89,8 +90,7 @@ linecache.checkcache = linecache_checkcache
|
||||||
|
|
||||||
|
|
||||||
class PyShellEditorWindow(EditorWindow):
|
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
|
# XXX ought to merge with regular editor window
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
|
@ -532,6 +532,8 @@ class PyShell(OutputWindow):
|
||||||
if db:
|
if db:
|
||||||
self.interp.setdebugger(None)
|
self.interp.setdebugger(None)
|
||||||
db.close()
|
db.close()
|
||||||
|
if self.interp.rpcclt:
|
||||||
|
RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
|
||||||
self.resetoutput()
|
self.resetoutput()
|
||||||
self.console.write("[DEBUG OFF]\n")
|
self.console.write("[DEBUG OFF]\n")
|
||||||
sys.ps1 = ">>> "
|
sys.ps1 = ">>> "
|
||||||
|
@ -551,7 +553,6 @@ class PyShell(OutputWindow):
|
||||||
self.set_debugger_indicator()
|
self.set_debugger_indicator()
|
||||||
|
|
||||||
def open_remote_debugger(self):
|
def open_remote_debugger(self):
|
||||||
import RemoteDebugger
|
|
||||||
gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self)
|
gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self)
|
||||||
self.interp.setdebugger(gui)
|
self.interp.setdebugger(gui)
|
||||||
sys.ps1 = "[DEBUG ON]\n>>> "
|
sys.ps1 = "[DEBUG ON]\n>>> "
|
||||||
|
@ -559,7 +560,7 @@ class PyShell(OutputWindow):
|
||||||
self.set_debugger_indicator()
|
self.set_debugger_indicator()
|
||||||
|
|
||||||
def beginexecuting(self):
|
def beginexecuting(self):
|
||||||
# Helper for ModifiedInterpreter
|
"Helper for ModifiedInterpreter"
|
||||||
self.resetoutput()
|
self.resetoutput()
|
||||||
self.executing = 1
|
self.executing = 1
|
||||||
##self._cancel_check = self.cancel_check
|
##self._cancel_check = self.cancel_check
|
||||||
|
|
|
@ -52,6 +52,7 @@ class GUIProxy:
|
||||||
self.oid = gui_adap_oid
|
self.oid = gui_adap_oid
|
||||||
|
|
||||||
def interaction(self, message, frame, info=None):
|
def interaction(self, message, frame, info=None):
|
||||||
|
# calls rpc.SocketIO.remotecall() via run.MyHandler instance
|
||||||
self.conn.remotecall(self.oid, "interaction",
|
self.conn.remotecall(self.oid, "interaction",
|
||||||
(message, wrap_frame(frame), wrap_info(info)),
|
(message, wrap_frame(frame), wrap_info(info)),
|
||||||
{})
|
{})
|
||||||
|
@ -156,20 +157,21 @@ class IdbAdapter:
|
||||||
#----------end 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 debugger and its RPC link in the Python subprocess
|
||||||
|
|
||||||
Start the subprocess side of the split debugger and set up that side of the
|
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
|
RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
|
||||||
objects and linking them together. Register the IdbAdapter to handle RPC
|
objects and linking them together. Register the IdbAdapter with the
|
||||||
requests from the split debugger GUI via the IdbProxy.
|
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 = Debugger.Idb(gui_proxy)
|
||||||
idb_adap = IdbAdapter(idb)
|
idb_adap = IdbAdapter(idb)
|
||||||
idb_adap_oid = "idb_adapter"
|
idb_adap_oid = "idb_adapter"
|
||||||
conn.register(idb_adap_oid, idb_adap)
|
rpchandler.register(idb_adap_oid, idb_adap)
|
||||||
return idb_adap_oid
|
return idb_adap_oid
|
||||||
|
|
||||||
|
|
||||||
|
@ -315,25 +317,39 @@ class IdbProxy:
|
||||||
msg = self.call("clear_all_file_breaks", filename)
|
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
|
"""Start the subprocess debugger, initialize the debugger GUI and RPC link
|
||||||
|
|
||||||
Request the RPCServer start the Python subprocess debugger and link. Set
|
Request the RPCServer start the Python subprocess debugger and link. Set
|
||||||
up the Idle side of the split debugger by instantiating the IdbProxy,
|
up the Idle side of the split debugger by instantiating the IdbProxy,
|
||||||
debugger GUI, and debugger GUIAdapter objects and linking them together.
|
debugger GUI, and debugger GUIAdapter objects and linking them together.
|
||||||
|
|
||||||
Register the GUIAdapter to handle debugger GUI interaction requests coming
|
Register the GUIAdapter with the RPCClient to handle debugger GUI
|
||||||
from the subprocess debugger via the GUIProxy.
|
interaction requests coming from the subprocess debugger via the GUIProxy.
|
||||||
|
|
||||||
The IdbAdapter will pass execution and environment requests coming from the
|
The IdbAdapter will pass execution and environment requests coming from the
|
||||||
Idle debugger GUI to the subprocess debugger via the IdbProxy.
|
Idle debugger GUI to the subprocess debugger via the IdbProxy.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
gui_adap_oid = "gui_adapter"
|
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,), {})
|
(gui_adap_oid,), {})
|
||||||
idb_proxy = IdbProxy(conn, idb_adap_oid)
|
idb_proxy = IdbProxy(rpcclt, idb_adap_oid)
|
||||||
gui = Debugger.Debugger(pyshell, idb_proxy)
|
gui = Debugger.Debugger(pyshell, idb_proxy)
|
||||||
gui_adap = GUIAdapter(conn, gui)
|
gui_adap = GUIAdapter(rpcclt, gui)
|
||||||
conn.register(gui_adap_oid, gui_adap)
|
rpcclt.register(gui_adap_oid, gui_adap)
|
||||||
return gui
|
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):
|
def __init__(self, addr, handlerclass=None):
|
||||||
if handlerclass is None:
|
if handlerclass is None:
|
||||||
handlerclass = RPCHandler
|
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)
|
SocketServer.TCPServer.__init__(self, addr, handlerclass)
|
||||||
|
|
||||||
def verify_request(self, request, client_address):
|
# XXX KBK 25Jun02 Following method is not used (yet)
|
||||||
host, port = client_address
|
# def verify_request(self, request, client_address):
|
||||||
if host != "127.0.0.1":
|
# host, port = client_address
|
||||||
print "Disallowed host:", host
|
# if host != "127.0.0.1":
|
||||||
return 0
|
# print "Disallowed host:", host
|
||||||
else:
|
# return 0
|
||||||
return 1
|
# else:
|
||||||
|
# return 1
|
||||||
|
|
||||||
def register(self, oid, object):
|
# XXX KBK 25Jun02 The handlerclass is expected to provide register/unregister
|
||||||
self.objtable[oid] = object
|
# 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):
|
# Exactly how this gets set up is convoluted. When the
|
||||||
try:
|
# TCPServer is instantiated, it creates an instance of
|
||||||
del self.objtable[oid]
|
# run.MyHandler and calls its handle() method. handle()
|
||||||
except KeyError:
|
# instantiates a run.Executive, passing it a reference to the
|
||||||
pass
|
# 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 = {}
|
objecttable = {}
|
||||||
|
@ -198,11 +221,6 @@ class SocketIO:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise getattr(__import__(mod), name)(*args)
|
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
|
raise name, args
|
||||||
if how == "ERROR":
|
if how == "ERROR":
|
||||||
raise RuntimeError, what
|
raise RuntimeError, what
|
||||||
|
|
|
@ -23,7 +23,7 @@ class MyHandler(rpc.RPCHandler):
|
||||||
class Executive:
|
class Executive:
|
||||||
|
|
||||||
def __init__(self, rpchandler):
|
def __init__(self, rpchandler):
|
||||||
self.conn = rpchandler
|
self.rpchandler = rpchandler
|
||||||
import __main__
|
import __main__
|
||||||
self.locals = __main__.__dict__
|
self.locals = __main__.__dict__
|
||||||
|
|
||||||
|
@ -32,14 +32,18 @@ class Executive:
|
||||||
|
|
||||||
def start_the_debugger(self, gui_adap_oid):
|
def start_the_debugger(self, gui_adap_oid):
|
||||||
import RemoteDebugger
|
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):
|
def stackviewer(self, flist_oid=None):
|
||||||
if not hasattr(sys, "last_traceback"):
|
if not hasattr(sys, "last_traceback"):
|
||||||
return None
|
return None
|
||||||
flist = None
|
flist = None
|
||||||
if flist_oid is not 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 RemoteObjectBrowser
|
||||||
import StackViewer
|
import StackViewer
|
||||||
tb = sys.last_traceback
|
tb = sys.last_traceback
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue