blob: 6a438c3c2a5e381d97d2a78c5a1dec4d4bf33c11 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001# Everything is done inside the loader function so that no other names
2# are placed in the global namespace. Before user code is executed,
3# even this name is unbound.
4def loader():
5 import sys, os, protocol, threading, time
6 import Remote
7
8## Use to debug the loading process itself:
9## sys.stdout = open('c:\\windows\\desktop\\stdout.txt','a')
10## sys.stderr = open('c:\\windows\\desktop\\stderr.txt','a')
11
12 # Ensure that there is absolutely no pollution of the global
13 # namespace by deleting the global name of this function.
14 global loader
15 del loader
16
17 # Connect to IDLE
18 try:
19 client = protocol.Client()
20 except protocol.connectionLost, cL:
21 print 'loader: Unable to connect to IDLE', cL
22 return
23
24 # Connect to an ExecBinding object that needs our help. If
25 # the user is starting multiple programs right now, we might get a
26 # different one than the one that started us. Proving that's okay is
27 # left as an exercise to the reader. (HINT: Twelve, by the pigeonhole
28 # principle)
29 ExecBinding = client.getobject('ExecBinding')
30 if not ExecBinding:
31 print "loader: IDLE does not need me."
32 return
33
34 # All of our input and output goes through ExecBinding.
35 sys.stdin = Remote.pseudoIn( ExecBinding.readline )
36 sys.stdout = Remote.pseudoOut( ExecBinding.write.void, tag="stdout" )
37 sys.stderr = Remote.pseudoOut( ExecBinding.write.void, tag="stderr" )
38
39 # Create a Remote object and start it running.
40 remote = Remote.Remote(globals(), ExecBinding)
41 rthread = threading.Thread(target=remote.mainloop)
42 rthread.setDaemon(1)
43 rthread.start()
44
45 # Block until either the client or the user program stops
46 user = rthread.isAlive
47 while user and client.isAlive():
48 time.sleep(0.025)
49
50 if not user():
51 user = hasattr(sys, "ready_to_exit") and sys.ready_to_exit
52 for t in threading.enumerate():
53 if not t.isDaemon() and t.isAlive() and t!=threading.currentThread():
54 user = t.isAlive
55 break
56
57 # We need to make sure we actually exit, so that the user doesn't get
58 # stuck with an invisible process. We want to finalize C modules, so
59 # we don't use os._exit(), but we don't call sys.exitfunc, which might
60 # block forever.
61 del sys.exitfunc
62 sys.exit()
63
64loader()