Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ffd3a42

Browse files
committed
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
1 parent fdc3431 commit ffd3a42

4 files changed

Lines changed: 80 additions & 41 deletions

File tree

Lib/idlelib/PyShell.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import idlever
2626

2727
import rpc
28+
import RemoteDebugger
2829

2930
# XX hardwire this for now, remove later KBK 09Jun02
3031
use_subprocess = 1 # Set to 1 to spawn subprocess for command execution
@@ -89,8 +90,7 @@ def linecache_checkcache(orig_checkcache=linecache.checkcache):
8990

9091

9192
class PyShellEditorWindow(EditorWindow):
92-
93-
# Regular text edit window when a shell is present
93+
"Regular text edit window when a shell is present"
9494
# XXX ought to merge with regular editor window
9595

9696
def __init__(self, *args):
@@ -532,6 +532,8 @@ def close_debugger(self):
532532
if db:
533533
self.interp.setdebugger(None)
534534
db.close()
535+
if self.interp.rpcclt:
536+
RemoteDebugger.close_remote_debugger(self.interp.rpcclt)
535537
self.resetoutput()
536538
self.console.write("[DEBUG OFF]\n")
537539
sys.ps1 = ">>> "
@@ -551,15 +553,14 @@ def open_debugger(self):
551553
self.set_debugger_indicator()
552554

553555
def open_remote_debugger(self):
554-
import RemoteDebugger
555556
gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self)
556557
self.interp.setdebugger(gui)
557558
sys.ps1 = "[DEBUG ON]\n>>> "
558559
self.showprompt()
559560
self.set_debugger_indicator()
560561

561562
def beginexecuting(self):
562-
# Helper for ModifiedInterpreter
563+
"Helper for ModifiedInterpreter"
563564
self.resetoutput()
564565
self.executing = 1
565566
##self._cancel_check = self.cancel_check

Lib/idlelib/RemoteDebugger.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def __init__(self, conn, gui_adap_oid):
5252
self.oid = gui_adap_oid
5353

5454
def interaction(self, message, frame, info=None):
55+
# calls rpc.SocketIO.remotecall() via run.MyHandler instance
5556
self.conn.remotecall(self.oid, "interaction",
5657
(message, wrap_frame(frame), wrap_info(info)),
5758
{})
@@ -156,20 +157,21 @@ def dict_item(self, did, key):
156157
#----------end class IdbAdapter----------
157158

158159

159-
def start_debugger(conn, gui_adap_oid):
160+
def start_debugger(rpchandler, gui_adap_oid):
160161
"""Start the debugger and its RPC link in the Python subprocess
161162
162163
Start the subprocess side of the split debugger and set up that side of the
163164
RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
164-
objects and linking them together. Register the IdbAdapter to handle RPC
165-
requests from the split debugger GUI via the IdbProxy.
165+
objects and linking them together. Register the IdbAdapter with the
166+
RPCServer to handle RPC requests from the split debugger GUI via the
167+
IdbProxy.
166168
167169
"""
168-
gui_proxy = GUIProxy(conn, gui_adap_oid)
170+
gui_proxy = GUIProxy(rpchandler, gui_adap_oid)
169171
idb = Debugger.Idb(gui_proxy)
170172
idb_adap = IdbAdapter(idb)
171173
idb_adap_oid = "idb_adapter"
172-
conn.register(idb_adap_oid, idb_adap)
174+
rpchandler.register(idb_adap_oid, idb_adap)
173175
return idb_adap_oid
174176

175177

@@ -315,25 +317,39 @@ def clear_all_file_breaks(self, filename):
315317
msg = self.call("clear_all_file_breaks", filename)
316318

317319

318-
def start_remote_debugger(conn, pyshell):
320+
def start_remote_debugger(rpcclt, pyshell):
319321
"""Start the subprocess debugger, initialize the debugger GUI and RPC link
320322
321323
Request the RPCServer start the Python subprocess debugger and link. Set
322324
up the Idle side of the split debugger by instantiating the IdbProxy,
323325
debugger GUI, and debugger GUIAdapter objects and linking them together.
324326
325-
Register the GUIAdapter to handle debugger GUI interaction requests coming
326-
from the subprocess debugger via the GUIProxy.
327+
Register the GUIAdapter with the RPCClient to handle debugger GUI
328+
interaction requests coming from the subprocess debugger via the GUIProxy.
327329
328330
The IdbAdapter will pass execution and environment requests coming from the
329331
Idle debugger GUI to the subprocess debugger via the IdbProxy.
330332
331333
"""
332334
gui_adap_oid = "gui_adapter"
333-
idb_adap_oid = conn.remotecall("exec", "start_the_debugger",\
335+
idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
334336
(gui_adap_oid,), {})
335-
idb_proxy = IdbProxy(conn, idb_adap_oid)
337+
idb_proxy = IdbProxy(rpcclt, idb_adap_oid)
336338
gui = Debugger.Debugger(pyshell, idb_proxy)
337-
gui_adap = GUIAdapter(conn, gui)
338-
conn.register(gui_adap_oid, gui_adap)
339+
gui_adap = GUIAdapter(rpcclt, gui)
340+
rpcclt.register(gui_adap_oid, gui_adap)
339341
return gui
342+
343+
def close_remote_debugger(rpcclt):
344+
"""Shut down subprocess debugger and Idle side of debugger RPC link
345+
346+
Request that the RPCServer shut down the subprocess debugger and link.
347+
Unregister the GUIAdapter, which will cause a GC on the Idle process
348+
debugger and RPC link objects. (The second reference to the debugger GUI
349+
is deleted in PyShell.close_remote_debugger().)
350+
351+
"""
352+
idb_adap_oid = "idb_adapter"
353+
rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {})
354+
gui_adap_oid = "gui_adapter"
355+
rpcclt.unregister(gui_adap_oid)

