Merge pull request #1068 from esdrubal/bug18421
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / ThreadMirror.cs
1 using System;
2 using System.Threading;
3 using System.Collections.Generic;
4
5 namespace Mono.Debugger.Soft
6 {
7         public class ThreadMirror : ObjectMirror
8         {
9                 string name;
10                 bool cacheInvalid = true;
11                 bool fetching;
12                 object fetchingLocker = new object ();
13                 ManualResetEvent fetchingEvent = new ManualResetEvent (false);
14                 ThreadInfo info;
15                 StackFrame[] frames;
16
17                 internal ThreadMirror (VirtualMachine vm, long id) : base (vm, id) {
18                 }
19
20                 internal ThreadMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id, type, domain) {
21                 }
22
23                 public StackFrame[] GetFrames () {
24                         FetchFrames (true);
25                         fetchingEvent.WaitOne ();
26                         return frames;
27                 }
28
29                 internal void InvalidateFrames () {
30                         cacheInvalid = true;
31                 }
32
33                 internal void FetchFrames (bool mustFetch = false) {
34                         lock (fetchingLocker) {
35                                 if (fetching || !cacheInvalid)
36                                         return;
37                                 cacheInvalid = false;
38                                 fetching = true;
39                                 fetchingEvent.Reset ();
40                         }
41                         vm.conn.Thread_GetFrameInfo (id, 0, -1, (frame_info) => {
42                                 var framesList = new List<StackFrame> ();
43                                 for (int i = 0; i < frame_info.Length; ++i) {
44                                         var frameInfo = (FrameInfo)frame_info [i];
45                                         var method = vm.GetMethod (frameInfo.method);
46                                         var f = new StackFrame (vm, frameInfo.id, this, method, frameInfo.il_offset, frameInfo.flags);
47                                         if (!(f.IsNativeTransition && !NativeTransitions))
48                                                 framesList.Add (f);
49                                 }
50                                 lock (fetchingLocker) {
51                                         vm.AddThreadToInvalidateList (this);
52                                         fetching = false;
53                                         //In case it was invalidated during waiting for response from
54                                         //runtime and mustFetch was set refetch
55                                         if (cacheInvalid && mustFetch) {
56                                                 FetchFrames (mustFetch);
57                                                 return;
58                                         }
59                                         frames = framesList.ToArray ();
60                                         fetchingEvent.Set ();
61                                 }
62                         });
63                 }
64
65                 public static void FetchFrames(IList<ThreadMirror> threads)
66                 {
67                         if (threads.Count == 0)
68                                 return;
69                         threads [0].vm.conn.StartBuffering ();
70                         foreach (var thread in threads) {
71                                 thread.FetchFrames ();
72                         }
73                         threads [0].vm.conn.StopBuffering ();
74                 }
75
76                 public string Name {
77                         get {
78                                 if (name == null)
79                                         name = vm.conn.Thread_GetName (id);
80                                 return name;
81                         }
82                 }
83
84                 public new long Id {
85                         get {
86                                 return id;
87                         }
88                 }
89
90                 public ThreadState ThreadState {
91                         get {
92                                 return (ThreadState)vm.conn.Thread_GetState (id);
93                         }
94                 }
95
96                 public bool IsThreadPoolThread {
97                         get {
98                                 if (info == null)
99                                         info = vm.conn.Thread_GetInfo (id);
100                                 return info.is_thread_pool;
101                         }
102                 }
103
104                 long? thread_id;
105                 /*
106                  * Return a unique identifier for this thread, multiple ThreadMirror objects
107                  * may have the same ThreadId because of appdomains.
108                  */
109                 public long ThreadId {
110                         get {
111                                 if (thread_id == null)
112                                         thread_id = vm.conn.Thread_GetId (id);
113                                 return (long)thread_id;
114                         }
115                 }
116
117                 /*
118                  * Return the system thread id (TID) for this thread, this id is not unique since
119                  * a newly started thread might reuse a dead thread's id.
120                  */
121                 public long TID {
122                         get {
123                                 return vm.conn.Thread_GetTID (id);
124                         }
125                 }
126
127                 /*
128                  * Get/set whenever GetFrames () should return frames for managed-to-native
129                  * transitions, i.e frames whose IsNativeTransition property is set.
130                  * This is needed because some clients might not be able to deal with those
131                  * frames.
132                  */
133                 public static bool NativeTransitions {
134                         get; set;
135                 }
136
137                 /*
138                  * Set the location where execution will return when this thread is
139                  * resumed.
140                  * Throws:
141                  * ArgumentException - if L doesn't refer to a location in the
142                  * current method of this thread.
143                  * NotSupportedException - if continuing at L is not supported
144                  * for any other reason.
145                  * Since protocol version 29.
146                  */
147                 public void SetIP (Location loc) {
148                         if (loc == null)
149                                 throw new ArgumentNullException ("loc");
150                         try {
151                                 vm.conn.Thread_SetIP (id, loc.Method.Id, loc.ILOffset);
152                         } catch (CommandException ex) {
153                                 if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
154                                         throw new ArgumentException ("loc doesn't refer to a location in the current method of this thread.", "loc");
155
156                                 throw;
157                         }
158                 }
159     }
160 }