diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Watchdog.cs | 98 |
1 files changed, 80 insertions, 18 deletions
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs index 3389ecb..e26a6f2 100644 --- a/OpenSim/Framework/Watchdog.cs +++ b/OpenSim/Framework/Watchdog.cs | |||
@@ -40,19 +40,31 @@ namespace OpenSim.Framework | |||
40 | { | 40 | { |
41 | /// <summary>Timer interval in milliseconds for the watchdog timer</summary> | 41 | /// <summary>Timer interval in milliseconds for the watchdog timer</summary> |
42 | const double WATCHDOG_INTERVAL_MS = 2500.0d; | 42 | const double WATCHDOG_INTERVAL_MS = 2500.0d; |
43 | |||
43 | /// <summary>Maximum timeout in milliseconds before a thread is considered dead</summary> | 44 | /// <summary>Maximum timeout in milliseconds before a thread is considered dead</summary> |
44 | const int WATCHDOG_TIMEOUT_MS = 5000; | 45 | const int WATCHDOG_TIMEOUT_MS = 5000; |
45 | 46 | ||
46 | [System.Diagnostics.DebuggerDisplay("{Thread.Name}")] | 47 | [System.Diagnostics.DebuggerDisplay("{Thread.Name}")] |
47 | public class ThreadWatchdogInfo | 48 | public class ThreadWatchdogInfo |
48 | { | 49 | { |
49 | public Thread Thread; | 50 | public Thread Thread { get; private set; } |
50 | public int LastTick; | 51 | public int LastTick { get; set; } |
52 | |||
53 | /// <summary> | ||
54 | /// Number of milliseconds before we notify that the thread is having a problem. | ||
55 | /// </summary> | ||
56 | public int Timeout { get; set; } | ||
57 | |||
58 | /// <summary> | ||
59 | /// Is this thread considered timed out? | ||
60 | /// </summary> | ||
61 | public bool IsTimedOut { get; set; } | ||
51 | 62 | ||
52 | public ThreadWatchdogInfo(Thread thread) | 63 | public ThreadWatchdogInfo(Thread thread, int timeout) |
53 | { | 64 | { |
54 | Thread = thread; | 65 | Thread = thread; |
55 | LastTick = Environment.TickCount; | 66 | Timeout = timeout; |
67 | LastTick = Environment.TickCount & Int32.MaxValue; | ||
56 | } | 68 | } |
57 | } | 69 | } |
58 | 70 | ||
@@ -82,7 +94,7 @@ namespace OpenSim.Framework | |||
82 | } | 94 | } |
83 | 95 | ||
84 | /// <summary> | 96 | /// <summary> |
85 | /// Start a new thread that is tracked by the watchdog timer | 97 | /// Start a new thread that is tracked by the watchdog timer. |
86 | /// </summary> | 98 | /// </summary> |
87 | /// <param name="start">The method that will be executed in a new thread</param> | 99 | /// <param name="start">The method that will be executed in a new thread</param> |
88 | /// <param name="name">A name to give to the new thread</param> | 100 | /// <param name="name">A name to give to the new thread</param> |
@@ -92,12 +104,37 @@ namespace OpenSim.Framework | |||
92 | /// <returns>The newly created Thread object</returns> | 104 | /// <returns>The newly created Thread object</returns> |
93 | public static Thread StartThread(ThreadStart start, string name, ThreadPriority priority, bool isBackground) | 105 | public static Thread StartThread(ThreadStart start, string name, ThreadPriority priority, bool isBackground) |
94 | { | 106 | { |
107 | return StartThread(start, name, priority, isBackground, WATCHDOG_TIMEOUT_MS); | ||
108 | } | ||
109 | |||
110 | /// <summary> | ||
111 | /// Start a new thread that is tracked by the watchdog timer | ||
112 | /// </summary> | ||
113 | /// <param name="start">The method that will be executed in a new thread</param> | ||
114 | /// <param name="name">A name to give to the new thread</param> | ||
115 | /// <param name="priority">Priority to run the thread at</param> | ||
116 | /// <param name="isBackground">True to run this thread as a background | ||
117 | /// thread, otherwise false</param> | ||
118 | /// <param name="timeout"> | ||
119 | /// Number of milliseconds to wait until we issue a warning about timeout. | ||
120 | /// </para> | ||
121 | /// <returns>The newly created Thread object</returns> | ||
122 | public static Thread StartThread( | ||
123 | ThreadStart start, string name, ThreadPriority priority, bool isBackground, int timeout) | ||
124 | { | ||
95 | Thread thread = new Thread(start); | 125 | Thread thread = new Thread(start); |
96 | thread.Name = name; | 126 | thread.Name = name; |
97 | thread.Priority = priority; | 127 | thread.Priority = priority; |
98 | thread.IsBackground = isBackground; | 128 | thread.IsBackground = isBackground; |
99 | thread.Start(); | 129 | thread.Start(); |
100 | 130 | ||
131 | ThreadWatchdogInfo twi = new ThreadWatchdogInfo(thread, timeout); | ||
132 | |||
133 | m_log.Debug("[WATCHDOG]: Started tracking thread \"" + twi.Thread.Name + "\" (ID " + twi.Thread.ManagedThreadId + ")"); | ||
134 | |||
135 | lock (m_threads) | ||
136 | m_threads.Add(twi.Thread.ManagedThreadId, twi); | ||
137 | |||
101 | return thread; | 138 | return thread; |
102 | } | 139 | } |
103 | 140 | ||
@@ -112,25 +149,38 @@ namespace OpenSim.Framework | |||
112 | /// <summary> | 149 | /// <summary> |
113 | /// Stops watchdog tracking on the current thread | 150 | /// Stops watchdog tracking on the current thread |
114 | /// </summary> | 151 | /// </summary> |
115 | /// <returns>True if the thread was removed from the list of tracked | 152 | /// <returns> |
116 | /// threads, otherwise false</returns> | 153 | /// True if the thread was removed from the list of tracked |
154 | /// threads, otherwise false | ||
155 | /// </returns> | ||
117 | public static bool RemoveThread() | 156 | public static bool RemoveThread() |
118 | { | 157 | { |
119 | return RemoveThread(Thread.CurrentThread.ManagedThreadId); | 158 | return RemoveThread(Thread.CurrentThread.ManagedThreadId); |
120 | } | 159 | } |
121 | 160 | ||
122 | private static void AddThread(ThreadWatchdogInfo threadInfo) | 161 | private static bool RemoveThread(int threadID) |
123 | { | 162 | { |
124 | m_log.Debug("[WATCHDOG]: Started tracking thread \"" + threadInfo.Thread.Name + "\" (ID " + threadInfo.Thread.ManagedThreadId + ")"); | ||
125 | |||
126 | lock (m_threads) | 163 | lock (m_threads) |
127 | m_threads.Add(threadInfo.Thread.ManagedThreadId, threadInfo); | 164 | return m_threads.Remove(threadID); |
128 | } | 165 | } |
129 | 166 | ||
130 | public static bool RemoveThread(int threadID) | 167 | public static bool AbortThread(int threadID) |
131 | { | 168 | { |
132 | lock (m_threads) | 169 | lock (m_threads) |
133 | return m_threads.Remove(threadID); | 170 | { |
171 | if (m_threads.ContainsKey(threadID)) | ||
172 | { | ||
173 | ThreadWatchdogInfo twi = m_threads[threadID]; | ||
174 | twi.Thread.Abort(); | ||
175 | RemoveThread(threadID); | ||
176 | |||
177 | return true; | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | return false; | ||
182 | } | ||
183 | } | ||
134 | } | 184 | } |
135 | 185 | ||
136 | private static void UpdateThread(int threadID) | 186 | private static void UpdateThread(int threadID) |
@@ -144,9 +194,14 @@ namespace OpenSim.Framework | |||
144 | try | 194 | try |
145 | { | 195 | { |
146 | if (m_threads.TryGetValue(threadID, out threadInfo)) | 196 | if (m_threads.TryGetValue(threadID, out threadInfo)) |
147 | threadInfo.LastTick = Environment.TickCount; | 197 | { |
198 | threadInfo.LastTick = Environment.TickCount & Int32.MaxValue; | ||
199 | threadInfo.IsTimedOut = false; | ||
200 | } | ||
148 | else | 201 | else |
149 | AddThread(new ThreadWatchdogInfo(Thread.CurrentThread)); | 202 | { |
203 | m_log.WarnFormat("[WATCHDOG]: Asked to update thread {0} which is not being monitored", threadID); | ||
204 | } | ||
150 | } | 205 | } |
151 | catch { } | 206 | catch { } |
152 | } | 207 | } |
@@ -157,7 +212,8 @@ namespace OpenSim.Framework | |||
157 | /// <returns></returns> | 212 | /// <returns></returns> |
158 | public static ThreadWatchdogInfo[] GetThreads() | 213 | public static ThreadWatchdogInfo[] GetThreads() |
159 | { | 214 | { |
160 | return m_threads.Values.ToArray(); | 215 | lock (m_threads) |
216 | return m_threads.Values.ToArray(); | ||
161 | } | 217 | } |
162 | 218 | ||
163 | private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) | 219 | private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) |
@@ -174,10 +230,16 @@ namespace OpenSim.Framework | |||
174 | 230 | ||
175 | foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) | 231 | foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) |
176 | { | 232 | { |
177 | if (threadInfo.Thread.ThreadState == ThreadState.Stopped || now - threadInfo.LastTick >= WATCHDOG_TIMEOUT_MS) | 233 | if (threadInfo.Thread.ThreadState == ThreadState.Stopped) |
234 | { | ||
235 | timedOut = threadInfo; | ||
236 | RemoveThread(threadInfo.Thread.ManagedThreadId); | ||
237 | break; | ||
238 | } | ||
239 | else if (!threadInfo.IsTimedOut && now - threadInfo.LastTick >= threadInfo.Timeout) | ||
178 | { | 240 | { |
241 | threadInfo.IsTimedOut = true; | ||
179 | timedOut = threadInfo; | 242 | timedOut = threadInfo; |
180 | m_threads.Remove(threadInfo.Thread.ManagedThreadId); | ||
181 | break; | 243 | break; |
182 | } | 244 | } |
183 | } | 245 | } |