private static SafeMemoryMappedFileHandle CreateOrOpenCore(
string mapName, HandleInheritability inheritability, MemoryMappedFileAccess access,
MemoryMappedFileOptions options, long capacity)
{
/// Try to open the file if it exists -- this requires a bit more work. Loop until we can
/// either create or open a memory mapped file up to a timeout. CreateFileMapping may fail
/// if the file exists and we have non-null security attributes, in which case we need to
/// use OpenFileMapping. But, there exists a race condition because the memory mapped file
/// may have closed between the two calls -- hence the loop.
///
/// The retry/timeout logic increases the wait time each pass through the loop and times
/// out in approximately 1.4 minutes. If after retrying, a MMF handle still hasn't been opened,
/// throw an InvalidOperationException.
Debug.Assert(access != MemoryMappedFileAccess.Write, "Callers requesting write access shouldn't try to create a mmf");
SafeMemoryMappedFileHandle handle = null;
Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability);
int waitRetries = 14; //((2^13)-1)*10ms == approximately 1.4mins
int waitSleep = 0;
// keep looping until we've exhausted retries or break as soon we get valid handle
while (waitRetries > 0)
{
// try to create
handle = Interop.CreateFileMapping(INVALID_HANDLE_VALUE, ref secAttrs,
GetPageAccess(access) | (int)options, capacity, mapName);
if (!handle.IsInvalid)
{
break;
}
else
{
handle.Dispose();
int createErrorCode = Marshal.GetLastWin32Error();
if (createErrorCode != Interop.Errors.ERROR_ACCESS_DENIED)
{
throw Win32Marshal.GetExceptionForWin32Error(createErrorCode);
}
}
// try to open
handle = Interop.OpenFileMapping(GetFileMapAccess(access), (inheritability &
HandleInheritability.Inheritable) != 0, mapName);
// valid handle
if (!handle.IsInvalid)
{
break;
}
// didn't get valid handle; have to retry
else
{
handle.Dispose();
int openErrorCode = Marshal.GetLastWin32Error();
if (openErrorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
{
throw Win32Marshal.GetExceptionForWin32Error(openErrorCode);
}
// increase wait time
--waitRetries;
if (waitSleep == 0)
{
waitSleep = 10;
}
else
{
ThreadSleep(waitSleep);
waitSleep *= 2;
}
}
}
// finished retrying but couldn't create or open
if (handle == null || handle.IsInvalid)
{
throw new InvalidOperationException(SR.InvalidOperation_CantCreateFileMapping);
}
return handle;
}