DebugClients/Python/ThreadExtension.py

branch
debugger fine grinding
changeset 5552
313a91a38aed
parent 5544
5a90f78a73c9
child 5561
5fffb5cc1a88
equal deleted inserted replaced
5551:16f9a0bccda1 5552:313a91a38aed
18 18
19 import threading 19 import threading
20 20
21 from DebugBase import DebugBase 21 from DebugBase import DebugBase
22 22
23 _qtThreadNumber = 1
24
23 25
24 class ThreadExtension(object): 26 class ThreadExtension(object):
25 """ 27 """
26 Class implementing the thread support for the debugger. 28 Class implementing the thread support for the debugger.
27 29
34 """ 36 """
35 self.threadNumber = 1 37 self.threadNumber = 1
36 self.enableImportHooks = True 38 self.enableImportHooks = True
37 self._original_start_new_thread = None 39 self._original_start_new_thread = None
38 self.threadingAttached = False 40 self.threadingAttached = False
39 self._qtThread = None 41 self.qtThreadAttached = False
40 42
41 self.clientLock = threading.RLock() 43 self.clientLock = threading.RLock()
42 44
43 # dictionary of all threads running {id: DebugBase} 45 # dictionary of all threads running {id: DebugBase}
44 self.threads = {_thread.get_ident(): self} 46 self.threads = {_thread.get_ident(): self}
283 # _debugClient as a class attribute can't be accessed in following 285 # _debugClient as a class attribute can't be accessed in following
284 # class. Therefore we need a global variable. 286 # class. Therefore we need a global variable.
285 _debugClient = self 287 _debugClient = self
286 288
287 def _bootstrap(self, run): 289 def _bootstrap(self, run):
290 """
291 Bootstrap for threading, which reports exceptions correctly.
292
293 @param run the run method of threading.Thread
294 @type method pointer
295 """
288 newThread = _debugClient.threads[self.ident] 296 newThread = _debugClient.threads[self.ident]
289 newThread.name = self.name 297 newThread.name = self.name
290 # see DebugBase.bootstrap 298 # see DebugBase.bootstrap
291 sys.settrace(newThread.trace_dispatch) 299 sys.settrace(newThread.trace_dispatch)
292 try: 300 try:
294 except Exception: 302 except Exception:
295 excinfo = sys.exc_info() 303 excinfo = sys.exc_info()
296 newThread.user_exception(excinfo, True) 304 newThread.user_exception(excinfo, True)
297 305
298 class ThreadWrapper(module.Thread): 306 class ThreadWrapper(module.Thread):
307 """ Wrapper class for threading.Thread. """
299 308
300 def __init__(self, *args, **kwargs): 309 def __init__(self, *args, **kwargs):
301 # Overwrite the provided run method with our own, to 310 # Overwrite the provided run method with our own, to
302 # intercept the thread creation by threading.Thread 311 # intercept the thread creation by threading.Thread
303 self.run = lambda s=self, run=self.run: _bootstrap(s, run) 312 self.run = lambda s=self, run=self.run: _bootstrap(s, run)
304 313
305 super(ThreadWrapper, self).__init__(*args, **kwargs) 314 super(ThreadWrapper, self).__init__(*args, **kwargs)
306 315
307 module.Thread = ThreadWrapper 316 module.Thread = ThreadWrapper
308 317
318 # Add hook for *.QThread
309 elif (fullname in ['PyQt4.QtCore', 'PyQt5.QtCore', 319 elif (fullname in ['PyQt4.QtCore', 'PyQt5.QtCore',
310 'PySide.QtCore', 'PySide2.QtCore'] and 320 'PySide.QtCore', 'PySide2.QtCore'] and
311 self._qtThread is None): 321 self.qtThreadAttached is False):
312 self._qtThread = module.QThread 322 self.qtThreadAttached = True
313 # _debugClient as a class attribute can't be accessed in following 323 # _debugClient as a class attribute can't be accessed in following
314 # class. Therefore we need a global variable. 324 # class. Therefore we need a global variable.
315 _debugClient = self 325 _debugClient = self
316 326
327 def _bootstrapQThread(self, run):
328 """
329 Bootstrap for QThread, which reports exceptions correctly.
330
331 @param run the run method of *.QThread
332 @type method pointer
333 """
334 global _qtThreadNumber
335
336 newThread = DebugBase(_debugClient)
337 ident = _thread.get_ident()
338 name = 'QtThread-{0}'.format(_qtThreadNumber)
339
340 _qtThreadNumber += 1
341
342 newThread.id = ident
343 newThread.name = name
344
345 _debugClient.threads[ident] = newThread
346
347 # see DebugBase.bootstrap
348 sys.settrace(newThread.trace_dispatch)
349 try:
350 run()
351 except SystemExit:
352 # *.QThreads doesn't like SystemExit
353 pass
354 except Exception:
355 excinfo = sys.exc_info()
356 newThread.user_exception(excinfo, True)
357
317 class QThreadWrapper(module.QThread): 358 class QThreadWrapper(module.QThread):
318 __qtThreadNumber = 1 359 """ Wrapper class for *.QThread. """
319 360
320 def __init__(self, *args, **kwargs): 361 def __init__(self, *args, **kwargs):
321 # Overwrite the provided run method with our own, to 362 # Overwrite the provided run method with our own, to
322 # intercept the thread creation by Qt 363 # intercept the thread creation by Qt
323 self._ApplicationRun = self.run 364 self.run = lambda s=self, run=self.run: (
324 self.run = self.__bootstrapQThread 365 _bootstrapQThread(s, run))
325 366
326 super(QThreadWrapper, self).__init__(*args, **kwargs) 367 super(QThreadWrapper, self).__init__(*args, **kwargs)
327
328 def __bootstrapQThread(self):
329 newThread = DebugBase(_debugClient)
330 ident = _thread.get_ident()
331 name = 'QtThread-{0}'.format(self.__qtThreadNumber)
332 self.__qtThreadNumber += 1
333
334 newThread.id = ident
335 newThread.name = name
336
337 _debugClient.threads[ident] = newThread
338
339 frame = sys._getframe()
340 newThread.botframe = frame
341 frame.f_trace = newThread.trace_dispatch
342 # see DebugBase.bootstrap
343 sys.settrace(
344 lambda frame, event, arg: newThread.trace_dispatch)
345
346 return self._ApplicationRun()
347 368
348 module.QThread = QThreadWrapper 369 module.QThread = QThreadWrapper
349 370
350 self.enableImportHooks = True 371 self.enableImportHooks = True
351 return module 372 return module
352 373
353
354 # 374 #
355 # eflag: noqa = M702 375 # eflag: noqa = M702

eric ide

mercurial