eric6/DebugClients/Python/MultiProcessDebugExtension.py

branch
multi_processing
changeset 7871
eb65864ca038
parent 7802
eefe954f01e8
child 7872
433dacbfa456
equal deleted inserted replaced
7870:ab8f95bc7d2d 7871:eb65864ca038
7 Module implementing a function to patch the process creation functions to 7 Module implementing a function to patch the process creation functions to
8 support multiprocess debugging. 8 support multiprocess debugging.
9 """ 9 """
10 10
11 11
12 from DebugUtilities import patchArguments, isPythonProgram 12 from DebugUtilities import (
13 patchArguments, patchArgumentStringWindows, isPythonProgram,
14 isWindowsPlatform
15 )
13 16
14 _debugClient = None 17 _debugClient = None
15 18
16 19
17 def patchModule(module, functionName, createFunction): 20 def patchModule(module, functionName, createFunction):
45 """ 48 """
46 def newExecl(path, *args): 49 def newExecl(path, *args):
47 """ 50 """
48 Function replacing the 'execl' functions of the os module. 51 Function replacing the 'execl' functions of the os module.
49 """ 52 """
50 print(args)
51 import os 53 import os
52 if ( 54 if (
53 _debugClient.debugging and 55 _debugClient.debugging and
54 _debugClient.multiprocessSupport 56 _debugClient.multiprocessSupport
55 ): 57 ):
56 args = patchArguments(_debugClient, args) 58 args = patchArguments(_debugClient, args)
57 if isPythonProgram(args[0]): 59 if isPythonProgram(args[0]):
58 path = args[0] 60 path = args[0]
59 print(args)
60 return getattr(os, originalName)(path, *args) 61 return getattr(os, originalName)(path, *args)
61 return newExecl 62 return newExecl
63
64
65 def createExecv(originalName):
66 """
67 Function to patch the 'execv' process creation functions.
68
69 <ul>
70 <li>os.execv(path, args)</li>
71 <li>os.execvp(file, args)</li>
72 </ul>
73 """
74 def newExecv(path, args):
75 """
76 Function replacing the 'execv' functions of the os module.
77 """
78 import os
79 if (
80 _debugClient.debugging and
81 _debugClient.multiprocessSupport
82 ):
83 args = patchArguments(_debugClient, args)
84 if isPythonProgram(args[0]):
85 path = args[0]
86 return getattr(os, originalName)(path, args)
87 return newExecv
88
89
90 def createExecve(originalName):
91 """
92 Function to patch the 'execve' process creation functions.
93
94 <ul>
95 <li>os.execve(path, args, env)</li>
96 <li>os.execvpe(file, args, env)</li>
97 </ul>
98 """
99 def newExecve(path, args, env):
100 """
101 Function replacing the 'execve' functions of the os module.
102 """
103 import os
104 if (
105 _debugClient.debugging and
106 _debugClient.multiprocessSupport
107 ):
108 args = patchArguments(_debugClient, args)
109 if isPythonProgram(args[0]):
110 path = args[0]
111 return getattr(os, originalName)(path, args, env)
112 return newExecve
113
114
115 # TODO: add createSpawn...
116
117
118 def createForkExec(originalName):
119 """
120 Function to patch the 'fork_exec' process creation functions.
121
122 <ul>
123 <li>_posixsubprocess.fork_exec(args, executable_list, close_fds,
124 ... (13 more))</li>
125 </ul>
126 """
127 def newForkExec(args, *other_args):
128 """
129 Function replacing the 'fork_exec' functions of the _posixsubprocess
130 module.
131 """
132 import _posixsubprocess
133 if (
134 _debugClient.debugging and
135 _debugClient.multiprocessSupport
136 ):
137 args = patchArguments(_debugClient, args)
138 return getattr(_posixsubprocess, originalName)(args, *other_args)
139 return newForkExec
140
141
142 def createFork(original_name):
143 """
144 Function to patch the 'fork' process creation functions.
145
146 <ul>
147 <li>os.fork()</li>
148 </ul>
149 """
150 def new_fork():
151 """
152 Function replacing the 'fork' function of the os module.
153 """
154 import os
155 import sys
156
157 # A simple fork will result in a new python process
158 isNewPythonProcess = True
159 frame = sys._getframe()
160
161 multiprocess = (
162 _debugClient.debugging and _debugClient.multiprocessSupport
163 )
164
165 isSubprocessFork = False
166 while frame is not None:
167 if (
168 frame.f_code.co_name == '_execute_child' and
169 'subprocess' in frame.f_code.co_filename
170 ):
171 isSubprocessFork = True
172 # If we're actually in subprocess.Popen creating a child, it
173 # may result in something which is not a Python process, (so,
174 # we don't want to connect with it in the forked version).
175 executable = frame.f_locals.get('executable')
176 if executable is not None:
177 isNewPythonProcess = False
178 if isPythonProgram(executable):
179 isNewPythonProcess = True
180 break
181
182 frame = frame.f_back
183 frame = None # Just make sure we don't hold on to it.
184
185 childProcess = getattr(os, original_name)() # fork
186 if not childProcess:
187 if isNewPythonProcess:
188 sys.settrace(None)
189 sys.setprofile(None)
190 _debugClient.sessionClose(False)
191 (wd, host, port, exceptions, tracePython, redirect,
192 noencoding, fork_auto, fork_child) = _debugClient.startOptions
193 _debugClient.startDebugger(
194 filename=sys.argv[0],
195 host=host,
196 port=port,
197 enableTrace=multiprocess and not isSubprocessFork,
198 exceptions=exceptions,
199 tracePython=tracePython,
200 redirect=redirect,
201 passive=False,
202 multiprocessSupport=multiprocess)
203 return childProcess
204
205 return new_fork
206
207
208 def createCreateProcess(originalName):
209 """
210 Function to patch the 'CreateProcess' process creation function of
211 Windows.
212 """
213 def newCreateProcess(appName, cmdline, *args):
214 """
215 Function replacing the 'CreateProcess' function of the _subprocess
216 or _winapi module.
217 """
218 try:
219 import _subprocess
220 except ImportError:
221 import _winapi as _subprocess
222 return getattr(_subprocess, originalName)(
223 appName, patchArgumentStringWindows(_debugClient, cmdline), *args)
224 return newCreateProcess
225
226
227 # TODO: add 'createFork'
62 228
63 229
64 def patchNewProcessFunctions(multiprocessEnabled, debugClient): 230 def patchNewProcessFunctions(multiprocessEnabled, debugClient):
65 """ 231 """
66 Function to patch the process creation functions to support multiprocess 232 Function to patch the process creation functions to support multiprocess
82 # patch 'os.exec...()' functions 248 # patch 'os.exec...()' functions
83 patchModule(os, "execl", createExecl) 249 patchModule(os, "execl", createExecl)
84 patchModule(os, "execle", createExecl) 250 patchModule(os, "execle", createExecl)
85 patchModule(os, "execlp", createExecl) 251 patchModule(os, "execlp", createExecl)
86 patchModule(os, "execlpe", createExecl) 252 patchModule(os, "execlpe", createExecl)
253 patchModule(os, "execv", createExecv)
254 patchModule(os, "execve", createExecve)
255 patchModule(os, "execvp", createExecv)
256 patchModule(os, "execvpe", createExecve)
87 257
88 # TODO: implement patching of the various functions of the os module 258 # TODO: implement patching of the various functions of the os module
89 259
260 if isWindowsPlatform():
261 try:
262 import _subprocess
263 except ImportError:
264 import _winapi as _subprocess
265 patchModule(_subprocess, 'CreateProcess', createCreateProcess)
266 else:
267 patchModule(os, "fork", createFork)
268 try:
269 import _posixsubprocess
270 patchModule(_posixsubprocess, "fork_exec", createForkExec)
271 except ImportError:
272 pass
273
90 _debugClient = debugClient 274 _debugClient = debugClient

eric ide

mercurial