-
Notifications
You must be signed in to change notification settings - Fork 57
Description
I have been using AsyncIO to write TCP applications for quite sometime. However, I encountered weird behaviors when the workload went a bit heavy, about several thousands of concurrent connections at a time.
I then studied the source code and deduct the possible production procedures of the issue:
- Called the
Send
orReceive
method of theAsyncSocket
(via the Windows implementation, the one that P/Invoke winsocks). Dispose
theAsyncSocket
before the overlapped operation is completed.- The
CancelIoEx
is called, the cancellation is send on its way. closesocket
is called.- The
Dispose
(Free
) ofm_receivePinnedBuffer
andm_sendPinnedBuffer
will be called.
- The
- GC reclaims the memory assigned to
AsyncSocket
.
According to the documetation of CancelIoEx
:
Most types of operations can be canceled immediately; other operations can continue toward completion before they are actually canceled and the caller is notified. The CancelIoEx function does not wait for all canceled operations to complete.
...The operation being canceled is completed with one of three statuses; you must check the completion status to determine the completion state. The three statuses are:
- The operation completed normally. This can occur even if the operation was canceled, because the cancel request might not have been submitted in time to cancel the operation.
- The operation was canceled. The GetLastError function returns ERROR_OPERATION_ABORTED.
- The operation failed with another error. The GetLastError function returns the relevant error code.
Thus, theoretically, the overlapped operation may still complete after the Dispose
of AsyncSocket
is called and write data back to the buffer that m_receivePinnedBuffer
points to.
In most cases, it's OK since the aforementioned buffer is pointing to a managed byte array, which is just unpinned by the Free
method and it usually may still be there.
However, if GC happens before the write-back, things can go wrong since the buffers have already been unpinned and can be moved by GC.
A rarer case is that the GC occurs when an overlapped sending operation and incorrect bytes will be read
by the outgoing sender, before the cancellation is executed.
How do you think about the above situation? Please correct me if I am wrong.