private static unsafe void WriteSyncUsingAsyncHandle(SafeFileHandle handle, ReadOnlySpan <byte> buffer, long fileOffset)
{
if (buffer.IsEmpty)
{
return;
}
handle.EnsureThreadPoolBindingInitialized();
CallbackResetEvent resetEvent = new CallbackResetEvent(handle.ThreadPoolBinding !);
NativeOverlapped * overlapped = null;
try
{
overlapped = GetNativeOverlappedForAsyncHandle(handle.ThreadPoolBinding !, fileOffset, resetEvent);
fixed(byte *pinned = &MemoryMarshal.GetReference(buffer))
{
Interop.Kernel32.WriteFile(handle, pinned, buffer.Length, IntPtr.Zero, overlapped);
int errorCode = FileStreamHelpers.GetLastWin32ErrorAndDisposeHandleIfInvalid(handle);
if (errorCode == Interop.Errors.ERROR_IO_PENDING)
{
resetEvent.WaitOne();
errorCode = Interop.Errors.ERROR_SUCCESS;
}
if (errorCode == Interop.Errors.ERROR_SUCCESS)
{
int result = 0;
if (Interop.Kernel32.GetOverlappedResult(handle, overlapped, ref result, bWait: false))
{
Debug.Assert(result == buffer.Length, $"GetOverlappedResult returned {result} for {buffer.Length} bytes request");
return;
}
errorCode = FileStreamHelpers.GetLastWin32ErrorAndDisposeHandleIfInvalid(handle);
}
switch (errorCode)
{
case Interop.Errors.ERROR_NO_DATA:
// For pipes, ERROR_NO_DATA is not an error, but the pipe is closing.
return;
case Interop.Errors.ERROR_INVALID_PARAMETER:
// ERROR_INVALID_PARAMETER may be returned for writes
// where the position is too large or for synchronous writes
// to a handle opened asynchronously.
throw new IOException(SR.IO_FileTooLong);
default:
throw Win32Marshal.GetExceptionForWin32Error(errorCode, handle.Path);
}
}
}
finally
{
if (overlapped != null)
{
resetEvent.FreeNativeOverlapped(overlapped);
}
resetEvent.Dispose();
}
}