Skip to content

Commit

Permalink
feat: LockFileEx/UnLockFileEx methods shouldn't be called explicitly (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Jklawreszuk authored Dec 17, 2024
1 parent 51410f6 commit aa8ab55
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 26 deletions.
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

0 comments on commit aa8ab55

Please sign in to comment.