From 316739c624d97171a0891b8907dc7b39aac8cde8 Mon Sep 17 00:00:00 2001 From: gnembon Date: Tue, 14 Jan 2020 14:23:33 -0400 Subject: [PATCH] added synchronization and thread shutdown procedures. --- .../java/carpet/script/CarpetScriptHost.java | 8 ++--- .../carpet/script/CarpetScriptServer.java | 8 +++-- src/main/java/carpet/script/Expression.java | 21 ++++++++++++ .../java/carpet/script/value/ThreadValue.java | 32 +++++++++++++++++++ 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index fe54ef7a..fb307910 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -267,10 +267,6 @@ public class CarpetScriptHost extends ScriptHost @Override public void onClose() { - super.onClose(); - if (this.saveTimeout > 0) - dumpState(); - FunctionValue closing = getFunction("__on_close"); if (closing != null) { @@ -307,7 +303,9 @@ public class CarpetScriptHost extends ScriptHost e.remove(); } } - + if (this.saveTimeout > 0) + dumpState(); + super.onClose(); } private void dumpState() diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index 0364945e..34c206c4 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -1,14 +1,15 @@ package carpet.script; import carpet.script.bundled.BundledModule; -import carpet.script.value.FunctionValue; -import carpet.script.value.MapValue; -import carpet.script.value.StringValue; import carpet.CarpetSettings; import carpet.CarpetServer; import carpet.script.bundled.FileModule; import carpet.script.bundled.Module; import carpet.script.exception.InvalidCallbackException; +import carpet.script.value.FunctionValue; +import carpet.script.value.MapValue; +import carpet.script.value.StringValue; +import carpet.script.value.ThreadValue; import carpet.script.value.Value; import carpet.utils.Messenger; import com.mojang.brigadier.arguments.StringArgumentType; @@ -299,5 +300,6 @@ public class CarpetScriptServer { host.onClose(); } + ThreadValue.shutdown(); } } diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index b6be4cbf..eeed2959 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -2681,6 +2681,10 @@ public class Expression *

task_completed(task)

*

Returns true if task has completed, or false otherwise.

* + *

synchronize(lock, expression)

+ *

Evaluates expression synchronized with respect to the lock lock. Returns the value of the + * expression.

+ * *
*

Auxiliary functions

* @@ -3118,6 +3122,23 @@ public class Expression return new NumericValue(((ThreadValue) v).isFinished()); }); + addLazyFunction("synchronize", -1, (c, t, lv) -> + { + if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize"); + Value lockValue = Value.NULL; + int ind = 0; + if (lv.size() == 2) + { + lockValue = lv.get(0).evalValue(c); + ind = 1; + } + synchronized (ThreadValue.getLock(lockValue)) + { + Value ret = lv.get(ind).evalValue(c, t); + return (_c, _t) -> ret; + } + }); + addLazyFunction("system_variable_get", -1, (c, t, lv) -> { if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched"); diff --git a/src/main/java/carpet/script/value/ThreadValue.java b/src/main/java/carpet/script/value/ThreadValue.java index 42682197..6d3998f6 100644 --- a/src/main/java/carpet/script/value/ThreadValue.java +++ b/src/main/java/carpet/script/value/ThreadValue.java @@ -10,9 +10,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; public class ThreadValue extends Value { @@ -20,6 +23,7 @@ public class ThreadValue extends Value private long id; private static long sequence = 0L; private static final Map executorServices = new HashMap<>(); + private static final Map locks = new ConcurrentHashMap<>(); public ThreadValue(Value pool, FunctionValue function, Expression expr, Tokenizer.Token token, Context ctx, List args) { @@ -100,4 +104,32 @@ public class ThreadValue extends Value } return 0; } + + public static Object getLock(Value name) + { + return locks.computeIfAbsent(name, (n) -> new Object()); + } + + + public static void shutdown() + { + for (ExecutorService exec : executorServices.values()) + { + exec.shutdown(); + try + { + exec.awaitTermination(5000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException ignored) + { + } + finally + { + exec.shutdownNow(); + } + } + executorServices.clear(); + locks.clear(); + } + }