From 406c43b0ec211f211877c4587eb90e44b3bccd55 Mon Sep 17 00:00:00 2001 From: P0nk Date: Thu, 20 May 2021 22:03:11 +0200 Subject: [PATCH] Make all event script invocations thread safe Simple solution for avoiding concurrent access of the same evaluated script, but I would be surprised if performance is not affected for the worse. The same Invocable is used for all instances of an event, so more active instances means higher contention of the single Invocable. Hopefully the number of instances required for it to be noticeably slow is high enough that this is not an issue. --- .../scripting/event/EventScriptManager.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/scripting/event/EventScriptManager.java b/src/main/java/scripting/event/EventScriptManager.java index 3197b5924a..18a13d454d 100644 --- a/src/main/java/scripting/event/EventScriptManager.java +++ b/src/main/java/scripting/event/EventScriptManager.java @@ -23,6 +23,7 @@ package scripting.event; import net.server.channel.Channel; import scripting.AbstractScriptManager; +import scripting.SynchronizedInvocable; import javax.script.Invocable; import javax.script.ScriptEngine; @@ -39,7 +40,7 @@ import java.util.logging.Logger; * @author Matze */ public class EventScriptManager extends AbstractScriptManager { - private static final String INJECTED_VARIABLE = "em"; + private static final String INJECTED_VARIABLE_NAME = "em"; private static EventEntry fallback; private final Map events = new ConcurrentHashMap<>(); private boolean active = false; @@ -57,11 +58,7 @@ public class EventScriptManager extends AbstractScriptManager { public EventScriptManager(final Channel channel, String[] scripts) { for (String script : scripts) { if (!script.isEmpty()) { - ScriptEngine engine = getInvocableScriptEngine("event/" + script + ".js"); - Invocable iv = (Invocable) engine; - EventManager eventManager = new EventManager(channel, iv, script); - engine.put(INJECTED_VARIABLE, eventManager); - events.put(script, new EventEntry(iv, eventManager)); + events.put(script, initializeEventEntry(script, channel)); } } @@ -100,17 +97,21 @@ public class EventScriptManager extends AbstractScriptManager { return; } - Channel cserv = eventEntries.iterator().next().getValue().em.getChannelServer(); + Channel channel = eventEntries.iterator().next().getValue().em.getChannelServer(); for (Entry entry : eventEntries) { String script = entry.getKey(); - ScriptEngine engine = getInvocableScriptEngine("event/" + script + ".js"); - Invocable iv = (Invocable) engine; - EventManager eventManager = new EventManager(cserv, iv, script); - engine.put(INJECTED_VARIABLE, eventManager); - events.put(script, new EventEntry(iv, eventManager)); + events.put(script, initializeEventEntry(script, channel)); } } + private EventEntry initializeEventEntry(String script, Channel channel) { + ScriptEngine engine = getInvocableScriptEngine("event/" + script + ".js"); + Invocable iv = SynchronizedInvocable.of((Invocable) engine); + EventManager eventManager = new EventManager(channel, iv, script); + engine.put(INJECTED_VARIABLE_NAME, eventManager); + return new EventEntry(iv, eventManager); + } + // Is never being called public void reload() { cancel();