Kaydet (Commit) e866c81d authored tarafından Kurt B. Kaiser's avatar Kurt B. Kaiser

Merged revisions 71126 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r71126 | kurt.kaiser | 2009-04-04 03:03:48 -0400 (Sat, 04 Apr 2009) | 5 lines

  Allow multiple IDLE GUI/subprocess pairs to exist
  simultaneously. Thanks to David Scherer for suggesting
  the use of an ephemeral port for the GUI.
  Patch 1529142 Weeble.
........
üst 88f14354
...@@ -3,6 +3,10 @@ What's New in IDLE 3.1a1? ...@@ -3,6 +3,10 @@ What's New in IDLE 3.1a1?
*Release date: XX-XXX-XXXX* *Release date: XX-XXX-XXXX*
- Allow multiple IDLE GUI/subprocess pairs to exist simultaneously. Thanks to
David Scherer for suggesting the use of an ephemeral port for the GUI.
Patch 1529142 Weeble.
- Remove port spec from run.py and fix bug where subprocess fails to - Remove port spec from run.py and fix bug where subprocess fails to
extract port from command line when warnings are present. extract port from command line when warnings are present.
......
...@@ -34,7 +34,8 @@ from idlelib import Debugger ...@@ -34,7 +34,8 @@ from idlelib import Debugger
from idlelib import RemoteDebugger from idlelib import RemoteDebugger
from idlelib import macosxSupport from idlelib import macosxSupport
LOCALHOST = '127.0.0.1' HOST = '127.0.0.1' # python execution server on localhost loopback
PORT = 0 # someday pass in host, port for remote debug capability
try: try:
from signal import SIGTERM from signal import SIGTERM
...@@ -339,17 +340,21 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -339,17 +340,21 @@ class ModifiedInterpreter(InteractiveInterpreter):
InteractiveInterpreter.__init__(self, locals=locals) InteractiveInterpreter.__init__(self, locals=locals)
self.save_warnings_filters = None self.save_warnings_filters = None
self.restarting = False self.restarting = False
self.subprocess_arglist = self.build_subprocess_arglist() self.subprocess_arglist = None
self.port = PORT
port = 8833
rpcclt = None rpcclt = None
rpcpid = None rpcpid = None
def spawn_subprocess(self): def spawn_subprocess(self):
if self.subprocess_arglist == None:
self.subprocess_arglist = self.build_subprocess_arglist()
args = self.subprocess_arglist args = self.subprocess_arglist
self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args) self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
def build_subprocess_arglist(self): def build_subprocess_arglist(self):
assert (self.port!=0), (
"Socket should have been assigned a port number.")
w = ['-W' + s for s in sys.warnoptions] w = ['-W' + s for s in sys.warnoptions]
# Maybe IDLE is installed and is being accessed via sys.path, # Maybe IDLE is installed and is being accessed via sys.path,
# or maybe it's not installed and the idle.py script is being # or maybe it's not installed and the idle.py script is being
...@@ -368,11 +373,8 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -368,11 +373,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
return [decorated_exec] + w + ["-c", command, str(self.port)] return [decorated_exec] + w + ["-c", command, str(self.port)]
def start_subprocess(self): def start_subprocess(self):
# spawning first avoids passing a listening socket to the subprocess addr = (HOST, self.port)
self.spawn_subprocess() # GUI makes several attempts to acquire socket, listens for connection
#time.sleep(20) # test to simulate GUI not accepting connection
addr = (LOCALHOST, self.port)
# Idle starts listening for connection on localhost
for i in range(3): for i in range(3):
time.sleep(i) time.sleep(i)
try: try:
...@@ -383,6 +385,18 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -383,6 +385,18 @@ class ModifiedInterpreter(InteractiveInterpreter):
else: else:
self.display_port_binding_error() self.display_port_binding_error()
return None return None
# if PORT was 0, system will assign an 'ephemeral' port. Find it out:
self.port = self.rpcclt.listening_sock.getsockname()[1]
# if PORT was not 0, probably working with a remote execution server
if PORT != 0:
# To allow reconnection within the 2MSL wait (cf. Stevens TCP
# V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
# on Windows since the implementation allows two active sockets on
# the same address!
self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
self.spawn_subprocess()
#time.sleep(20) # test to simulate GUI not accepting connection
# Accept the connection from the Python execution server # Accept the connection from the Python execution server
self.rpcclt.listening_sock.settimeout(10) self.rpcclt.listening_sock.settimeout(10)
try: try:
...@@ -734,13 +748,12 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -734,13 +748,12 @@ class ModifiedInterpreter(InteractiveInterpreter):
def display_port_binding_error(self): def display_port_binding_error(self):
tkMessageBox.showerror( tkMessageBox.showerror(
"Port Binding Error", "Port Binding Error",
"IDLE can't bind TCP/IP port 8833, which is necessary to " "IDLE can't bind to a TCP/IP port, which is necessary to "
"communicate with its Python execution server. Either " "communicate with its Python execution server. This might be "
"no networking is installed on this computer or another " "because no networking is installed on this computer. "
"process (another IDLE?) is using the port. Run IDLE with the -n " "Run IDLE with the -n command line switch to start without a "
"command line switch to start without a subprocess and refer to " "subprocess and refer to Help/IDLE Help 'Running without a "
"Help/IDLE Help 'Running without a subprocess' for further " "subprocess' for further details.",
"details.",
master=self.tkconsole.text) master=self.tkconsole.text)
def display_no_subprocess_error(self): def display_no_subprocess_error(self):
...@@ -1285,7 +1298,7 @@ def main(): ...@@ -1285,7 +1298,7 @@ def main():
global flist, root, use_subprocess global flist, root, use_subprocess
use_subprocess = True use_subprocess = True
enable_shell = False enable_shell = True
enable_edit = False enable_edit = False
debug = False debug = False
cmd = None cmd = None
...@@ -1306,6 +1319,7 @@ def main(): ...@@ -1306,6 +1319,7 @@ def main():
enable_shell = True enable_shell = True
if o == '-e': if o == '-e':
enable_edit = True enable_edit = True
enable_shell = False
if o == '-h': if o == '-h':
sys.stdout.write(usage_msg) sys.stdout.write(usage_msg)
sys.exit() sys.exit()
...@@ -1356,7 +1370,6 @@ def main(): ...@@ -1356,7 +1370,6 @@ def main():
edit_start = idleConf.GetOption('main', 'General', edit_start = idleConf.GetOption('main', 'General',
'editor-on-startup', type='bool') 'editor-on-startup', type='bool')
enable_edit = enable_edit or edit_start enable_edit = enable_edit or edit_start
enable_shell = enable_shell or not edit_start
# start editor and/or shell windows: # start editor and/or shell windows:
root = Tk(className="Idle") root = Tk(className="Idle")
......
...@@ -518,8 +518,6 @@ class RPCClient(SocketIO): ...@@ -518,8 +518,6 @@ class RPCClient(SocketIO):
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM): def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
self.listening_sock = socket.socket(family, type) self.listening_sock = socket.socket(family, type)
self.listening_sock.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
self.listening_sock.bind(address) self.listening_sock.bind(address)
self.listening_sock.listen(1) self.listening_sock.listen(1)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment