protected override bool ReleaseHandle() { int error = 0; Socket.Blocking_internal(handle, false, out error); #if MOBILE_STATIC /* It's only for platforms that do not have working syscall abort mechanism, like WatchOS and TvOS */ Socket.Shutdown_internal(handle, SocketShutdown.Both, out error); #endif if (blocking_threads != null) { lock (blocking_threads) { 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."); } // Attempts to close the socket safely failed. // We give up, and close the socket with pending blocking system calls. // This should not occur, nonetheless if it does this avoids an endless loop. break; } /* * This method can be called by the DangerousRelease inside RegisterForBlockingSyscall * When this happens blocking_threads contains the current thread. * We can safely close the socket and throw SocketException in RegisterForBlockingSyscall * before the blocking system call. */ if (blocking_threads.Count == 1 && blocking_threads[0] == Thread.CurrentThread) { break; } // abort registered threads foreach (var t in blocking_threads) { Socket.cancel_blocking_socket_operation(t); } // Sleep so other threads can resume in_cleanup = true; Monitor.Wait(blocking_threads, 100); } } } Socket.Close_internal(handle, out error); return(error == 0); }
protected override bool ReleaseHandle() { int error = 0; Socket.Blocking_internal(handle, false, out error); if (blocking_threads != null) { 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."); } // Attempts to close the socket safely failed. // We give up, and close the socket with pending blocking system calls. // This should not occur, nonetheless if it does this avoids an endless loop. break; } /* * This method can be called by the DangerousRelease inside RegisterForBlockingSyscall * When this happens blocking_threads contains the current thread. * We can safely close the socket and throw SocketException in RegisterForBlockingSyscall * before the blocking system call. */ lock (blocking_threads) { if (blocking_threads.Count == 1 && blocking_threads[0] == Thread.CurrentThread) { break; } } AbortRegisteredThreads(); // Sleep so other threads can resume Thread.Sleep(1); } } Socket.Close_internal(handle, out error); return(error == 0); }