aboutsummaryrefslogtreecommitdiff
path: root/lib/Plugins.Runtime/src/PluginController.cs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Plugins.Runtime/src/PluginController.cs')
-rw-r--r--lib/Plugins.Runtime/src/PluginController.cs89
1 files changed, 60 insertions, 29 deletions
diff --git a/lib/Plugins.Runtime/src/PluginController.cs b/lib/Plugins.Runtime/src/PluginController.cs
index 14ea7f0..f602492 100644
--- a/lib/Plugins.Runtime/src/PluginController.cs
+++ b/lib/Plugins.Runtime/src/PluginController.cs
@@ -25,6 +25,7 @@
using System;
using System.Linq;
using System.Text.Json;
+using System.Threading;
using System.Reflection;
using System.Collections.Generic;
@@ -38,6 +39,18 @@ namespace VNLib.Plugins.Runtime
/// </summary>
public sealed class PluginController : IPluginEventRegistrar
{
+ /*
+ * Lock must be held any time the internals lists are read/written
+ * to avoid read/write enumeration issues.
+ *
+ * This can happen when a manual unload is called duiring an automatic
+ * reload, or a runtime is tearing down the plugin environment
+ * when an automatic reload is happening.
+ *
+ * This also allows thread safe register/unregister event listeners
+ */
+ private readonly object _stateLock = new();
+
private readonly List<LivePlugin> _plugins;
private readonly List<KeyValuePair<IPluginEventListener, object?>> _listeners;
@@ -58,61 +71,80 @@ namespace VNLib.Plugins.Runtime
{
_ = listener ?? throw new ArgumentNullException(nameof(listener));
- _listeners.Add(new(listener, state));
+ lock (_stateLock)
+ {
+ _listeners.Add(new(listener, state));
+ }
}
///<inheritdoc/>
public bool Unregister(IPluginEventListener listener)
{
- //Remove listener
- return _listeners.RemoveAll(p => p.Key == listener) > 0;
+ lock(_stateLock)
+ {
+ //Remove listener
+ return _listeners.RemoveAll(p => p.Key == listener) > 0;
+ }
}
internal void InitializePlugins(Assembly asm)
{
- //get all Iplugin types
- Type[] types = asm.GetTypes().Where(static type => !type.IsAbstract && typeof(IPlugin).IsAssignableFrom(type)).ToArray();
+ lock (_stateLock)
+ {
+ //get all Iplugin types
+ Type[] types = asm.GetTypes().Where(static type => !type.IsAbstract && typeof(IPlugin).IsAssignableFrom(type)).ToArray();
- //Initialize the new plugin instances
- IPlugin[] plugins = types.Select(static t => (IPlugin)Activator.CreateInstance(t)!).ToArray();
+ //Initialize the new plugin instances
+ IPlugin[] plugins = types.Select(static t => (IPlugin)Activator.CreateInstance(t)!).ToArray();
- //Crate new containers
- LivePlugin[] lps = plugins.Select(p => new LivePlugin(p, asm)).ToArray();
+ //Crate new containers
+ LivePlugin[] lps = plugins.Select(p => new LivePlugin(p, asm)).ToArray();
- //Store containers
- _plugins.AddRange(lps);
+ //Store containers
+ _plugins.AddRange(lps);
+ }
}
internal void ConfigurePlugins(JsonDocument hostDom, JsonDocument pluginDom, string[] cliArgs)
{
- _plugins.TryForeach(lp => lp.InitConfig(hostDom, pluginDom));
- _plugins.TryForeach(lp => lp.InitLog(cliArgs));
+ lock (_stateLock)
+ {
+ _plugins.TryForeach(lp => lp.InitConfig(hostDom, pluginDom));
+ _plugins.TryForeach(lp => lp.InitLog(cliArgs));
+ }
}
internal void LoadPlugins()
{
- //Load all plugins
- _plugins.TryForeach(static p => p.LoadPlugin());
+ lock( _stateLock)
+ {
+ //Load all plugins
+ _plugins.TryForeach(static p => p.LoadPlugin());
- //Notify event handlers
- _listeners.TryForeach(l => l.Key.OnPluginLoaded(this, l.Value));
+ //Notify event handlers
+ _listeners.TryForeach(l => l.Key.OnPluginLoaded(this, l.Value));
+ }
}
internal void UnloadPlugins()
{
- try
- {
- //Notify event handlers
- _listeners.TryForeach(l => l.Key.OnPluginUnloaded(this, l.Value));
-
- //Unload plugin instances
- _plugins.TryForeach(static p => p.UnloadPlugin());
- }
- finally
+ lock (_stateLock)
{
- //Always
- _plugins.Clear();
+ try
+ {
+ //Notify event handlers
+ _listeners.TryForeach(l => l.Key.OnPluginUnloaded(this, l.Value));
+
+ //Unload plugin instances
+ _plugins.TryForeach(static p => p.UnloadPlugin());
+ }
+ finally
+ {
+ //Always
+ _plugins.Clear();
+
+ }
}
}
@@ -121,7 +153,6 @@ namespace VNLib.Plugins.Runtime
_plugins.Clear();
_listeners.Clear();
}
-
}
}