DebugClients/Python/ThreadExtension.py

branch
maintenance
changeset 5680
b93cb6353cc0
parent 5598
0e59df936fb6
parent 5667
86554f131048
child 5948
6f958d5765f4
equal deleted inserted replaced
5655:884cd9c9ce05 5680:b93cb6353cc0
37 self.threadNumber = 1 37 self.threadNumber = 1
38 self.enableImportHooks = True 38 self.enableImportHooks = True
39 self._original_start_new_thread = None 39 self._original_start_new_thread = None
40 self.threadingAttached = False 40 self.threadingAttached = False
41 self.qtThreadAttached = False 41 self.qtThreadAttached = False
42 self.greenlet = False
42 43
43 self.clientLock = threading.RLock() 44 self.clientLock = threading.RLock()
44 45
45 # dictionary of all threads running {id: DebugBase} 46 # dictionary of all threads running {id: DebugBase}
46 self.threads = {_thread.get_ident(): self} 47 self.threads = {_thread.get_ident(): self}
62 del sys.modules[self.threadModName] 63 del sys.modules[self.threadModName]
63 del sys.modules['threading'] 64 del sys.modules['threading']
64 65
65 sys.meta_path.insert(0, self) 66 sys.meta_path.insert(0, self)
66 67
67 def attachThread(self, target=None, args=None, kwargs={}, 68 def attachThread(self, target=None, args=None, kwargs=None,
68 mainThread=False): 69 mainThread=False):
69 """ 70 """
70 Public method to setup a standard thread for DebugClient to debug. 71 Public method to setup a standard thread for DebugClient to debug.
71 72
72 If mainThread is True, then we are attaching to the already 73 If mainThread is True, then we are attaching to the already
78 @param kwargs keyword arguments to pass to target 79 @param kwargs keyword arguments to pass to target
79 @param mainThread True, if we are attaching to the already 80 @param mainThread True, if we are attaching to the already
80 started mainthread of the app 81 started mainthread of the app
81 @return identifier of the created thread 82 @return identifier of the created thread
82 """ 83 """
84 if kwargs is None:
85 kwargs = {}
86
83 if mainThread: 87 if mainThread:
84 ident = _thread.get_ident() 88 ident = _thread.get_ident()
85 name = 'MainThread' 89 name = 'MainThread'
86 newThread = self.mainThread 90 newThread = self.mainThread
87 newThread.isMainThread = True 91 newThread.isMainThread = True
138 try: 142 try:
139 self.clientLock.release() 143 self.clientLock.release()
140 except AssertionError: 144 except AssertionError:
141 pass 145 pass
142 146
143 def setCurrentThread(self, id): 147 def setCurrentThread(self, threadId):
144 """ 148 """
145 Public method to set the current thread. 149 Public method to set the current thread.
146 150
147 @param id the id the current thread should be set to. 151 @param threadId the id the current thread should be set to.
148 @type int 152 @type int
149 """ 153 """
150 try: 154 try:
151 self.lockClient() 155 self.lockClient()
152 if id is None: 156 if threadId is None:
153 self.currentThread = None 157 self.currentThread = None
154 else: 158 else:
155 self.currentThread = self.threads.get(id) 159 self.currentThread = self.threads.get(threadId)
156 finally: 160 finally:
157 self.unlockClient() 161 self.unlockClient()
158 162
159 def dumpThreadList(self): 163 def dumpThreadList(self):
160 """ 164 """
165 if len(self.threads) > 1: 169 if len(self.threads) > 1:
166 currentId = _thread.get_ident() 170 currentId = _thread.get_ident()
167 # update thread names set by user (threading.setName) 171 # update thread names set by user (threading.setName)
168 threadNames = {t.ident: t.getName() for t in threading.enumerate()} 172 threadNames = {t.ident: t.getName() for t in threading.enumerate()}
169 173
170 for id, thd in self.threads.items(): 174 for threadId, thd in self.threads.items():
171 d = {"id": id} 175 d = {"id": threadId}
172 try: 176 try:
173 d["name"] = threadNames.get(id, thd.name) 177 d["name"] = threadNames.get(threadId, thd.name)
174 d["broken"] = thd.isBroken 178 d["broken"] = thd.isBroken
175 except Exception: 179 except Exception:
176 d["name"] = 'UnknownThread' 180 d["name"] = 'UnknownThread'
177 d["broken"] = False 181 d["broken"] = False
178 182
213 def updateThreadList(self): 217 def updateThreadList(self):
214 """ 218 """
215 Public method to update the list of running threads. 219 Public method to update the list of running threads.
216 """ 220 """
217 frames = sys._current_frames() 221 frames = sys._current_frames()
218 for id, frame in frames.items(): 222 for threadId, frame in frames.items():
219 # skip our own timer thread 223 # skip our own timer thread
220 if frame.f_code.co_name == '__eventPollTimer': 224 if frame.f_code.co_name == '__eventPollTimer':
221 continue 225 continue
222 226
223 # Unknown thread 227 # Unknown thread
224 if id not in self.threads: 228 if threadId not in self.threads:
225 newThread = DebugBase(self) 229 newThread = DebugBase(self)
226 name = 'Thread-{0}'.format(self.threadNumber) 230 name = 'Thread-{0}'.format(self.threadNumber)
227 self.threadNumber += 1 231 self.threadNumber += 1
228 232
229 newThread.id = id 233 newThread.id = threadId
230 newThread.name = name 234 newThread.name = name
231 self.threads[id] = newThread 235 self.threads[threadId] = newThread
232 236
233 # adjust current frame 237 # adjust current frame
234 if "__pypy__" not in sys.builtin_module_names: 238 if "__pypy__" not in sys.builtin_module_names:
235 # Don't update with None 239 # Don't update with None
236 currentFrame = self.getExecutedFrame(frame) 240 currentFrame = self.getExecutedFrame(frame)
237 if (currentFrame is not None and 241 if (currentFrame is not None and
238 self.threads[id].isBroken is False): 242 self.threads[threadId].isBroken is False):
239 self.threads[id].currentFrame = currentFrame 243 self.threads[threadId].currentFrame = currentFrame
240 244
241 # Clean up obsolet because terminated threads 245 # Clean up obsolet because terminated threads
242 self.threads = {id_: thrd for id_, thrd in self.threads.items() 246 self.threads = {id_: thrd for id_, thrd in self.threads.items()
243 if id_ in frames} 247 if id_ in frames}
244 248
255 """ 259 """
256 if fullname in sys.modules or not self.debugging: 260 if fullname in sys.modules or not self.debugging:
257 return None 261 return None
258 262
259 if fullname in [self.threadModName, 'PyQt4.QtCore', 'PyQt5.QtCore', 263 if fullname in [self.threadModName, 'PyQt4.QtCore', 'PyQt5.QtCore',
260 'PySide.QtCore', 'PySide2.QtCore', 264 'PySide.QtCore', 'PySide2.QtCore', 'greenlet',
261 'threading'] and self.enableImportHooks: 265 'threading'] and self.enableImportHooks:
262 # Disable hook to be able to import original module 266 # Disable hook to be able to import original module
263 self.enableImportHooks = False 267 self.enableImportHooks = False
264 return self 268 return self
265 269
280 self._original_start_new_thread is None): 284 self._original_start_new_thread is None):
281 # make thread hooks available to system 285 # make thread hooks available to system
282 self._original_start_new_thread = module.start_new_thread 286 self._original_start_new_thread = module.start_new_thread
283 module.start_new_thread = self.attachThread 287 module.start_new_thread = self.attachThread
284 288
289 elif (fullname == 'greenlet' and self.greenlet is False):
290 # Check for greenlet.settrace
291 if hasattr(module, 'settrace'):
292 self.greenlet = True
293 DebugBase.pollTimerEnabled = False
294
295 # TODO: Implement the debugger extension for greenlets
296
285 # Add hook for threading.run() 297 # Add hook for threading.run()
286 elif (fullname == "threading" and self.threadingAttached is False): 298 elif (fullname == "threading" and self.threadingAttached is False):
287 self.threadingAttached = True 299 self.threadingAttached = True
288 300
289 # _debugClient as a class attribute can't be accessed in following 301 # _debugClient as a class attribute can't be accessed in following
295 Bootstrap for threading, which reports exceptions correctly. 307 Bootstrap for threading, which reports exceptions correctly.
296 308
297 @param run the run method of threading.Thread 309 @param run the run method of threading.Thread
298 @type method pointer 310 @type method pointer
299 """ 311 """
300 newThread = _debugClient.threads[self.ident] 312 newThread = DebugBase(_debugClient)
313 _debugClient.threads[self.ident] = newThread
301 newThread.name = self.name 314 newThread.name = self.name
302 # see DebugBase.bootstrap 315 # see DebugBase.bootstrap
303 sys.settrace(newThread.trace_dispatch) 316 sys.settrace(newThread.trace_dispatch)
304 try: 317 try:
305 run() 318 run()

eric ide

mercurial