You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -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,9 @@ 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;
|
||||
|
||||
@ -25,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
|
||||
@ -43,32 +51,45 @@ namespace System.Net.Sockets {
|
||||
#endif
|
||||
|
||||
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.");
|
||||
lock (blocking_threads) {
|
||||
int abort_attempts = 0;
|
||||
while (blocking_threads.Count > 0) {
|
||||
if (abort_attempts++ >= ABORT_RETRIES) {
|
||||
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 ();
|
||||
|
||||
// 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;
|
||||
}
|
||||
throw new Exception (sb.ToString ());
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
AbortRegisteredThreads ();
|
||||
// Sleep so other threads can resume
|
||||
Thread.Sleep (1);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,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 ();
|
||||
@ -105,16 +128,11 @@ 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);
|
||||
|
||||
void AbortRegisteredThreads () {
|
||||
if (blocking_threads == null)
|
||||
return;
|
||||
|
||||
lock (blocking_threads) {
|
||||
foreach (var t in blocking_threads)
|
||||
Socket.cancel_blocking_socket_operation (t);
|
||||
if (in_cleanup && blocking_threads.Count == 0)
|
||||
Monitor.Pulse (blocking_threads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user