|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the debug thread. |
|
8 """ |
|
9 |
|
10 import bdb |
|
11 import os |
|
12 import sys |
|
13 |
|
14 from DebugBase import * |
|
15 |
|
16 class DebugThread(DebugBase): |
|
17 """ |
|
18 Class implementing a debug thread. |
|
19 |
|
20 It represents a thread in the python interpreter that we are tracing. |
|
21 |
|
22 Provides simple wrapper methods around bdb for the 'owning' client to |
|
23 call to step etc. |
|
24 """ |
|
25 def __init__(self, dbgClient, targ = None, args = None, kwargs = None, |
|
26 mainThread = False): |
|
27 """ |
|
28 Constructor |
|
29 |
|
30 @param dbgClient the owning client |
|
31 @param targ the target method in the run thread |
|
32 @param args arguments to be passed to the thread |
|
33 @param kwargs arguments to be passed to the thread |
|
34 @param mainThread 0 if this thread is not the mainscripts thread |
|
35 """ |
|
36 DebugBase.__init__(self, dbgClient) |
|
37 |
|
38 self._target = targ |
|
39 self._args = args |
|
40 self._kwargs = kwargs |
|
41 self._mainThread = mainThread |
|
42 # thread running tracks execution state of client code |
|
43 # it will always be False for main thread as that is tracked |
|
44 # by DebugClientThreads and Bdb... |
|
45 self._threadRunning = False |
|
46 |
|
47 self.__ident = None # id of this thread. |
|
48 self.__name = "" |
|
49 |
|
50 def set_ident(self, id): |
|
51 """ |
|
52 Public method to set the id for this thread. |
|
53 |
|
54 @param id id for this thread (int) |
|
55 """ |
|
56 self.__ident = id |
|
57 |
|
58 def get_ident(self): |
|
59 """ |
|
60 Public method to return the id of this thread. |
|
61 |
|
62 @return the id of this thread (int) |
|
63 """ |
|
64 return self.__ident |
|
65 |
|
66 def get_name(self): |
|
67 """ |
|
68 Public method to return the name of this thread. |
|
69 |
|
70 @return name of this thread (string) |
|
71 """ |
|
72 return self.__name |
|
73 |
|
74 def traceThread(self): |
|
75 """ |
|
76 Private method to setup tracing for this thread. |
|
77 """ |
|
78 self.set_trace() |
|
79 if not self._mainThread: |
|
80 self.set_continue(False) |
|
81 |
|
82 def bootstrap(self): |
|
83 """ |
|
84 Private method to bootstrap the thread. |
|
85 |
|
86 It wraps the call to the user function to enable tracing |
|
87 before hand. |
|
88 """ |
|
89 try: |
|
90 self._threadRunning = True |
|
91 self.traceThread() |
|
92 self._target(*self._args, **self._kwargs) |
|
93 except bdb.BdbQuit: |
|
94 pass |
|
95 finally: |
|
96 self._threadRunning = False |
|
97 self.quitting = True |
|
98 self._dbgClient.threadTerminated(self) |
|
99 sys.settrace(None) |
|
100 sys.setprofile(None) |
|
101 |
|
102 def trace_dispatch(self, frame, event, arg): |
|
103 """ |
|
104 Private method wrapping the trace_dispatch of bdb.py. |
|
105 |
|
106 It wraps the call to dispatch tracing into |
|
107 bdb to make sure we have locked the client to prevent multiple |
|
108 threads from entering the client event loop. |
|
109 |
|
110 @param frame The current stack frame. |
|
111 @param event The trace event (string) |
|
112 @param arg The arguments |
|
113 @return local trace function |
|
114 """ |
|
115 try: |
|
116 self._dbgClient.lockClient() |
|
117 # if this thread came out of a lock, and we are quitting |
|
118 # and we are still running, then get rid of tracing for this thread |
|
119 if self.quitting and self._threadRunning: |
|
120 sys.settrace(None) |
|
121 sys.setprofile(None) |
|
122 import threading |
|
123 self.__name = threading.current_thread().name |
|
124 retval = DebugBase.trace_dispatch(self, frame, event, arg) |
|
125 finally: |
|
126 self._dbgClient.unlockClient() |
|
127 |
|
128 return retval |