DebugClients/Python/ThreadExtension.py

branch
debugger speed
changeset 5207
7283629b02c0
child 5208
aa8045780ce4
equal deleted inserted replaced
5206:997064ba25d6 5207:7283629b02c0
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing an import hook patching thread modules to get debugged too.
8 """
9
10 import os.path
11 import sys
12
13 if sys.version_info[0] == 2:
14 import thread as _thread
15 else:
16 import _thread
17
18 import threading
19
20 from DebugBase import DebugBase
21
22
23 class ThreadExtension(object):
24 """
25 Class implementing the thread support for the debugger.
26
27 Provides methods for intercepting thread creation, retriving the running
28 threads and their name and state.
29 """
30 def __init__(self):
31 """
32 Constructor
33 """
34 self.threadNumber = 1
35 self._original_start_new_thread = None
36
37 self.clientLock = threading.RLock()
38
39 # dictionary of all threads running {id: DebugBase}
40 self.threads = {}
41
42 # the "current" thread, basically for variables view
43 self.currentThread = self
44
45 # special objects representing the main scripts thread and frame
46 self.mainThread = self
47
48 if sys.version_info[0] == 2:
49 self.threadModName = 'thread'
50 else:
51 self.threadModName = '_thread'
52
53 # reset already imported thread module to apply hooks at next import
54 del sys.modules[self.threadModName]
55 del sys.modules['threading']
56
57 # provide a hook to perform a hard breakpoint
58 # Use it like this:
59 # if hasattr(sys, 'breakpoint): sys.breakpoint()
60 sys.breakpoint = self.set_trace
61
62 def attachThread(self, target=None, args=None, kwargs=None,
63 mainThread=False):
64 """
65 Public method to setup a thread for DebugClient to debug.
66
67 If mainThread is True, then we are attaching to the already
68 started mainthread of the app and the rest of the args are ignored.
69
70 @param target the start function of the target thread (i.e. the
71 user code)
72 @param args arguments to pass to target
73 @param kwargs keyword arguments to pass to target
74 @param mainThread True, if we are attaching to the already
75 started mainthread of the app
76 @return identifier of the created thread
77 """
78 return
79 try:
80 self.lockClient()
81 newThread = DebugThread(self, target, args, kwargs, mainThread)
82 ident = -1
83 if mainThread:
84 ident = _thread.get_ident()
85 self.mainThread = newThread
86 if self.debugging:
87 sys.setprofile(newThread.profile)
88 else:
89 ident = _original_start_thread(newThread.bootstrap, ())
90 if self.mainThread is not None:
91 self.tracePython = self.mainThread.tracePython
92 newThread.set_ident(ident)
93 self.threads[newThread.get_ident()] = newThread
94 finally:
95 self.unlockClient()
96 return ident
97
98 def threadTerminated(self, dbgThread):
99 """
100 Public method called when a DebugThread has exited.
101
102 @param dbgThread the DebugThread that has exited
103 """
104 self.lockClient()
105 try:
106 del self.threads[dbgThread.get_ident()]
107 except KeyError:
108 pass
109 finally:
110 self.unlockClient()
111
112 def lockClient(self, blocking=True):
113 """
114 Public method to acquire the lock for this client.
115
116 @param blocking flag to indicating a blocking lock
117 @type bool
118 @return flag indicating successful locking
119 @rtype bool
120 """
121 if blocking:
122 self.clientLock.acquire()
123 else:
124 return self.clientLock.acquire(blocking)
125
126 def unlockClient(self):
127 """
128 Public method to release the lock for this client.
129 """
130 try:
131 self.clientLock.release()
132 except AssertionError:
133 pass
134
135 def setCurrentThread(self, id):
136 """
137 Public method to set the current thread.
138
139 @param id the id the current thread should be set to.
140 """
141 try:
142 self.lockClient()
143 if id is None or id not in self.threads:
144 self.currentThread = None
145 else:
146 self.currentThread = self.threads[id]
147 finally:
148 self.unlockClient()
149
150 def dumpThreadList(self):
151 """
152 Public method to send the list of threads.
153 """
154 threadList = []
155 if self.threads and self.currentThread:
156 # indication for the threaded debugger
157 currentId = self.currentThread.get_ident()
158 for t in self.threads.values():
159 d = {}
160 d["id"] = t.get_ident()
161 d["name"] = t.get_name()
162 d["broken"] = t.isBroken
163 threadList.append(d)
164 else:
165 currentId = -1
166 d = {}
167 d["id"] = -1
168 d["name"] = "MainThread"
169 if hasattr(self, "isBroken"):
170 d["broken"] = self.isBroken
171 else:
172 d["broken"] = False
173 threadList.append(d)
174
175 self.sendJsonCommand("ResponseThreadList", {
176 "currentID": currentId,
177 "threadList": threadList,
178 })
179
180
181 #
182 # eflag: noqa = M702

eric ide

mercurial