def attachThread(self, target=None, args=None, kwargs=None,
                     mainThread=False):
        """
        Public method to setup a standard thread for DebugClient to debug.

        If mainThread is True, then we are attaching to the already
        started mainthread of the app and the rest of the args are ignored.
        """
        if kwargs is None:
            kwargs = {}

        if mainThread:
            ident = _thread.get_ident()
            name = 'MainThread'
            newThread = self.mainThread
            newThread.isMainThread = True
        else:
            newThread = DebugBase(self)
            ident = self._original_start_new_thread(
                newThread.bootstrap, (target, args, kwargs))
            name = 'Thread-{0}'.format(self.threadNumber)
            self.threadNumber += 1

        newThread.id = ident
        newThread.name = name

        self.threads[ident] = newThread

        return ident
            def _bootstrapQThread(self, run):
                """Bootstrap for QThread, which reports exceptions correctly"""
                global _qtThreadNumber

                newThread = DebugBase(_debugClient)
                ident = _thread.get_ident()
                name = 'QtThread-{0}'.format(_qtThreadNumber)

                _qtThreadNumber += 1

                newThread.id = ident
                newThread.name = name

                _debugClient.threads[ident] = newThread

                # see DebugBase.bootstrap
                sys.settrace(newThread.trace_dispatch)
                try:
                    run()
                except SystemExit:
                    # *.QThreads doesn't like SystemExit
                    pass
                except Exception:
                    excinfo = sys.exc_info()
                    newThread.user_exception(excinfo, True)
                finally:
                    sys.settrace(None)
    def updateThreadList(self):
        """Updates the list of running threads"""
        frames = sys._current_frames()
        for threadId, frame in frames.items():
            # skip our own timer thread
            if frame.f_code.co_name == '__eventPollTimer':
                continue

            # Unknown thread
            if threadId not in self.threads:
                newThread = DebugBase(self)
                name = 'Thread-{0}'.format(self.threadNumber)
                self.threadNumber += 1

                newThread.id = threadId
                newThread.name = name
                self.threads[threadId] = newThread

            # adjust current frame
            if "__pypy__" not in sys.builtin_module_names:
                # Don't update with None
                currentFrame = self.getExecutedFrame(frame)
                if (currentFrame is not None and
                        self.threads[threadId].isBroken is False):
                    self.threads[threadId].currentFrame = currentFrame

        # Clean up obsolet because terminated threads
        self.threads = {id_: thrd for id_, thrd in self.threads.items()
                        if id_ in frames}
            def _bootstrap(self, run):
                """
                Bootstrap for threading, which reports exceptions correctly.

                @param run the run method of threading.Thread
                @type method pointer
                """
                newThread = DebugBase(_debugClient)
                _debugClient.threads[self.ident] = newThread
                newThread.name = self.name
                # see DebugBase.bootstrap
                sys.settrace(newThread.trace_dispatch)
                try:
                    run()
                except Exception:
                    excinfo = sys.exc_info()
                    newThread.user_exception(excinfo, True)
                finally:
                    sys.settrace(None)