2 // System.Net.Sockets.SafeSocketHandle
5 // Marcos Henrich <marcos.henrich@xamarin.com>
10 using System.Threading;
11 using System.Collections.Generic;
12 using Microsoft.Win32.SafeHandles;
14 namespace System.Net.Sockets {
16 sealed class SafeSocketHandle : SafeHandleZeroOrMinusOneIsInvalid {
18 List<Thread> blocking_threads;
20 const int ABORT_RETRIES = 10;
21 static bool THROW_ON_ABORT_RETRIES = Environment.GetEnvironmentVariable("MONO_TESTS_IN_PROGRESS") == "yes";
23 public SafeSocketHandle (IntPtr preexistingHandle, bool ownsHandle) : base (ownsHandle)
25 SetHandle (preexistingHandle);
28 // This is just for marshalling
29 internal SafeSocketHandle () : base (true)
35 /*protected override void Dispose (bool disposing)
42 Socket.Blocking_internal (handle, false, out error);
43 //AbortRegisteredThreads ();
44 Socket.Close_internal (handle, out error);
45 //Console.Error.WriteLine ("Closed "+ handle);
48 base.Dispose (disposing);
51 protected override bool ReleaseHandle ()
55 Socket.Blocking_internal (handle, false, out error);
57 if (blocking_threads != null) {
58 int abort_attempts = 0;
59 while (blocking_threads.Count > 0) {
60 if (abort_attempts++ >= ABORT_RETRIES) {
61 if (THROW_ON_ABORT_RETRIES)
62 throw new Exception ("Could not abort registered blocking threads before closing socket.");
64 // Attempts to close the socket safely failed.
65 // We give up, and close the socket with pending blocking system calls.
66 // This should not occur, nonetheless if it does this avoids an endless loop.
70 AbortRegisteredThreads ();
71 // Sleep so other threads can resume
76 Socket.Close_internal (handle, out error);
81 public void RegisterForBlockingSyscall ()
83 if (blocking_threads == null)
84 Interlocked.CompareExchange (ref blocking_threads, new List<Thread> (), null);
88 DangerousAddRef (ref release);
90 /* We must use a finally block here to make this atomic. */
91 lock (blocking_threads) {
92 blocking_threads.Add (Thread.CurrentThread);
99 /* This must be called from a finally block! */
100 public void UnRegisterForBlockingSyscall ()
102 //If this NRE, we're in deep problems because Register Must have
103 lock (blocking_threads) {
104 blocking_threads.Remove (Thread.CurrentThread);
108 void AbortRegisteredThreads () {
109 if (blocking_threads == null)
112 lock (blocking_threads) {
113 foreach (var t in blocking_threads)
114 Socket.cancel_blocking_socket_operation (t);