--- a/DebugClients/Python/ThreadExtension.py Sat Oct 08 21:01:32 2016 +0200 +++ b/DebugClients/Python/ThreadExtension.py Sun Oct 09 22:22:36 2016 +0200 @@ -145,6 +145,7 @@ Public method to set the current thread. @param id the id the current thread should be set to. + @type int """ try: self.lockClient() @@ -159,6 +160,7 @@ """ Public method to send the list of threads. """ + self.updateThreadList() threadList = [] if len(self.threads) > 1: currentId = _thread.get_ident() @@ -187,6 +189,54 @@ "threadList": threadList, }) + def getExecutedFrame(self, frame): + """ + Public method to return the currently executed frame. + + @param frame the current frame + @type frame object + @return the frame which is excecuted (without debugger frames) + @rtype frame object + """ + # to get the currently executed frame, skip all frames belonging to the + # debugger + while frame is not None: + baseName = os.path.basename(frame.f_code.co_filename) + if not baseName.startswith( + ('DebugClientBase.py', 'DebugBase.py', 'AsyncIO.py', + 'ThreadExtension.py', 'threading.py')): + break + frame = frame.f_back + + return frame + + def updateThreadList(self): + """ + Public method to update the list of running threads. + """ + frames = sys._current_frames() + for id, frame in frames.items(): + # skip our own timer thread + if frame.f_code.co_name == '__eventPollTimer': + continue + + # Unknown thread + if id not in self.threads: + newThread = DebugBase(self) + name = 'Thread-{0}'.format(self.threadNumber) + self.threadNumber += 1 + + newThread.id = id + newThread.name = name + self.threads[id] = newThread + + # adjust current frame + self.threads[id].currentFrame = self.getExecutedFrame(frame) + + # Clean up obsolet because terminated threads + self.threads = {id_: thrd for id_, thrd in self.threads.items() + if id_ in frames} + def find_module(self, fullname, path=None): """ Public method returning the module loader.