SafeSocketHandle: avoid potential blocking of finalizer thread - #41508
Conversation
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.
|
Tagging subscribers to this area: @dotnet/ncl |
|
I know it's a bit off-topic, but if we are already here, would make sense to remove comments about inner/outer handles in
|
antonfirsov
left a comment
There was a problem hiding this comment.
Just nits, should be good once a test is added.
|
Anton, thanks for reviewing! I've addressed your feedback. Socket tests pass on my machine. |
|
The OSX test failure is unrelated and tracked in #41511, the mono one seems to be a hang in |
antonfirsov
left a comment
There was a problem hiding this comment.
LGTM.
@geoffkizer if you are also fine with the changes and all tests do pass, maybe we can even do the packport today?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Inner loop test failure is #41078 |
antonfirsov
left a comment
There was a problem hiding this comment.
Test failure seems related:
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
at System.Net.Sockets.Socket.Dispose(Boolean disposing) in /_/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs:line 4262
at System.Net.Sockets.Socket.Finalize() in /_/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs:line 4367
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
at System.Net.Sockets.Socket.Dispose(Boolean disposing) in /_/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs:line 4262
at System.Net.Sockets.Socket.Finalize() in /_/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs:line 4367
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
We do have a test somewhere that ensures that the socket handle is closed when the Socket gets finalized, right? This was the original problem that led us to adding logic to the Socket finalizer. We need to make sure we haven't broken that again. |
|
NonDisposedSocket_SafeHandlesCollected ? |
|
/backport to release/5.0 |
|
Started backporting to release/5.0: https://github.com/dotnet/runtime/actions/runs/234344348 |
|
/backport to release/5.0-rc2 |
|
Started backporting to release/5.0-rc2: https://github.com/dotnet/runtime/actions/runs/236412175 |
…izer thread (#41747) Backport of #41508 to release/5.0-rc2 * 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 Co-authored-by: Tom Deseyn <tom.deseyn@gmail.com>
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.
Fixes #40301
@antonfirsov @geoffkizer ptal
cc @jaredpar