From 00a841afcb8c1c6b79e0acf2af11cc0abef045c3 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Tue, 16 Oct 2018 02:30:16 +0200 Subject: [PATCH] Improve FSW of ASF in terms of race conditions --- ArchiSteamFarm/ASF.cs | 92 +++++++++---------------------------------- 1 file changed, 19 insertions(+), 73 deletions(-) diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index 219be734f..ca80f9627 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -33,7 +33,7 @@ namespace ArchiSteamFarm { internal static class ASF { internal static readonly ArchiLogger ArchiLogger = new ArchiLogger(SharedInfo.ASF); - private static readonly ConcurrentDictionary LastWriteTimes = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary LastWriteEvents = new ConcurrentDictionary(); private static readonly SemaphoreSlim UpdateSemaphore = new SemaphoreSlim(1, 1); private static Timer AutoUpdatesTimer; @@ -241,6 +241,18 @@ namespace ArchiSteamFarm { await RestartOrExit().ConfigureAwait(false); } + private static async Task CanHandleWriteEvent(string name) { + // Save our event in dictionary + object currentWriteEvent = new object(); + LastWriteEvents[name] = currentWriteEvent; + + // Wait a second for eventual other events to arrive + await Task.Delay(1000).ConfigureAwait(false); + + // We're allowed to handle this event if the one that is saved after full second is our event and we succeed in clearing it (we don't care what we're clearing anymore, it doesn't have to be atomic operation) + return LastWriteEvents.TryGetValue(name, out object savedWriteEvent) && (currentWriteEvent == savedWriteEvent) && LastWriteEvents.TryRemove(name, out _); + } + private static bool IsValidBotName(string botName) { if (string.IsNullOrEmpty(botName)) { ArchiLogger.LogNullError(nameof(botName)); @@ -319,30 +331,8 @@ namespace ArchiSteamFarm { return; } - DateTime lastWriteTime = DateTime.UtcNow; - - if (LastWriteTimes.TryGetValue(name, out DateTime savedLastWriteTime)) { - if (savedLastWriteTime >= lastWriteTime) { - return; - } - } - - LastWriteTimes[name] = lastWriteTime; - - // It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it - await Task.Delay(1000).ConfigureAwait(false); - - // It's also possible that we got some other event in the meantime - if (LastWriteTimes.TryGetValue(name, out savedLastWriteTime)) { - if (lastWriteTime != savedLastWriteTime) { - return; - } - - if (LastWriteTimes.TryRemove(name, out savedLastWriteTime)) { - if (lastWriteTime != savedLastWriteTime) { - return; - } - } + if (!await CanHandleWriteEvent(name).ConfigureAwait(false)) { + return; } if (botName.Equals(SharedInfo.ASF)) { @@ -391,30 +381,8 @@ namespace ArchiSteamFarm { return; } - DateTime lastWriteTime = DateTime.UtcNow; - - if (LastWriteTimes.TryGetValue(name, out DateTime savedLastWriteTime)) { - if (savedLastWriteTime >= lastWriteTime) { - return; - } - } - - LastWriteTimes[name] = lastWriteTime; - - // It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it - await Task.Delay(1000).ConfigureAwait(false); - - // It's also possible that we got some other event in the meantime - if (LastWriteTimes.TryGetValue(name, out savedLastWriteTime)) { - if (lastWriteTime != savedLastWriteTime) { - return; - } - - if (LastWriteTimes.TryRemove(name, out savedLastWriteTime)) { - if (lastWriteTime != savedLastWriteTime) { - return; - } - } + if (!await CanHandleWriteEvent(name).ConfigureAwait(false)) { + return; } if (!Bot.Bots.TryGetValue(botName, out Bot bot)) { @@ -444,30 +412,8 @@ namespace ArchiSteamFarm { return; } - DateTime lastWriteTime = DateTime.UtcNow; - - if (LastWriteTimes.TryGetValue(name, out DateTime savedLastWriteTime)) { - if (savedLastWriteTime >= lastWriteTime) { - return; - } - } - - LastWriteTimes[name] = lastWriteTime; - - // It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it - await Task.Delay(1000).ConfigureAwait(false); - - // It's also possible that we got some other event in the meantime - if (LastWriteTimes.TryGetValue(name, out savedLastWriteTime)) { - if (lastWriteTime != savedLastWriteTime) { - return; - } - - if (LastWriteTimes.TryRemove(name, out savedLastWriteTime)) { - if (lastWriteTime != savedLastWriteTime) { - return; - } - } + if (!await CanHandleWriteEvent(name).ConfigureAwait(false)) { + return; } if (botName.Equals(SharedInfo.ASF)) {