summaryrefslogtreecommitdiff
path: root/python/helpers/pydev/pydevd_custom_frames.py
blob: 8709e6a17dd6458c6f387e605e4b891524b6bdda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from pydevd_constants import *  #@UnusedWildImport
from pydevd_file_utils import GetFilenameAndBase
from _pydev_imps import _pydev_thread
threadingCurrentThread = threading.currentThread

DEBUG = False

#=======================================================================================================================
# CustomFramesContainer
#=======================================================================================================================
class CustomFramesContainer:
    pass

    
def CustomFramesContainerInit(): #Note: no staticmethod on jython 2.1 (so, use free-function)
    
    CustomFramesContainer.custom_frames_lock = _pydev_thread.allocate_lock()
    
    # custom_frames can only be accessed if properly locked with custom_frames_lock! 
    # Key is a string identifying the frame (as well as the thread it belongs to). 
    # Value is a CustomFrame.
    #
    CustomFramesContainer.custom_frames = {}
    
    # Only to be used in this module
    CustomFramesContainer._next_frame_id = 0
    
    # This is the event we must set to release an internal process events. It's later set by the actual debugger
    # when we do create the debugger.
    CustomFramesContainer._py_db_command_thread_event = Null()
    
#Initialize it the first time (it may be reinitialized later on when dealing with a fork).
CustomFramesContainerInit()
    
    
#=======================================================================================================================
# CustomFrame
#=======================================================================================================================
class CustomFrame:
    
    def __init__(self, name, frame, thread_id):
        # 0 = string with the representation of that frame
        self.name = name
        
        # 1 = the frame to show
        self.frame = frame
        
        # 2 = an integer identifying the last time the frame was changed.
        self.mod_time = 0
        
        # 3 = the thread id of the given frame
        self.thread_id = thread_id


def addCustomFrame(frame, name, thread_id):
    CustomFramesContainer.custom_frames_lock.acquire()
    try:
        curr_thread_id = GetThreadId(threadingCurrentThread())
        next_id = CustomFramesContainer._next_frame_id = CustomFramesContainer._next_frame_id + 1
        
        # Note: the frame id kept contains an id and thread information on the thread where the frame was added
        # so that later on we can check if the frame is from the current thread by doing frame_id.endswith('|'+thread_id).
        frame_id = '__frame__:%s|%s' % (next_id, curr_thread_id)
        if DEBUG:
            sys.stderr.write('addCustomFrame: %s (%s) %s %s\n' % (
                frame_id, GetFilenameAndBase(frame)[1], frame.f_lineno, frame.f_code.co_name))

        CustomFramesContainer.custom_frames[frame_id] = CustomFrame(name, frame, thread_id)
        CustomFramesContainer._py_db_command_thread_event.set()
        return frame_id
    finally:
        CustomFramesContainer.custom_frames_lock.release()


def updateCustomFrame(frame_id, frame, thread_id, name=None):
    CustomFramesContainer.custom_frames_lock.acquire()
    try:
        if DEBUG:
            sys.stderr.write('updateCustomFrame: %s\n' % frame_id)
        try:
            old = CustomFramesContainer.custom_frames[frame_id]
            if name is not None:
                old.name = name
            old.mod_time += 1
            old.thread_id = thread_id
        except:
            sys.stderr.write('Unable to get frame to replace: %s\n' % (frame_id,))
            import traceback;traceback.print_exc()
            
        CustomFramesContainer._py_db_command_thread_event.set()
    finally:
        CustomFramesContainer.custom_frames_lock.release()


def getCustomFrame(thread_id, frame_id):
    '''
    :param thread_id: This should actually be the frame_id which is returned by addCustomFrame.
    :param frame_id: This is the actual id() of the frame
    '''
    
    CustomFramesContainer.custom_frames_lock.acquire()
    try:
        frame_id = int(frame_id)
        f = CustomFramesContainer.custom_frames[thread_id].frame
        while f is not None:
            if id(f) == frame_id:
                return f
            f = f.f_back
    finally:
        f = None
        CustomFramesContainer.custom_frames_lock.release()
    
    
def removeCustomFrame(frame_id):
    CustomFramesContainer.custom_frames_lock.acquire()
    try:
        if DEBUG:
            sys.stderr.write('removeCustomFrame: %s\n' % frame_id)
        DictPop(CustomFramesContainer.custom_frames, frame_id, None)
        CustomFramesContainer._py_db_command_thread_event.set()
    finally:
        CustomFramesContainer.custom_frames_lock.release()