Lib/idlelib/rpc.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,48 @@ class RPCServer(SocketServer.TCPServer):
5555
def __init__(self, addr, handlerclass=None):
5656
if handlerclass is None:
5757
handlerclass = RPCHandler
58-
self.objtable = objecttable
58+
# XXX KBK 25Jun02 Not used in Idlefork, see register/unregister note below.
59+
# self.objtable = objecttable
5960
SocketServer.TCPServer.__init__(self, addr, handlerclass)
6061

61-
def verify_request(self, request, client_address):
62-
host, port = client_address
63-
if host != "127.0.0.1":
64-
print "Disallowed host:", host
65-
return 0
66-
else:
67-
return 1
68-
69-
def register(self, oid, object):
70-
self.objtable[oid] = object
71-
72-
def unregister(self, oid):
73-
try:
74-
del self.objtable[oid]
75-
except KeyError:
76-
pass
62+
# XXX KBK 25Jun02 Following method is not used (yet)
63+
# def verify_request(self, request, client_address):
64+
# host, port = client_address
65+
# if host != "127.0.0.1":
66+
# print "Disallowed host:", host
67+
# return 0
68+
# else:
69+
# return 1
70+
71+
# XXX KBK 25Jun02 The handlerclass is expected to provide register/unregister
72+
# methods. In Idle, RPCServer is instantiated with
73+
# handlerclass MyHandler, which in turn inherits the
74+
# register/unregister methods from the mix-in class SocketIO.
75+
# It is true that this is asymmetric with the RPCClient's use
76+
# of register/unregister, but I guess that's how a SocketServer
77+
# is supposed to work.
78+
79+
# Exactly how this gets set up is convoluted. When the
80+
# TCPServer is instantiated, it creates an instance of
81+
# run.MyHandler and calls its handle() method. handle()
82+
# instantiates a run.Executive, passing it a reference to the
83+
# MyHandler object. That reference is saved as an attribute of
84+
# the Executive instance. The Executive methods have access to
85+
# the reference and can pass it on to entities that they
86+
# command (e.g. RemoteDebugger.Debugger.start_debugger()). The
87+
# latter, in turn, can call MyHandler(SocketIO)
88+
# register/unregister methods via the reference to register and
89+
# unregister themselves. Whew.
90+
91+
# The following two methods are not currently used in Idlefork.
92+
# def register(self, oid, object):
93+
# self.objtable[oid] = object
94+
95+
# def unregister(self, oid):
96+
# try:
97+
# del self.objtable[oid]
98+
# except KeyError:
99+
# pass
77100

78101

79102
objecttable = {}
@@ -198,11 +221,6 @@ def decoderesponse(self, response):
198221
pass
199222
else:
200223
raise getattr(__import__(mod), name)(*args)
201-
# XXX KBK 15Jun02 mod is False here, also want to raise remaining exceptions
202-
# else:
203-
# if mod:
204-
# name = mod + "." + name
205-
# raise name, args
206224
raise name, args
207225
if how == "ERROR":
208226
raise RuntimeError, what

Lib/idlelib/run.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def handle(self):
2323
class Executive:
2424

2525
def __init__(self, rpchandler):
26-
self.conn = rpchandler
26+
self.rpchandler = rpchandler
2727
import __main__
2828
self.locals = __main__.__dict__
2929

@@ -32,14 +32,18 @@ def runcode(self, code):
3232

3333
def start_the_debugger(self, gui_adap_oid):
3434
import RemoteDebugger
35-
return RemoteDebugger.start_debugger(self.conn, gui_adap_oid)
35+
return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
36+
37+
def stop_the_debugger(self, idb_adap_oid):
38+
"Unregister the Idb Adapter. Link objects and Idb then subject to GC"
39+
self.rpchandler.unregister(idb_adap_oid)
3640

3741
def stackviewer(self, flist_oid=None):
3842
if not hasattr(sys, "last_traceback"):
3943
return None
4044
flist = None
4145
if flist_oid is not None:
42-
flist = self.conn.get_remote_proxy(flist_oid)
46+
flist = self.rpchandler.get_remote_proxy(flist_oid)
4347
import RemoteObjectBrowser
4448
import StackViewer
4549
tb = sys.last_traceback

0 commit comments

Comments
 (0)