OBT/1.2.1(Summer update)
Sync with upstream
This commit is contained in:
@@ -332,17 +332,9 @@ namespace Barotrauma
|
||||
void RunStateUnloaded_OnEnter(State<RunState> currentState)
|
||||
{
|
||||
Logger.LogMessage("LuaCs unloaded state entered");
|
||||
|
||||
if (PackageManagementService.IsAnyPackageRunning())
|
||||
{
|
||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||
}
|
||||
|
||||
if (PackageManagementService.IsAnyPackageLoaded())
|
||||
{
|
||||
DisposeLuaCsConfig();
|
||||
Logger.LogResults(PackageManagementService.UnloadAllPackages());
|
||||
}
|
||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||
DisposeLuaCsConfig();
|
||||
Logger.LogResults(PackageManagementService.UnloadAllPackages());
|
||||
|
||||
EventService.Reset();
|
||||
ConfigService.Reset();
|
||||
@@ -362,11 +354,7 @@ namespace Barotrauma
|
||||
void RunStateLoadedNoExec_OnEnter(State<RunState> currentState)
|
||||
{
|
||||
Logger.LogMessage("LuaCs no execution state entered");
|
||||
|
||||
if (PackageManagementService.IsAnyPackageRunning())
|
||||
{
|
||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||
}
|
||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||
|
||||
if (!PackageManagementService.IsAnyPackageLoaded())
|
||||
{
|
||||
|
||||
@@ -256,6 +256,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public Result<Assembly> CompileScriptAssembly([NotNull] string assemblyName,
|
||||
bool compileWithInternalAccess,
|
||||
ImmutableArray<SyntaxTree> syntaxTrees,
|
||||
@@ -348,6 +349,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public FluentResults.Result<Assembly> LoadAssemblyFromFile(string assemblyFilePath,
|
||||
ImmutableArray<string> additionalDependencyPaths)
|
||||
{
|
||||
@@ -434,6 +436,8 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public FluentResults.Result<Assembly> GetAssemblyByName(string assemblyName)
|
||||
{
|
||||
if (IsDisposed)
|
||||
@@ -481,6 +485,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public FluentResults.Result<ImmutableArray<Type>> GetTypesInAssemblies()
|
||||
{
|
||||
if (IsDisposed)
|
||||
@@ -501,6 +506,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public IEnumerable<Type> UnsafeGetTypesInAssemblies()
|
||||
{
|
||||
if (IsDisposed)
|
||||
@@ -529,6 +535,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public Result<Type> GetTypeInAssemblies(string typeName)
|
||||
{
|
||||
if (IsDisposed)
|
||||
@@ -557,13 +564,12 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
return; // we don't want to invoke events twice nor cause strong GC handles.
|
||||
IsDisposed = true;
|
||||
this.Unload();
|
||||
this.DisposeInternal();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~AssemblyLoader()
|
||||
{
|
||||
this.DisposeInternal();
|
||||
this.Unload();
|
||||
}
|
||||
|
||||
private void OnUnload(AssemblyLoadContext context)
|
||||
@@ -578,8 +584,8 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
Thread.Sleep(1000/Timing.FixedUpdateRate-1);
|
||||
}
|
||||
|
||||
var wf = new WeakReference<IAssemblyLoaderService>(this);
|
||||
_onUnload?.Invoke(this);
|
||||
this.DisposeInternal();
|
||||
}
|
||||
|
||||
private void DisposeInternal()
|
||||
@@ -590,6 +596,9 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
base.Unloading -= OnUnload;
|
||||
this._dependencyResolvers.Clear();
|
||||
this._loadedAssemblyData.Clear();
|
||||
|
||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true);
|
||||
GC.WaitForFullGCComplete(10);
|
||||
}
|
||||
|
||||
protected override Assembly Load(AssemblyName assemblyName)
|
||||
@@ -658,6 +667,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
public readonly ImmutableArray<Type> Types;
|
||||
public readonly ImmutableDictionary<string, Type> TypesByName;
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public AssemblyData(Assembly assembly, byte[] assemblyImage)
|
||||
{
|
||||
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
|
||||
@@ -667,6 +677,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
TypesByName = Types.ToImmutableDictionary(type => type.FullName, type => type);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public AssemblyData(Assembly assembly, string path)
|
||||
{
|
||||
Assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
|
||||
@@ -694,6 +705,7 @@ public sealed class AssemblyLoader : AssemblyLoadContext, IAssemblyLoaderService
|
||||
HashCode = AssemblyName.GetHashCode();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public AssemblyOrStringKey(string assemblyName)
|
||||
{
|
||||
if (assemblyName.IsNullOrWhiteSpace())
|
||||
|
||||
+2
-2
@@ -396,7 +396,7 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService,
|
||||
typeof(ISettingList<ulong>),
|
||||
typeof(ISettingList<long>),
|
||||
typeof(ISettingList<float>),
|
||||
typeof(ISettingList<double>),
|
||||
typeof(ISettingList<double>)
|
||||
];
|
||||
|
||||
Dictionary<string, Dictionary<string, object>> settingsTable = [];
|
||||
@@ -420,9 +420,9 @@ class LuaScriptManagementService : ILuaScriptManagementService, ILuaDataService,
|
||||
_script.Globals[keyPair.Key] = keyPair.Value;
|
||||
}
|
||||
|
||||
UserData.RegisterType(typeof(ISettingRangeBase<int>));
|
||||
#if CLIENT
|
||||
UserData.RegisterType(typeof(ISettingControl));
|
||||
_script.Globals["SettingControl"] = UserData.CreateStatic(typeof(ISettingControl));
|
||||
#endif
|
||||
|
||||
new LuaConverters(this).RegisterLuaConverters();
|
||||
|
||||
@@ -43,7 +43,9 @@ internal class MainMenuPatch : ISystem, IEventScreenSelected
|
||||
{
|
||||
if (mainMenuUIAdded) { return; }
|
||||
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Point(300, 30), screen.Frame.RectTransform, Anchor.TopLeft) { AbsoluteOffset = new Point(10, 10) }, "", Color.Red)
|
||||
var textBlock = new GUITextBlock(
|
||||
new RectTransform(new Point(300, 30), screen.Frame.RectTransform, Anchor.TopLeft) { AbsoluteOffset = new Point(10, 10) },
|
||||
"", Color.Red, textAlignment: Alignment.TopLeft)
|
||||
{
|
||||
IgnoreLayoutGroups = false
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed partial class ModConfigFileParserService :
|
||||
public ModConfigFileParserService(IStorageService storageService)
|
||||
{
|
||||
_storageService = storageService;
|
||||
_storageService.UseCaching = false;
|
||||
}
|
||||
|
||||
#region Dispose
|
||||
|
||||
@@ -45,6 +45,7 @@ public sealed class ModConfigService : IModConfigService
|
||||
#if CLIENT
|
||||
_stylesParserService = stylesParserService;
|
||||
#endif
|
||||
_storageService.UseCaching = false;
|
||||
}
|
||||
|
||||
#region Dispose
|
||||
|
||||
+4
-2
@@ -194,7 +194,7 @@ public sealed class PackageManagementService : IPackageManagementService
|
||||
|
||||
IService.CheckDisposed(this);
|
||||
var result = new FluentResults.Result();
|
||||
var packages2 = packages.OrderBy(pkg => pkg.Name == "LuaCsForBarotrauma" ? 0 : 1) // always run lua cs first.
|
||||
var packages2 = packages.OrderBy(pkg => pkg.Name == LuaCsSetup.PackageName ? 0 : 1) // always run lua cs first.
|
||||
.ThenBy(packages.IndexOf)
|
||||
.ToImmutableArray();
|
||||
|
||||
@@ -318,7 +318,7 @@ public sealed class PackageManagementService : IPackageManagementService
|
||||
|
||||
// get loading order. Note: packages not in the execution order list will load first.
|
||||
var loadingOrderedPackages = _loadedPackages
|
||||
.OrderBy(pkg => pkg.Key.Name == "LuaCsForBarotrauma" ? 0 : 1) // always run lua cs first.
|
||||
.OrderBy(pkg => pkg.Key.Name == LuaCsSetup.PackageName ? 0 : 1) // always run lua cs first.
|
||||
.ThenBy(pkg => executionOrder.IndexOf(pkg.Key))
|
||||
.ToImmutableArray();
|
||||
var loadOrderByPackage = loadingOrderedPackages.Select(p => p.Key).ToImmutableArray();
|
||||
@@ -415,7 +415,9 @@ public sealed class PackageManagementService : IPackageManagementService
|
||||
|
||||
if (_loadedPackages.IsEmpty || _runningPackages.IsEmpty)
|
||||
{
|
||||
#if DEGUG
|
||||
_logger.LogWarning($"{nameof(StopRunningPackages)}: No packages are currently executing.");
|
||||
#endif
|
||||
return FluentResults.Result.Ok();
|
||||
}
|
||||
|
||||
|
||||
+167
-72
@@ -10,6 +10,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
@@ -88,7 +89,15 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
|
||||
private ImmutableArray<MetadataReference> _baseMetadataReferences = ImmutableArray<MetadataReference>.Empty;
|
||||
private ImmutableArray<MetadataReference> _baseMetadataReferencesNonPublicized = ImmutableArray<MetadataReference>.Empty;
|
||||
|
||||
private Thread _backgroundGCCleanupThread = null;
|
||||
private long _backgroundGCWatchdogTicks = 0;
|
||||
|
||||
private static readonly int
|
||||
GC_TASK_COMPLETION_TIMEOUT = 5000,
|
||||
GC_BACKGND_MAXITERATIONS = 2,
|
||||
GC_BACKGND_INTERVAL_MILLIS = 200,
|
||||
GC_BACKGND_GENERATION_WAIT_MILLIS = 100;
|
||||
|
||||
private IEnumerable<MetadataReference> BaseMetadataReferences
|
||||
{
|
||||
@@ -174,6 +183,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
_pluginInjectorContainer?.Dispose();
|
||||
_pluginInjectorContainer = null;
|
||||
|
||||
ReflectionUtils.ResetCache();
|
||||
foreach (var loader in _assemblyLoaders)
|
||||
{
|
||||
try
|
||||
@@ -184,14 +194,6 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger?.LogError($"Failed to dispose of {nameof(IAssemblyLoaderService)} for ContentPackage {loader.Key.Name}: \n{e.Message}");
|
||||
if (loader.Value.Assemblies.Any())
|
||||
{
|
||||
foreach (var ass in loader.Value.Assemblies)
|
||||
{
|
||||
_logger?.LogWarning($"{nameof(PluginManagementService)}: Fallback manual unsubscription of assemblies: {ass.GetName()}");
|
||||
ReflectionUtils.RemoveAssemblyFromCache(ass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_assemblyLoaders.Clear();
|
||||
@@ -222,6 +224,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
private IEventService _pluginEventService;
|
||||
private Lazy<ILuaPatcher> _pluginLuaPatcherService;
|
||||
private Func<IConsoleCommandsService> _consoleCommandServiceFactory;
|
||||
private readonly IConsoleCommandsService _internalConsoleCommandsService;
|
||||
private ILuaCsInfoProvider _luaCsInfoProvider;
|
||||
private readonly ConcurrentDictionary<ContentPackage, IAssemblyLoaderService> _assemblyLoaders = new();
|
||||
private readonly ConcurrentDictionary<Type, ContentPackage> _pluginPackageLookup = new();
|
||||
@@ -251,6 +254,21 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
_pluginLuaPatcherService = pluginLuaPatcherService;
|
||||
_consoleCommandServiceFactory = consoleCommandServiceFactory;
|
||||
_luaCsInfoProvider = luaCsInfoProvider;
|
||||
_internalConsoleCommandsService = consoleCommandServiceFactory.Invoke();
|
||||
|
||||
RegisterCommands(_internalConsoleCommandsService);
|
||||
}
|
||||
|
||||
private void RegisterCommands(IConsoleCommandsService cmdService)
|
||||
{
|
||||
cmdService.RegisterCommand("plugin_forcerungc", "Forces the GC to run", cmds =>
|
||||
{
|
||||
_logger.LogMessage("Forcing GC run.");
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
await RunGC(true, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private ServiceContainer CreatePluginServiceContainer()
|
||||
@@ -317,11 +335,13 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public bool TryGetPackageForPlugin<TPlugin>(out ContentPackage ownerPackage)
|
||||
{
|
||||
return _pluginPackageLookup.TryGetValue(typeof(TPlugin), out ownerPackage);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public Type GetType(string typeName, bool isByRefType = false, bool includeInterfaces = false,
|
||||
bool includeDefaultContext = true)
|
||||
{
|
||||
@@ -370,6 +390,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public FluentResults.Result ActivatePluginInstances(ImmutableArray<ContentPackage> executionOrder, bool excludeAlreadyRunningPackages = true)
|
||||
{
|
||||
if (executionOrder.IsDefaultOrEmpty)
|
||||
@@ -488,6 +509,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
return results;
|
||||
|
||||
// helper
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
FluentResults.Result PluginInitRunner(IAssemblyPlugin plugin, Action<IAssemblyPlugin> action)
|
||||
{
|
||||
try
|
||||
@@ -502,7 +524,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public FluentResults.Result LoadAssemblyResources(ImmutableArray<IAssemblyResourceInfo> resources)
|
||||
{
|
||||
if (resources.IsDefaultOrEmpty)
|
||||
@@ -705,7 +727,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
{
|
||||
builder.AddRange(BaseMetadataReferencesWithBarotrauma);
|
||||
foreach (var loaderService in _assemblyLoaders
|
||||
.Where(asl => !asl.Key.Name.Equals("LuaCsForBarotrauma", StringComparison.InvariantCultureIgnoreCase))
|
||||
.Where(asl => !asl.Key.Name.Equals(LuaCsSetup.PackageName, StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToImmutableArray())
|
||||
{
|
||||
builder.AddRange(loaderService.Value.AssemblyReferences.Where(ar => ar is not null));
|
||||
@@ -732,7 +754,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
.Replace(" Barotrauma.Networking.Client.ClientList", " ModUtils.Client.ClientList")
|
||||
.Replace("ItemPrefab.GetItemPrefab", "ModUtils.ItemPrefab.GetItemPrefab");
|
||||
}
|
||||
|
||||
|
||||
private IntPtr OnAssemblyLoaderResolvingUnmanaged(Assembly callerAssembly, string targetAssemblyName)
|
||||
{
|
||||
Guard.IsNull(callerAssembly, nameof(callerAssembly));
|
||||
@@ -805,21 +827,58 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
{
|
||||
_eventService?.Value?.PublishEvent<IEventAssemblyUnloading>(sub => sub.OnAssemblyUnloading(assembly));
|
||||
}
|
||||
|
||||
_unloadingAssemblyLoaders.Add(loader, loader.OwnerPackage);
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||
public FluentResults.Result UnloadManagedAssemblies()
|
||||
{
|
||||
using var lck = _operationsLock.AcquireWriterLock().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
IService.CheckDisposed(this);
|
||||
|
||||
if (_assemblyLoaders.Count == 0)
|
||||
{
|
||||
return FluentResults.Result.Ok();
|
||||
}
|
||||
|
||||
var results = new FluentResults.Result();
|
||||
|
||||
results.WithReasons(UnsafeDisposeManagedTypeInstances().Reasons);
|
||||
if (!_pluginInstances.IsEmpty)
|
||||
{
|
||||
foreach (var instance in _pluginInstances.SelectMany(kvp => kvp.Value))
|
||||
{
|
||||
try
|
||||
{
|
||||
instance.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
results.WithError(new ExceptionalError(e));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_pluginInstances.Clear();
|
||||
}
|
||||
|
||||
if (_pluginEventService is not null)
|
||||
{
|
||||
_eventService.Value.RemoveDispatcherEventService(_pluginEventService);
|
||||
try
|
||||
{
|
||||
_pluginEventService.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
results.WithError(new ExceptionalError(e));
|
||||
}
|
||||
_pluginEventService = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_pluginInjectorContainer?.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
results.WithError(new ExceptionalError(e));
|
||||
}
|
||||
_pluginInjectorContainer = null;
|
||||
|
||||
ReflectionUtils.ResetCache();
|
||||
foreach (var loaderService in _assemblyLoaders)
|
||||
@@ -827,7 +886,6 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
try
|
||||
{
|
||||
loaderService.Value.Dispose();
|
||||
_unloadingAssemblyLoaders.Add(loaderService.Value, loaderService.Key);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -837,38 +895,7 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
|
||||
_assemblyLoaders.Clear();
|
||||
_storageService.PurgeCache();
|
||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true);
|
||||
|
||||
#if DEBUG
|
||||
// Print still loaded assembly load ctx after giving some time
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
if (!_unloadingAssemblyLoaders.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine("The following ContentPackages have not unloaded their assemblies:");
|
||||
|
||||
foreach (var kvp in _unloadingAssemblyLoaders.ToImmutableArray())
|
||||
{
|
||||
sb.AppendLine($"- '{kvp.Value.Name}'");
|
||||
}
|
||||
|
||||
|
||||
// Use DebugConsole in case logger is null by the time this executes.
|
||||
if (_logger is null)
|
||||
{
|
||||
DebugConsole.LogError(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning(sb.ToString());
|
||||
}
|
||||
}, 3.0f);
|
||||
#endif
|
||||
_pluginPackageLookup.Clear();
|
||||
|
||||
// clear native libraries
|
||||
if (_loadedNativeLibraries.Any())
|
||||
@@ -888,41 +915,109 @@ public class PluginManagementService : IAssemblyManagementService
|
||||
|
||||
_loadedNativeLibraries.Clear();
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
await RunGC(true, false);
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private FluentResults.Result UnsafeDisposeManagedTypeInstances()
|
||||
private void SafeLogUnloadingPackages()
|
||||
{
|
||||
var results = new FluentResults.Result();
|
||||
|
||||
if (!_pluginInstances.IsEmpty)
|
||||
if (!_unloadingAssemblyLoaders.Any())
|
||||
{
|
||||
foreach (var instance in _pluginInstances.SelectMany(kvp => kvp.Value))
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine("The following ContentPackages have not unloaded their assemblies:");
|
||||
|
||||
foreach (var kvp in _unloadingAssemblyLoaders.ToImmutableArray())
|
||||
{
|
||||
sb.AppendLine($"- '{kvp.Value.Name}'");
|
||||
}
|
||||
|
||||
// Use DebugConsole in case logger is null by the time this executes.
|
||||
if (_logger is null)
|
||||
{
|
||||
DebugConsole.Log(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void GCCleanupTask(TaskCompletionSource<bool> completionSuccess)
|
||||
{
|
||||
GC.RegisterForFullGCNotification(1, 1);
|
||||
try
|
||||
{
|
||||
for (int iter = 0; iter < GC_BACKGND_MAXITERATIONS; iter++)
|
||||
{
|
||||
try
|
||||
int maxGen = GC.MaxGeneration;
|
||||
for (int currGen = 0; currGen < maxGen; currGen++)
|
||||
{
|
||||
instance.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
results.WithError(new ExceptionalError(e));
|
||||
continue;
|
||||
GC.Collect(currGen, GCCollectionMode.Forced, false, false); // marking pass
|
||||
GC.WaitForFullGCComplete(GC_BACKGND_GENERATION_WAIT_MILLIS);
|
||||
GC.Collect(currGen); // generation cleanup
|
||||
}
|
||||
Thread.Sleep(GC_BACKGND_INTERVAL_MILLIS);
|
||||
}
|
||||
completionSuccess.SetResult(true);
|
||||
}
|
||||
|
||||
if (_pluginEventService is not null)
|
||||
catch (ThreadInterruptedException tie)
|
||||
{
|
||||
_eventService.Value.RemoveDispatcherEventService(_pluginEventService);
|
||||
_pluginEventService = null;
|
||||
completionSuccess.SetResult(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
completionSuccess.SetException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.CancelFullGCNotification();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunGC(bool logResults, bool runOnMainThread)
|
||||
{
|
||||
var gcCompletionSuccess = new TaskCompletionSource<bool>();
|
||||
if (runOnMainThread)
|
||||
{
|
||||
GCCleanupTask(gcCompletionSuccess);
|
||||
if (logResults)
|
||||
{
|
||||
SafeLogUnloadingPackages();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
_pluginInjectorContainer = null;
|
||||
|
||||
_pluginInstances.Clear();
|
||||
_pluginPackageLookup.Clear();
|
||||
|
||||
return results;
|
||||
var gcThread = new Thread(() =>
|
||||
{
|
||||
GCCleanupTask(gcCompletionSuccess);
|
||||
}) { IsBackground = true };
|
||||
gcThread.Start();
|
||||
|
||||
try
|
||||
{
|
||||
await gcCompletionSuccess.Task.WaitAsync(TimeSpan.FromMilliseconds(GC_TASK_COMPLETION_TIMEOUT));
|
||||
}
|
||||
catch (TimeoutException te)
|
||||
{
|
||||
_logger.LogError($"{nameof(RunGC)}: The GC task thread has timed out.");
|
||||
gcThread.Interrupt();
|
||||
gcThread.Join();
|
||||
}
|
||||
|
||||
if (logResults)
|
||||
{
|
||||
SafeLogUnloadingPackages();
|
||||
}
|
||||
}
|
||||
|
||||
public Result<Assembly> GetLoadedAssembly(OneOf<AssemblyName, string> assemblyName, in Guid[] excludedContexts)
|
||||
|
||||
Reference in New Issue
Block a user