Checking in IDLEFORK exactly as it appears in the idlefork CVS.
On a branch, for now.
diff --git a/Tools/idle/run.py b/Tools/idle/run.py
new file mode 100644
index 0000000..497cbbd
--- /dev/null
+++ b/Tools/idle/run.py
@@ -0,0 +1,216 @@
+import sys
+import time
+import socket
+import traceback
+import threading
+import Queue
+
+import boolcheck
+
+import CallTips
+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
+
+    In the Python subprocess, RPCServer is instantiated with handlerclass
+    MyHandler, which inherits register/unregister methods from RPCHandler via
+    the mix-in class SocketIO.
+
+    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
+    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.
+
+    """
+    global queue, execution_finished, exit_requested
+
+    port = 8833
+    if sys.argv[1:]:
+        port = int(sys.argv[1])
+    sys.argv[:] = [""]
+    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:
+            server = rpc.RPCServer(address, MyHandler)
+            break
+        except socket.error, err:
+            if i < 3:
+                print>>sys.__stderr__, ".. ",
+            else:
+                print>>sys.__stderr__,"\nPython subprocess socket error: "\
+                                              + err[1] + ", retrying...."
+    else:
+        print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
+        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.getresponse(self, myseq=None, wait=0.5)
+
+
+class Executive:
+
+    def __init__(self, rpchandler):
+        self.rpchandler = rpchandler
+        self.locals = __main__.__dict__
+        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:
+            self.flush_stdout()
+            efile = sys.stderr
+            typ, val, tb = info = sys.exc_info()
+            sys.last_type, sys.last_value, sys.last_traceback = info
+            tbe = traceback.extract_tb(tb)
+            print >>efile, 'Traceback (most recent call last):'
+            exclude = ("run.py", "rpc.py", "RemoteDebugger.py", "bdb.py")
+            self.cleanup_traceback(tbe, exclude)
+            traceback.print_list(tbe, file=efile)
+            lines = traceback.format_exception_only(typ, val)
+            for line in lines:
+                print>>efile, line,
+            execution_finished = True
+        else:
+            self.flush_stdout()
+            execution_finished = True
+
+    def flush_stdout(self):
+        try:
+            if sys.stdout.softspace:
+                sys.stdout.softspace = 0
+                sys.stdout.write("\n")
+        except (AttributeError, EOFError):
+            pass
+
+    def cleanup_traceback(self, tb, exclude):
+        "Remove excluded traces from beginning/end of tb; get cached lines"
+        orig_tb = tb[:]
+        while tb:
+            for rpcfile in exclude:
+                if tb[0][0].count(rpcfile):
+                    break    # found an exclude, break for: and delete tb[0]
+            else:
+                break        # no excludes, have left RPC code, break while:
+            del tb[0]
+        while tb:
+            for rpcfile in exclude:
+                if tb[-1][0].count(rpcfile):
+                    break
+            else:
+                break
+            del tb[-1]
+        if len(tb) == 0:
+            # exception was in IDLE internals, don't prune!
+            tb[:] = orig_tb[:]
+            print>>sys.stderr, "** IDLE Internal Exception: "
+        for i in range(len(tb)):
+            fn, ln, nm, line = tb[i]
+            if nm == '?':
+                nm = "-toplevel-"
+            if not line and fn.startswith("<pyshell#"):
+                line = self.rpchandler.remotecall('linecache', 'getline',
+                                                  (fn, ln), {})
+            tb[i] = fn, ln, nm, line
+
+    def interrupt_the_server(self):
+        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)
+
+    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 get_the_calltip(self, name):
+        return self.calltip.fetch_tip(name)
+
+    def stackviewer(self, flist_oid=None):
+        if not hasattr(sys, "last_traceback"):
+            return None
+        flist = None
+        if flist_oid is not None:
+            flist = self.rpchandler.get_remote_proxy(flist_oid)
+        tb = sys.last_traceback
+        while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
+            tb = tb.tb_next
+        item = StackViewer.StackTreeItem(flist, tb)
+        return RemoteObjectBrowser.remote_object_tree_item(item)