-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Labels
Description
Describe the Issue
For a given Clojure program, the JVM waits but native-image exits on all OSes except linux + musl.
I believe it has something to do with non-daemon threads.
Using the latest version of GraalVM can resolve many issues.
- I tried with the latest version of GraalVM.
GraalVM Version
$ java -version
java version "26" 2026-03-17
Java(TM) SE Runtime Environment Oracle GraalVM 26-dev+11.1 (build 26+11-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 26-dev+11.1 (build 26+11-jvmci-b01, mixed mode, sharing)
Operating System and Version
all supported OSes
Troubleshooting Confirmation
- I tried the suggestions in the troubleshooting guide.
Run Command
./repro
Expected Behavior
I expect the native-image to behave in a similar way as the JVM and across OSes. In the case of this program, it should wait.
Actual Behavior
The native-image exits immediately except on musl.
Steps to Reproduce
Compile the below Clojure program to native-image. For ease of building I provide the uberjar. The native-image instructions are:
native-image -jar dude-1.0.0-standalone.jar --initialize-at-build-time=clojure,repro --verbose repro
(ns repro.repro
(:gen-class))
(defn- set-daemon-agent-executor
"Set Clojure's send-off agent executor (also affects futures). This is almost
an exact rewrite of the Clojure's executor, but the Threads are created as
daemons."
[]
(let [thread-counter (atom 0)
thread-factory (reify java.util.concurrent.ThreadFactory
(newThread [_ runnable]
(let [name (format "CLI-agent-send-off-pool-%d"
(first (swap-vals! thread-counter inc)))]
(doto (Thread. runnable)
(.setDaemon true) ;; DIFFERENT
(.setName name)))))
executor (java.util.concurrent.Executors/newCachedThreadPool thread-factory)]
(set-agent-send-off-executor! executor)))
(def ^:dynamic *foo* 1)
(def a (agent nil))
(defn -main [& _args]
(set-daemon-agent-executor)
(prn (-> (java.lang.ProcessHandle/current) (.pid)))
(binding [*foo* 2]
(send-off a (fn [_] *foo*)))
(await a)
(prn @a))
Additional Context
No response
Run-Time Log Output and Error Messages
No response