Browse Source

[System] Improved "Could not abort" exception.

Stack traces of blocked threads are now displayed on the exception.

The threads stacktraces are only stored when MONO_TESTS_IN_PROGRESS env
var is set to yes.
Marcos Henrich 9 years ago
parent
commit
91c68de23f
1 changed files with 23 additions and 2 deletions
  1. 23 2
      mcs/class/System/System.Net.Sockets/SafeSocketHandle.cs

+ 23 - 2
mcs/class/System/System.Net.Sockets/SafeSocketHandle.cs

@@ -7,7 +7,9 @@
 
 using System;
 using System.IO;
+using System.Text;
 using System.Threading;
+using System.Diagnostics;
 using System.Collections.Generic;
 using Microsoft.Win32.SafeHandles;
 
@@ -16,6 +18,8 @@ namespace System.Net.Sockets {
 	sealed class SafeSocketHandle : SafeHandleZeroOrMinusOneIsInvalid {
 
 		List<Thread> blocking_threads;
+		Dictionary<Thread, StackTrace> threads_stacktraces;
+
 		bool in_cleanup;
 
 		const int SOCKET_CLOSED = 10004;
@@ -26,6 +30,9 @@ namespace System.Net.Sockets {
 		public SafeSocketHandle (IntPtr preexistingHandle, bool ownsHandle) : base (ownsHandle)
 		{
 			SetHandle (preexistingHandle);
+
+			if (THROW_ON_ABORT_RETRIES)
+				threads_stacktraces = new Dictionary<Thread, StackTrace> ();
 		}
 
 		// This is just for marshalling
@@ -48,8 +55,17 @@ namespace System.Net.Sockets {
 					int abort_attempts = 0;
 					while (blocking_threads.Count > 0) {
 						if (abort_attempts++ >= ABORT_RETRIES) {
-							if (THROW_ON_ABORT_RETRIES)
-								throw new Exception ("Could not abort registered blocking threads before closing socket.");
+							if (THROW_ON_ABORT_RETRIES) {
+								StringBuilder sb = new StringBuilder ();
+								sb.AppendLine ("Could not abort registered blocking threads before closing socket.");
+								foreach (var thread in blocking_threads) {
+									sb.AppendLine ("Thread StackTrace:");
+									sb.AppendLine (threads_stacktraces[thread].ToString ());
+								}
+								sb.AppendLine ();
+
+								throw new Exception (sb.ToString ());
+							}
 
 							// Attempts to close the socket safely failed.
 							// We give up, and close the socket with pending blocking system calls.
@@ -94,6 +110,8 @@ namespace System.Net.Sockets {
 				/* We must use a finally block here to make this atomic. */
 				lock (blocking_threads) {
 					blocking_threads.Add (Thread.CurrentThread);
+					if (THROW_ON_ABORT_RETRIES)
+						threads_stacktraces.Add (Thread.CurrentThread, new StackTrace (true));
 				}
 				if (release)
 					DangerousRelease ();
@@ -110,6 +128,9 @@ namespace System.Net.Sockets {
 			//If this NRE, we're in deep problems because Register Must have
 			lock (blocking_threads) {
 				blocking_threads.Remove (Thread.CurrentThread);
+				if (THROW_ON_ABORT_RETRIES)
+					threads_stacktraces.Remove (Thread.CurrentThread);
+
 				if (in_cleanup && blocking_threads.Count == 0)
 					Monitor.Pulse (blocking_threads);
 			}