319 if self.stop_here(frame) or frame == self.botframe: |
320 if self.stop_here(frame) or frame == self.botframe: |
320 # Ignore return events in generator except when stepping. |
321 # Ignore return events in generator except when stepping. |
321 if self.stopframe and frame.f_code.co_flags & CO_GENERATOR: |
322 if self.stopframe and frame.f_code.co_flags & CO_GENERATOR: |
322 return |
323 return |
323 # The program has finished if we have just left the first frame |
324 # The program has finished if we have just left the first frame |
324 if (frame == self.botframe and |
325 if frame == self.botframe: |
325 self._mainThread): |
326 if self.isMainThread: |
326 atexit._run_exitfuncs() |
327 atexit._run_exitfuncs() |
327 self._dbgClient.progTerminated(arg) |
328 self._dbgClient.progTerminated(arg) |
|
329 else: |
|
330 self._dbgClient.threadTerminated(self.id) |
328 |
331 |
329 if self.quitting and not self._dbgClient.passive: |
332 if self.quitting and not self._dbgClient.passive: |
330 raise SystemExit |
333 raise SystemExit |
331 return |
334 return |
332 |
335 |
382 stopOnHandleLine = self._dbgClient.handleLine.__code__ |
385 stopOnHandleLine = self._dbgClient.handleLine.__code__ |
383 bootstrap = 'bootstrap' |
386 bootstrap = 'bootstrap' |
384 |
387 |
385 frame.f_trace = self.trace_dispatch |
388 frame.f_trace = self.trace_dispatch |
386 while frame is not None: |
389 while frame is not None: |
387 # stop at erics debugger frame |
390 # stop at erics debugger frame or the threading bootstrap |
388 if frame.f_back.f_code == stopOnHandleLine: |
391 if (frame.f_back.f_code == stopOnHandleLine or |
|
392 frame.f_back.f_code.co_name == bootstrap): |
389 frame.f_trace = self.trace_dispatch |
393 frame.f_trace = self.trace_dispatch |
390 self.botframe = frame |
394 self.botframe = frame |
391 break |
395 break |
392 |
396 |
393 frame = frame.f_back |
397 frame = frame.f_back |
394 |
398 |
395 self.stop_everywhere = True |
399 self.stop_everywhere = True |
396 sys.settrace(self.trace_dispatch) |
400 sys.settrace(self.trace_dispatch) |
397 sys.setprofile(self._dbgClient.callTraceEnabled) |
401 sys.setprofile(self._dbgClient.callTraceEnabled) |
398 |
402 |
399 def bootstrap(self): |
403 def bootstrap(self, target, args, kwargs): |
400 """ |
404 """ |
401 Public method to bootstrap the thread. |
405 Public method to bootstrap a thread. |
402 |
406 |
403 It wraps the call to the user function to enable tracing |
407 It wraps the call to the user function to enable tracing |
404 before hand. |
408 before hand. |
|
409 |
|
410 @param target function which is called in the new created thread |
|
411 @type function pointer |
|
412 @param args arguments to pass to target |
|
413 @type tuple |
|
414 @param kwargs keyword arguments to pass to target |
|
415 @type dict |
405 """ |
416 """ |
406 try: |
417 try: |
407 self._threadRunning = True |
418 frame = sys._getframe() |
408 self.traceThread() |
419 self.botframe = frame |
409 self._target(*self._args, **self._kwargs) |
420 # First time the dispach function is called, a "base debug" |
|
421 # function has to be returned, which is called at every user code |
|
422 # function call. Because of setting botframe manually, the |
|
423 # specific branch returning the trace_dispatch itself is skipped. |
|
424 # Because the next step is always in threading.py and we assume |
|
425 # that there is no breakpoint in it, it's save to return |
|
426 # trace_dispatch unconditionally. |
|
427 sys.settrace(lambda frame, event, arg: self.trace_dispatch) |
|
428 frame.f_trace = self.trace_dispatch |
|
429 |
|
430 target(*args, **kwargs) |
410 except SystemExit: |
431 except SystemExit: |
411 pass |
432 pass |
412 finally: |
433 finally: |
413 self._threadRunning = False |
|
414 self.quitting = True |
|
415 self._dbgClient.threadTerminated(self) |
|
416 sys.settrace(None) |
|
417 sys.setprofile(None) |
434 sys.setprofile(None) |
418 |
435 |
419 def run(self, cmd, globals=None, locals=None): |
436 def run(self, cmd, globals=None, locals=None): |
420 """ |
437 """ |
421 Public method to start a given command under debugger control. |
438 Public method to start a given command under debugger control. |