Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: LockFileEx/UnLockFileEx methods shouldn't be called explicitly #2564

Merged
merged 5 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions sources/core/Stride.Core.Design/Windows/FileLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ public void Dispose()
{
if (lockFile != null)
{
var overlapped = new NativeOverlapped();
NativeLockFile.UnlockFileEx(lockFile.SafeFileHandle, 0, uint.MaxValue, uint.MaxValue, ref overlapped);
NativeLockFile.TryUnlockFile(lockFile, 0, uint.MaxValue);
lockFile.Dispose();

// Try to delete the file
Expand Down Expand Up @@ -95,8 +94,7 @@ public static FileLock Wait(string name, int millisecondsTimeout)
if (millisecondsTimeout != 0 && millisecondsTimeout != -1)
throw new NotImplementedException("GlobalMutex.Wait() is implemented only for millisecondsTimeout 0 or -1");

var overlapped = new NativeOverlapped();
bool hasHandle = NativeLockFile.LockFileEx(fileLock.SafeFileHandle, NativeLockFile.LOCKFILE_EXCLUSIVE_LOCK | (millisecondsTimeout == 0 ? NativeLockFile.LOCKFILE_FAIL_IMMEDIATELY : 0), 0, uint.MaxValue, uint.MaxValue, ref overlapped);
bool hasHandle = NativeLockFile.TryLockFile(fileLock, 0, uint.MaxValue, true, millisecondsTimeout == 0);
return hasHandle == false ? null : new FileLock(fileLock);
}
catch (AbandonedMutexException)
Expand Down
25 changes: 9 additions & 16 deletions sources/core/Stride.Core.IO/NativeLockFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ namespace Stride.Core.IO
public static class NativeLockFile
{
[DllImport("Kernel32.dll", SetLastError = true)]
internal static extern bool LockFileEx(Microsoft.Win32.SafeHandles.SafeFileHandle handle, uint flags, uint reserved, uint countLow, uint countHigh, ref System.Threading.NativeOverlapped overlapped);
private static extern bool LockFileEx(Microsoft.Win32.SafeHandles.SafeFileHandle handle, uint flags, uint reserved, uint countLow, uint countHigh, ref System.Threading.NativeOverlapped overlapped);

[DllImport("Kernel32.dll", SetLastError = true)]
internal static extern bool UnlockFileEx(Microsoft.Win32.SafeHandles.SafeFileHandle handle, uint reserved, uint countLow, uint countHigh, ref System.Threading.NativeOverlapped overlapped);
private static extern bool UnlockFileEx(Microsoft.Win32.SafeHandles.SafeFileHandle handle, uint reserved, uint countLow, uint countHigh, ref System.Threading.NativeOverlapped overlapped);

internal const uint LOCKFILE_FAIL_IMMEDIATELY = 0x00000001;
internal const uint LOCKFILE_EXCLUSIVE_LOCK = 0x00000002;

public static void LockFile(FileStream fileStream, long offset, long count, bool exclusive)
public static bool TryLockFile(FileStream fileStream, long offset, long count, bool exclusive, bool failImmediately = false)
{
if (Platform.Type == PlatformType.Android)
{
Expand All @@ -36,17 +36,11 @@ public static void LockFile(FileStream fileStream, long offset, long count, bool

var overlapped = new NativeOverlapped()
{
InternalLow = IntPtr.Zero,
InternalHigh = IntPtr.Zero,
OffsetLow = (int)(offset & 0x00000000FFFFFFFF),
OffsetLow = (int)(offset & uint.MaxValue),
OffsetHigh = (int)(offset >> 32),
EventHandle = IntPtr.Zero,
};

if (!LockFileEx(fileStream.SafeFileHandle, exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, countLow, countHigh, ref overlapped))
{
throw new IOException("Couldn't lock file.");
}
return LockFileEx(fileStream.SafeFileHandle, (exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0) + (failImmediately ? NativeLockFile.LOCKFILE_FAIL_IMMEDIATELY : 0), 0, countLow, countHigh, ref overlapped);
}
else
{
Expand All @@ -57,16 +51,18 @@ public static void LockFile(FileStream fileStream, long offset, long count, bool
try
{
fileStream.Lock(offset, count);
return true;
}
catch (IOException)
{
tryAgain = true;
}
} while (tryAgain);
}
return false;
}

public static void UnlockFile(FileStream fileStream, long offset, long count)
public static void TryUnlockFile(FileStream fileStream, long offset, long count)
{
if (Platform.Type == PlatformType.Android)
{
Expand All @@ -81,11 +77,8 @@ public static void UnlockFile(FileStream fileStream, long offset, long count)

var overlapped = new NativeOverlapped()
{
InternalLow = IntPtr.Zero,
InternalHigh = IntPtr.Zero,
OffsetLow = (int)(offset & 0x00000000FFFFFFFF),
OffsetLow = (int)(offset & uint.MaxValue),
OffsetHigh = (int)(offset >> 32),
EventHandle = IntPtr.Zero,
};

if (!UnlockFileEx(fileStream.SafeFileHandle, 0, countLow, countHigh, ref overlapped))
Expand Down
24 changes: 18 additions & 6 deletions sources/core/Stride.Core.Serialization/IO/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,11 @@ private void SaveValues(IEnumerable<T> values, int currentTransaction)
// Acquire lock on end of file (for appending)
// This will prevent another thread from writing at the same time, or reading before it is flushed.
if (LockEnabled && stream is FileStream)
NativeLockFile.LockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition, true);
{
bool failed = !NativeLockFile.TryLockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition, true);
if (failed)
throw new IOException("Couldn't lock file.");
}

try
{
Expand Down Expand Up @@ -163,7 +167,7 @@ private void SaveValues(IEnumerable<T> values, int currentTransaction)
finally
{
if (LockEnabled && stream is FileStream)
NativeLockFile.UnlockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition);
NativeLockFile.TryUnlockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition);
}
}
}
Expand All @@ -180,7 +184,11 @@ private void SaveValue(T item, int currentTransaction)
// Acquire lock on end of file (for appending)
// This will prevent another thread from writing at the same time, or reading before it is flushed.
if (LockEnabled && stream is FileStream)
NativeLockFile.LockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition, true);
{
bool failed = !NativeLockFile.TryLockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition, true);
if (failed)
throw new IOException("Couldn't lock file.");
}

try
{
Expand All @@ -203,7 +211,7 @@ private void SaveValue(T item, int currentTransaction)
finally
{
if (LockEnabled && stream is FileStream)
NativeLockFile.UnlockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition);
NativeLockFile.TryUnlockFile((FileStream)stream, indexStreamPosition, long.MaxValue - indexStreamPosition);
}
}
}
Expand Down Expand Up @@ -276,7 +284,11 @@ public bool LoadNewValues()
// Or if the previously described case doesn't happen, maybe no lock at all is required?
// Otherwise, last possibility would be deterministic filesize (with size encoded at the beginning of each block).
if (LockEnabled && stream is FileStream)
NativeLockFile.LockFile((FileStream)stream, position, long.MaxValue - position, false);
{
bool failed = !NativeLockFile.TryLockFile((FileStream)stream, position, long.MaxValue - position, false);
if (failed)
throw new IOException("Couldn't lock file.");
}

try
{
Expand All @@ -288,7 +300,7 @@ public bool LoadNewValues()
{
// Release the lock
if (LockEnabled && stream is FileStream)
NativeLockFile.UnlockFile((FileStream)stream, position, long.MaxValue - position);
NativeLockFile.TryUnlockFile((FileStream)stream, position, long.MaxValue - position);
}

return true;
Expand Down