summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/run.py
diff options
context:
space:
mode:
authorKurt B. Kaiser <kbk@shore.net>2003-03-22 19:40:19 (GMT)
committerKurt B. Kaiser <kbk@shore.net>2003-03-22 19:40:19 (GMT)
commit11c53e2ea7f7d2a2969c98e81c1489c4e72254c4 (patch)
tree7d39c8ebae64934426779dd7d468ac4688d3e416 /Lib/idlelib/run.py
parente51529d79a5b575e648bf5e6eef5324c8fb819ba (diff)
downloadcpython-11c53e2ea7f7d2a2969c98e81c1489c4e72254c4.zip
cpython-11c53e2ea7f7d2a2969c98e81c1489c4e72254c4.tar.gz
cpython-11c53e2ea7f7d2a2969c98e81c1489c4e72254c4.tar.bz2
M PyShell.py
M run.py 1. Move subprocess socket handling to a subthread - "SockThread". 2. In the subprocess, implement a queue and global completion and exit flags. Execute code after it is passed through the queue. (Currently, user code is executed in SockThread. The next phase of development will move the tail of the queue to MainThread.) 3. Implement an RPC message used to shut down the execution server. 4. Improve normal and exception subprocess exits. (At this checkin a "pass loop" interrupt doesn't work on any platform. It will be restored for all platforms once user code execution is moved to MainThread.)
Diffstat (limited to 'Lib/idlelib/run.py')
-rw-r--r--Lib/idlelib/run.py81
1 files changed, 72 insertions, 9 deletions
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index d79f3d7..497cbbd 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -2,6 +2,8 @@ import sys
import time
import socket
import traceback
+import threading
+import Queue
import boolcheck
@@ -10,9 +12,20 @@ import RemoteDebugger
import RemoteObjectBrowser
import StackViewer
import rpc
+import interrupt
import __main__
+# Thread shared globals: Establish a queue between a subthread (which handles
+# the socket) and the main thread (which runs user code), plus global
+# completion and exit flags:
+
+server = None # RPCServer instance
+queue = Queue.Queue(0)
+execution_finished = False
+exit_requested = False
+
+
def main():
"""Start the Python execution server in a subprocess
@@ -20,7 +33,7 @@ def main():
MyHandler, which inherits register/unregister methods from RPCHandler via
the mix-in class SocketIO.
- When the RPCServer svr is instantiated, the TCPServer initialization
+ When the RPCServer 'server' is instantiated, the TCPServer initialization
creates an instance of run.MyHandler and calls its handle() method.
handle() instantiates a run.Executive object, passing it a reference to the
MyHandler object. That reference is saved as attribute rpchandler of the
@@ -31,15 +44,35 @@ def main():
register and unregister themselves.
"""
+ global queue, execution_finished, exit_requested
+
port = 8833
if sys.argv[1:]:
port = int(sys.argv[1])
sys.argv[:] = [""]
- addr = ("localhost", port)
+ sockthread = threading.Thread(target=manage_socket,
+ name='SockThread',
+ args=(('localhost', port),))
+ sockthread.setDaemon(True)
+ sockthread.start()
+ while 1:
+ try:
+ if exit_requested:
+ sys.exit()
+ # XXX KBK 22Mar03 eventually check queue here!
+ pass
+ time.sleep(0.05)
+ except KeyboardInterrupt:
+ ##execution_finished = True
+ continue
+
+def manage_socket(address):
+ global server, exit_requested
+
for i in range(6):
time.sleep(i)
try:
- svr = rpc.RPCServer(addr, MyHandler)
+ server = rpc.RPCServer(address, MyHandler)
break
except socket.error, err:
if i < 3:
@@ -49,18 +82,21 @@ def main():
+ err[1] + ", retrying...."
else:
print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
- sys.exit()
- svr.handle_request() # A single request only
+ exit_requested = True
+ server.handle_request() # A single request only
+
class MyHandler(rpc.RPCHandler):
def handle(self):
+ """Override base method"""
executive = Executive(self)
self.register("exec", executive)
sys.stdin = self.get_remote_proxy("stdin")
sys.stdout = self.get_remote_proxy("stdout")
sys.stderr = self.get_remote_proxy("stderr")
- rpc.RPCHandler.handle(self)
+ rpc.RPCHandler.getresponse(self, myseq=None, wait=0.5)
+
class Executive:
@@ -70,6 +106,25 @@ class Executive:
self.calltip = CallTips.CallTips()
def runcode(self, code):
+ global queue, execution_finished
+
+ execution_finished = False
+ queue.put(code)
+ # dequeue and run in subthread
+ self.runcode_from_queue()
+ while not execution_finished:
+ time.sleep(0.05)
+
+ def runcode_from_queue(self):
+ global queue, execution_finished
+
+ # poll until queue has code object, using threads, just block?
+ while True:
+ try:
+ code = queue.get(0)
+ break
+ except Queue.Empty:
+ time.sleep(0.05)
try:
exec code in self.locals
except:
@@ -85,7 +140,10 @@ class Executive:
lines = traceback.format_exception_only(typ, val)
for line in lines:
print>>efile, line,
- self.flush_stdout()
+ execution_finished = True
+ else:
+ self.flush_stdout()
+ execution_finished = True
def flush_stdout(self):
try:
@@ -126,9 +184,14 @@ class Executive:
tb[i] = fn, ln, nm, line
def interrupt_the_server(self):
- # XXX KBK 05Feb03 Windows requires this be done with messages and
- # threads....
self.rpchandler.interrupted = True
+ ##print>>sys.__stderr__, "** Interrupt main!"
+ interrupt.interrupt_main()
+
+ def shutdown_the_server(self):
+ global exit_requested
+
+ exit_requested = True
def start_the_debugger(self, gui_adap_oid):
return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)