Fix deadlock in FarmMultiple()

Our Forget() tasks are in fact getting forgotten when given async method stumbles upon await call.

We were executing async Farm() via Forget(), but it was entirely possible that we won't get opportunity to await anything if we follow FarmHours() path, making FarmingSemaphore signaled until we're done farming hours.
This commit is contained in:
JustArchi 2017-07-03 18:54:57 +02:00
parent 02f3a74dc9
commit 96a69f2157
5 changed files with 39 additions and 11 deletions

View file

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/TypingAssist/SmartIndentOnEnter/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/IncludeWarningsInSwea/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AnnotateCanBeNullParameter/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AnnotateCanBeNullTypeMember/@EntryIndexedValue">SUGGESTION</s:String>

View file

@ -3603,7 +3603,7 @@ namespace ArchiSteamFarm {
private async Task Start() {
if (!KeepRunning) {
KeepRunning = true;
Task.Factory.StartNew(HandleCallbacks, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning).Forget();
Utilities.StartBackgroundAction(HandleCallbacks);
ArchiLogger.LogGenericInfo(Strings.Starting);
}

View file

@ -93,7 +93,13 @@ namespace ArchiSteamFarm {
IdleFarmingTimer?.Dispose();
}
internal void OnDisconnected() => StopFarming().Forget();
internal void OnDisconnected() {
if (!NowFarming) {
return;
}
StopFarming().Forget();
}
internal async Task OnNewGameAdded() {
// We aim to have a maximum of 2 tasks, one already parsing, and one waiting in the queue
@ -222,7 +228,7 @@ namespace ArchiSteamFarm {
}
KeepFarming = NowFarming = true;
Farm().Forget(); // Farm() will end when we're done farming, so don't wait for it
Utilities.StartBackgroundFunction(Farm);
} finally {
FarmingSemaphore.Release();
}

View file

@ -64,6 +64,7 @@ namespace ArchiSteamFarm {
}
KeepRunning = true;
Utilities.StartBackgroundFunction(Run);
Task.Factory.StartNew(Run, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning).Forget();
ASF.ArchiLogger.LogGenericInfo(Strings.IPCReady);

View file

@ -29,6 +29,7 @@ using System.Globalization;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Humanizer;
namespace ArchiSteamFarm {
@ -40,17 +41,18 @@ namespace ArchiSteamFarm {
internal static void Forget(this object obj) { }
internal static string GetArgsAsString(this string[] args, byte argsToSkip = 1) {
if (args.Length >= argsToSkip) {
return string.Join(" ", args.GetArgs(argsToSkip));
if ((args == null) || (args.Length < argsToSkip)) {
ASF.ArchiLogger.LogNullError(nameof(args));
return null;
}
ASF.ArchiLogger.LogNullError(nameof(args));
return null;
string result = string.Join(" ", args.GetArgs(argsToSkip));
return result;
}
internal static string GetCookieValue(this CookieContainer cookieContainer, string url, string name) {
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(name)) {
ASF.ArchiLogger.LogNullError(nameof(url) + " || " + nameof(name));
if ((cookieContainer == null) || string.IsNullOrEmpty(url) || string.IsNullOrEmpty(name)) {
ASF.ArchiLogger.LogNullError(nameof(cookieContainer) + " || " + nameof(url) + " || " + nameof(name));
return null;
}
@ -93,14 +95,32 @@ namespace ArchiSteamFarm {
}
}
internal static IEnumerable<T> ToEnumerable<T>(this T item) {
internal static void StartBackgroundAction(Action action) {
if (action == null) {
ASF.ArchiLogger.LogNullError(nameof(action));
return;
}
Task.Factory.StartNew(action, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning).Forget();
}
internal static void StartBackgroundFunction(Func<Task> function) {
if (function == null) {
ASF.ArchiLogger.LogNullError(nameof(function));
return;
}
Task.Factory.StartNew(function, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning).Forget();
}
internal static IEnumerable<T> ToEnumerable<T>(this T item) where T : struct {
yield return item;
}
internal static string ToHumanReadable(this TimeSpan timeSpan) => timeSpan.Humanize(3);
private static string[] GetArgs(this string[] args, byte argsToSkip = 1) {
if (args.Length < argsToSkip) {
if ((args == null) || (args.Length < argsToSkip)) {
ASF.ArchiLogger.LogNullError(nameof(args));
return null;
}