From 57a3fba8a55621266be1d51361540b6f4ac4965e Mon Sep 17 00:00:00 2001 From: Gert Goet Date: Thu, 16 Jan 2025 19:04:43 +0100 Subject: [PATCH 1/3] Clojure 1.12.0 --- src/eval/deps_try.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval/deps_try.clj b/src/eval/deps_try.clj index 12d8458..9114237 100644 --- a/src/eval/deps_try.clj +++ b/src/eval/deps_try.clj @@ -103,7 +103,7 @@ (let [paths (into ["."] ;; needed for clojure.java.io/resource (string/split init-cp #":")) deps (merge - {'org.clojure/clojure {:mvn/version "1.12.0-alpha11"}} + {'org.clojure/clojure {:mvn/version "1.12.0"}} recipe-deps requested-deps) main-args (cond-> ["--version" version] From 4e407febff36a9f44d173c6ed5857d25c889818c Mon Sep 17 00:00:00 2001 From: Gert Goet Date: Thu, 16 Jan 2025 21:58:48 +0100 Subject: [PATCH 2/3] Handle breaks for Java > 19 --- .github/workflows/release.yml | 12 ++++-- .gitignore | 1 + bb.edn | 6 ++- deps.edn | 6 +-- java/dt/JvmtiAgent.java | 24 ++++++++++++ libdt/Makefile | 49 +++++++++++++++++++++++++ libdt/build/libdt-linux-arm64.so | Bin 0 -> 70096 bytes libdt/build/libdt-linux-x64.so | Bin 0 -> 15800 bytes libdt/build/libdt-macos-universal.so | Bin 0 -> 115664 bytes libdt/src/dt_agent.c | 46 +++++++++++++++++++++++ src/eval/deps_try.clj | 7 +++- src/eval/deps_try/try.clj | 17 +++++++-- src/eval/deps_try/util.clj | 13 +++++++ src/eval/deps_try/util/jvmti.clj | 53 +++++++++++++++++++++++++++ 14 files changed, 221 insertions(+), 13 deletions(-) create mode 100644 java/dt/JvmtiAgent.java create mode 100644 libdt/Makefile create mode 100755 libdt/build/libdt-linux-arm64.so create mode 100755 libdt/build/libdt-linux-x64.so create mode 100755 libdt/build/libdt-macos-universal.so create mode 100644 libdt/src/dt_agent.c create mode 100644 src/eval/deps_try/util/jvmti.clj diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e5fb107..191abb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ on: push: branches: - master - - feature/dockerfile + - fix/break-handling jobs: Config: @@ -67,14 +67,20 @@ jobs: bb: latest - name: Update VERSION run: echo "${{ needs.Config.outputs.version }}" > resources/VERSION + - name: Compile Java + run: bb java:compile - name: Zip it run: zip -r deps-try.zip . -x ".git/*" - name: Build uberjar run: | - rm -rf .git + # remove stuff not wanted in JAR + rm -rf .git .github mv deps-try.zip .. - bb uberjar deps-try-bb.jar -m eval.deps-try + + bb bb:uberjar + ls -lah deps-try-bb.jar jar -tf deps-try-bb.jar + mv ../deps-try.zip . - name: Testrun uberjar run: bb deps-try-bb.jar -h diff --git a/.gitignore b/.gitignore index d99d61a..eaae4ad 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /.clj-kondo .lsp /VERSION +*.class diff --git a/bb.edn b/bb.edn index 18eca27..4b0ef68 100644 --- a/bb.edn +++ b/bb.edn @@ -1,7 +1,11 @@ {:deps {io.github.eval/deps-try {:local/root "."}} :bbin/bin {deps-try {:main-opts ["-m" "eval.deps-try"]}} :tasks - {gen-manifest {:doc "Generate recipe-manifest and print to stdout" + {java:compile {:doc "Compile files under java/" + :task (shell {:dir "java"} "javac --release 11 dt/JvmtiAgent.java")} + bb:uberjar {:doc "Create the app's uberjar" + :task (shell "bb uberjar deps-try-bb.jar -m eval.deps-try")} + gen-manifest {:doc "Generate recipe-manifest and print to stdout" :requires ([babashka.fs :as fs]) :task (exec 'eval.deps-try.recipe/generate&print-manifest {:exec-args diff --git a/deps.edn b/deps.edn index c2e3b84..011d2db 100644 --- a/deps.edn +++ b/deps.edn @@ -1,11 +1,11 @@ -{:paths ["src" "resources" "."] +{:paths ["src" "resources" "." "java" "libdt/build"] :deps {borkdude/edamame {:mvn/version "1.4.24"} - cider/orchard {:mvn/version "0.22.0"} + cider/orchard {:mvn/version "0.30.0"} com.bhauman/rebel-readline {:local/root "./vendor/rebel-readline/rebel-readline"} deps-try/cli {:local/root "./vendor/deps-try.cli"} deps-try/http-client {:local/root "./vendor/deps-try.http-client"} io.github.eval/compliment {:git/sha "cd9706db27d456e8940dcd1118174c94effa9358"} - org.clojure/clojure {:mvn/version "1.12.0-alpha11"} + org.clojure/clojure {:mvn/version "1.12.0"} org.clojure/tools.gitlibs {:mvn/version "2.5.197"} ;; suppress logging org.slf4j/slf4j-nop {:mvn/version "2.0.5"}} diff --git a/java/dt/JvmtiAgent.java b/java/dt/JvmtiAgent.java new file mode 100644 index 0000000..5c026ce --- /dev/null +++ b/java/dt/JvmtiAgent.java @@ -0,0 +1,24 @@ +package dt; + +/** + * Java facade for the C side of the libnrepl JVMTI agent. Currently used to + * stop threads on JDK20+. + */ +public class JvmtiAgent { + + // This will bind to Java_nrepl_JvmtiAgent_stopThread function once the + // agent containing this function will be attached. + public static native void stopThread(Thread thread, Throwable throwable); + + /** + * Forcibly stop a given thread. + */ + public static void stopThread(Thread thread) { + // ThreadDeath is deprecated, but so it Thread.stop(). We can revisit + // this when JVM actually decides to remove this class. + @SuppressWarnings("deprecation") + Throwable throwable = new ThreadDeath(); + throwable.setStackTrace(new StackTraceElement[0]); + stopThread(thread, throwable); + } +} diff --git a/libdt/Makefile b/libdt/Makefile new file mode 100644 index 0000000..528fe3e --- /dev/null +++ b/libdt/Makefile @@ -0,0 +1,49 @@ +LIB=libdt-$(OS)-$(ARCH).so +CXXFLAGS=-O3 -fno-exceptions -fvisibility=hidden +INCLUDES=-I$(JAVA_HOME)/include +LIBS=-ldl +SOURCES := $(wildcard src/*.c) + +ifeq ($(JAVA_HOME),) + export JAVA_HOME:=$(shell java -cp . JavaHome) +endif + +ARCH:=$(shell uname -m) +ifeq ($(ARCH),x86_64) + ARCH=x64 +else + ifeq ($(findstring arm,$(ARCH)),arm) + ifeq ($(findstring 64,$(ARCH)),64) + ARCH=arm64 + else + ARCH=arm32 + endif + else ifeq ($(findstring aarch64,$(ARCH)),aarch64) + ARCH=arm64 + else + ARCH=x86 + endif +endif + +OS:=$(shell uname -s) +ifeq ($(OS),Darwin) + CXXFLAGS += -arch x86_64 -arch arm64 -mmacos-version-min=10.12 + INCLUDES += -I$(JAVA_HOME)/include/darwin + OS=macos + ARCH=universal +else + CXXFLAGS += -Wl,-z,defs + LIBS += -lrt + INCLUDES += -I$(JAVA_HOME)/include/linux + OS=linux + CC=gcc +endif + +all: build/$(LIB) + +clean: + $(RM) -r build + +build/$(LIB): $(SOURCES) + mkdir -p build + $(CC) $(CXXFLAGS) $(INCLUDES) -fPIC -shared -o $@ $(SOURCES) $(LIBS) diff --git a/libdt/build/libdt-linux-arm64.so b/libdt/build/libdt-linux-arm64.so new file mode 100755 index 0000000000000000000000000000000000000000..a1fd9f935cf0e803f7af0e59509e151673a7ba6e GIT binary patch literal 70096 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 F{{;$0KivQT literal 0 HcmV?d00001 diff --git a/libdt/build/libdt-linux-x64.so b/libdt/build/libdt-linux-x64.so new file mode 100755 index 0000000000000000000000000000000000000000..c9370f16b2c6fe1c731d47051d720b079e4e2df7 GIT binary patch literal 15800 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 literal 0 HcmV?d00001 diff --git a/libdt/build/libdt-macos-universal.so b/libdt/build/libdt-macos-universal.so new file mode 100755 index 0000000000000000000000000000000000000000..ef78fc3602304a63604b687ea0b5c555daf7a453 GIT binary patch literal 115664 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 +#include + +static jvmtiEnv* jvmti_env; + +// https://docs.oracle.com/en/java/javase/21/docs/specs/jvmti.html#StopThread +JNIEXPORT void JNICALL Java_dt_JvmtiAgent_stopThread +(JNIEnv* env, jclass cls, jthread thread, jobject throwable) { + jvmtiError err; + jvmtiThreadInfo threadInfo; + + err = (*jvmti_env)->GetThreadInfo(jvmti_env, thread, &threadInfo); + if (err != JVMTI_ERROR_NONE) { + printf("Error getting thread info: %d\n", err); + return; + } + + //printf("Stopping thread \"%s\" using JVMTI...\n", threadInfo.name); + + err = (*jvmti_env)->StopThread(jvmti_env, thread, throwable); + if (err != JVMTI_ERROR_NONE) { + printf("Error stopping thread: %d\n", err); + return; + } +} + +JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* _) { + //printf("nREPL native agent loaded\n"); + + // Initialize JVMTI environment. + jint res = (*vm)->GetEnv(vm, (void**)&jvmti_env, JVMTI_VERSION_1_2); + if (res != JNI_OK) { + fprintf(stderr, "Failed to get JVMTI environment\n"); + return JNI_ERR; + } + + // Request capabilities for StopThread + jvmtiCapabilities capabilities = {0}; + capabilities.can_signal_thread = 1; + (*jvmti_env)->AddCapabilities(jvmti_env, &capabilities); + + return JNI_OK; +} diff --git a/src/eval/deps_try.clj b/src/eval/deps_try.clj index 9114237..e2d9869 100644 --- a/src/eval/deps_try.clj +++ b/src/eval/deps_try.clj @@ -111,8 +111,11 @@ ["--recipe-ns" recipe-location] ["--recipe" recipe-location])) prepare (conj "-P"))] - (apply run-repl "-Sdeps" (str {:paths paths - :deps deps}) + (apply run-repl + "-J-Djdk.attach.allowAttachSelf" + "-J-XX:+EnableDynamicAgentLoading" + "-Sdeps" (str {:paths paths + :deps deps}) "-M" "-m" "eval.deps-try.try" main-args))) (defn- recipe-manifest-contents [{:keys [refresh] :as _cli-opts}] diff --git a/src/eval/deps_try/try.clj b/src/eval/deps_try/try.clj index daf5535..f2d9e27 100644 --- a/src/eval/deps_try/try.clj +++ b/src/eval/deps_try/try.clj @@ -9,6 +9,7 @@ [eval.deps-try.history :as history] [eval.deps-try.recipe :as recipe] [eval.deps-try.rr-service :as rebel-service] + [eval.deps-try.util :as util] [rebel-readline.clojure.line-reader :as clj-line-reader] [rebel-readline.clojure.main :as rebel-main] [rebel-readline.commands :as rebel-readline] @@ -112,7 +113,11 @@ (defn- handle-sigint-form [] `(let [thread# (Thread/currentThread)] - (clj-repl/set-break-handler! (fn [_signal#] (.stop thread#))))) + (clj-repl/set-break-handler! + (fn [_signal#] + (if (<= util/java-version 19) + (.stop thread#) + ((requiring-resolve 'eval.deps-try.util.jvmti/stop-thread) thread#)))))) (defn- recipe-instructions [{:keys [ns-only]}] (str "Recipe" (when ns-only " namespace") " successfully loaded in the REPL-history. Press arrow-up to start with the first step.")) @@ -191,8 +196,12 @@ repl-opts (cond-> {:deps-try/version (:version opts) :deps-try/data-path data-path :caught (fn [ex] - (persist-just-caught ex) - (clojure.main/repl-caught ex)) + (let [break-handled? + (= 'java.lang.ThreadDeath + (get-in (Throwable->map ex) [:via 1 :type]))] + (when-not break-handled? + (persist-just-caught ex) + (clojure.main/repl-caught ex)))) :init (fn [] (load-slow-deps!) (apply require clojure.main/repl-requires) @@ -210,6 +219,6 @@ (comment - (recipe/parse "/Users/gert/projects/deps-try/deps-try-recipes/recipes/next-jdbc/postgresql.clj") + (recipe/parse "/Users/gert/projects/deps-try/deps-try/recipes/next_jdbc/postgresql.clj") #_:end) diff --git a/src/eval/deps_try/util.clj b/src/eval/deps_try/util.clj index d0745c4..e925857 100644 --- a/src/eval/deps_try/util.clj +++ b/src/eval/deps_try/util.clj @@ -4,6 +4,19 @@ [eval.deps-try.fs :as fs] [eval.deps-try.process :as p])) +(defn parse-java-version + "Parse Java version string according to JEP 223 and return version as a number." + [] + (try (let [s (System/getProperty "java.specification.version") + [major minor _] (string/split s #"\.") + major (Integer/parseInt major)] + (if (> major 1) + major + (Integer/parseInt minor))) + (catch Exception _ 8))) + +(def java-version "Current Java version number." (parse-java-version)) + (defn duration->millis [{:keys [seconds minutes hours days weeks] :or {seconds 0 minutes 0 hours 0 days 0 weeks 0}}] (let [days (+ days (* weeks 7)) diff --git a/src/eval/deps_try/util/jvmti.clj b/src/eval/deps_try/util/jvmti.clj new file mode 100644 index 0000000..ea00cb8 --- /dev/null +++ b/src/eval/deps_try/util/jvmti.clj @@ -0,0 +1,53 @@ +(ns eval.deps-try.util.jvmti + "This namespace contains code exclusive to JDK9+ and should not be attempted to + load with earlier JDKs." + (:require + [clojure.java.io :as io]) + (:import + (com.sun.tools.attach VirtualMachine) + (java.lang ProcessHandle) + (java.nio.file Files) + (java.nio.file.attribute FileAttribute) + (dt JvmtiAgent))) + +;;; Agent unpacking + +(defonce ^:private temp-directory + (.toFile (Files/createTempDirectory "deps_try" (into-array FileAttribute [])))) + +(defn- unpack-from-jar [resource-name] + (let [path (io/file temp-directory resource-name)] + (if-let [resource (io/resource resource-name)] + (io/copy (io/input-stream resource) path) + (throw (ex-info (str "Could not find " resource-name " in resources.") {}))) + (.getAbsolutePath path))) + +(defn- macos? [] + (re-find #"(?i)mac" (System/getProperty "os.name"))) + +(defn- aarch64? [] + (re-find #"(?i)aarch64" (System/getProperty "os.arch"))) + +(def ^:private libdt-path + (delay + (let [lib (cond (macos?) "libdt-macos-universal.so" + (aarch64?) "libdt-linux-arm64.so" + :else "libdt-linux-x64.so")] + (unpack-from-jar lib)))) + +;;; Agent loading + +(defn- attach-self ^VirtualMachine [] + (VirtualMachine/attach (str (.pid (ProcessHandle/current))))) + +(defn- load-libdt-agent [] + (.loadAgentPath (attach-self) @libdt-path)) + +(def ^:private agent-loaded (delay (load-libdt-agent))) + +(defn stop-thread + "Stop the given `thread` using JVMTI StopThread function. Risks state + corruption. Should not be used prior to JDK20." + [thread] + @agent-loaded + (JvmtiAgent/stopThread thread)) From 19df88efd088b49e729b29607b9c24fc5cedad6e Mon Sep 17 00:00:00 2001 From: Gert Goet Date: Fri, 3 Jul 2026 17:08:45 +0200 Subject: [PATCH 3/3] Remove warning on boot WARNING: Use of :paths external to the project has been deprecated... --- src/eval/deps_try.clj | 17 +++++++++++++++-- src/eval/deps_try/deps.cljc | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/eval/deps_try.clj b/src/eval/deps_try.clj index e2d9869..e609f84 100644 --- a/src/eval/deps_try.clj +++ b/src/eval/deps_try.clj @@ -100,10 +100,23 @@ ;; TODO re-enable? ;; see https://github.com/clojure/brew-install/blob/1.11.3/CHANGELOG.md #_(warn-unless-minimum-clojure-cli-version "1.11.1.1273" tdeps-version) - (let [paths (into ["."] ;; needed for clojure.java.io/resource - (string/split init-cp #":")) + (let [cp-parts (string/split init-cp #":") + ;; When running from the packaged uberjar, its path is external to the + ;; project and tools.deps deprecates such :paths entries, so it's added as + ;; a :local/root dep instead. In dev the classpath is the project's own + ;; source dirs and resolved deps, which belong in :paths as before. + ;; "." is kept for clojure.java.io/resource. + {jars true, dirs false} (if dev? + {false cp-parts} + (group-by #(string/ends-with? % ".jar") cp-parts)) + paths (into ["."] dirs) + self-deps (into {} (map-indexed (fn [i jar] + [(symbol "deps-try.self" (str "cp" i)) + {:local/root jar}]) + jars)) deps (merge {'org.clojure/clojure {:mvn/version "1.12.0"}} + self-deps recipe-deps requested-deps) main-args (cond-> ["--version" version] diff --git a/src/eval/deps_try/deps.cljc b/src/eval/deps_try/deps.cljc index ddd5eff..9eaa67b 100644 --- a/src/eval/deps_try/deps.cljc +++ b/src/eval/deps_try/deps.cljc @@ -370,6 +370,9 @@ (defn deps-available [] (->> (clojure.java.basis/current-basis) :libs + ;; synthetic deps used to put the packaged uberjar on the classpath + ;; (see eval.deps-try/start-repl!) shouldn't show as user libraries + (remove (comp #{"deps-try.self"} namespace key)) (filter (comp #(every? empty? %) :parents val))))) #?(:bb nil