SafeSocketHandle: avoid potential blocking of finalizer thread (#41508)
* SafeSocketHandle: avoid potential blocking of finalizer thread
When the Socket is Disposed, it attempts to make all on-going operations
abort. It does this in a loop, and decides there are no on-going operations
when the reference count becomes zero and the handle gets released.
SafePipeHandle holds a reference to SafeSocketHandle. This prevents the
reference count to drop to zero, and causes the dispose to loop infinitly.
When the Socket is disposed from the finalizer thread, it is no longer used
for operations and we can skip the loop. This avoids blocking the finalizer
thread when the reference count can't drop to zero.
* When disposing from finalizer, fall back to ReleaseHandle
* Add test
* PR feedback
* Fix test
* PR feedback
* Refactor
* Refactor
* Log call to _handle.Dispose
* Handle null handle