Skip to content

Commit b4935ff

Browse files
Support adding -Djdk.attach.allowAttachSelf to jack-in params
Add `cider-enable-nrepl-jvmti-agent` customizable to control this behaviour.
1 parent 19d23e0 commit b4935ff

File tree

5 files changed

+53
-13
lines changed

5 files changed

+53
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### New features
66

77
- [#3692](https://github.com/clojure-emacs/cider/pull/3692): Add ability to switch view modes in the ispector (bound to `v`).
8+
- [#3693](https://github.com/clojure-emacs/cider/pull/3693): Add `cider-enable-nrepl-jvmti-agent` defcustom to enable loading native nREPL JVMTI agent which restores thread stop ability on Java 21+.
89

910
### Changes
1011

cider.el

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,6 @@ then concatenated into the \"-M[your-aliases]:cider/nrepl\" form."
173173
:safe #'stringp
174174
:package-version '(cider . "1.1"))
175175

176-
177176
(defcustom cider-clojure-cli-global-aliases
178177
nil
179178
"Global aliases to include when jacking in with the clojure CLI.
@@ -186,7 +185,6 @@ then concatenated into the \"-M[your-aliases]:cider/nrepl\" form."
186185
:safe #'stringp
187186
:package-version '(cider . "1.14"))
188187

189-
190188
(defcustom cider-shadow-cljs-command
191189
"npx shadow-cljs"
192190
"The command used to execute shadow-cljs.
@@ -376,6 +374,14 @@ The repl dependendcies are most likely to be nREPL middlewares."
376374
:safe #'booleanp
377375
:version '(cider . "0.11.0"))
378376

377+
(defcustom cider-enable-nrepl-jvmti-agent nil
378+
"When t, add `-Djdk.attach.allowAttachSelf' to the command line arguments.
379+
This allows nREPL JVMTI agent to be loaded. It is needed for evaluation
380+
interruption to properly work on Java 21 and above."
381+
:type 'boolean
382+
:safe #'booleanp
383+
:version '(cider . "1.15.0"))
384+
379385
(defcustom cider-offer-to-open-cljs-app-in-browser t
380386
"When nil, do not offer to open ClojureScript apps in a browser on connect."
381387
:type 'boolean
@@ -536,7 +542,7 @@ Throws an error if PROJECT-TYPE is unknown."
536542
"List of dependencies where elements are lists of artifact name and version.")
537543
(put 'cider-jack-in-dependencies 'risky-local-variable t)
538544

539-
(defcustom cider-injected-nrepl-version "1.1.2"
545+
(defcustom cider-injected-nrepl-version "1.2.0-beta2"
540546
"The version of nREPL injected on jack-in.
541547
We inject the newest known version of nREPL just in case
542548
your version of Boot or Leiningen is bundling an older one."
@@ -762,6 +768,8 @@ group:artifact:version notation and MIDDLEWARES are
762768
prepared as arguments to Clojurephant's ClojureNRepl task."
763769
(concat global-opts
764770
(unless (seq-empty-p global-opts) " ")
771+
(when cider-enable-nrepl-jvmti-agent
772+
"-Pjdk.attach.allowAttachSelf ")
765773
(cider--gradle-jack-in-property (append (cider--jack-in-required-dependencies) dependencies))
766774
" "
767775
params
@@ -813,7 +821,9 @@ removed, LEIN-PLUGINS, LEIN-MIDDLEWARES and finally PARAMS."
813821
(seq-map (lambda (middleware)
814822
(concat "update-in :middleware conj "
815823
middleware))
816-
lein-middlewares))
824+
lein-middlewares)
825+
(when cider-enable-nrepl-jvmti-agent
826+
`(,(concat "update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"))))
817827
" -- ")
818828
" -- "
819829
(if (not cider-enrich-classpath)
@@ -903,9 +913,10 @@ your aliases contain any mains, the cider/nrepl one will be the one used."
903913
(deps (format "{:deps {%s} :aliases {:cider/nrepl {:main-opts [%s]}}}"
904914
(string-join all-deps " ") main-opts))
905915
(deps-quoted (cider--shell-quote-argument deps command)))
906-
(format "%s-Sdeps %s -M%s:cider/nrepl%s"
916+
(format "%s%s-Sdeps %s -M%s:cider/nrepl%s"
907917
;; TODO: global-options are deprecated and should be removed in CIDER 2.0
908918
(if global-options (format "%s " global-options) "")
919+
(if cider-enable-nrepl-jvmti-agent "-J-Djdk.attach.allowAttachSelf " "")
909920
deps-quoted
910921
(cider--combined-aliases)
911922
(if params (format " %s" params) ""))))

doc/modules/ROOT/pages/basics/up_and_running.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ You can further customize the command line CIDER uses for `cider-jack-in` by
204204
modifying the some options. Those differ a bit between the various tools,
205205
so we'll examine them tool by tool.
206206

207+
==== Enabling nREPL JVMTI agent
208+
209+
Since version 1.2.0, nREPL ships together with a native JVMTI agent, so that the
210+
eval interrupts properly work on Java 21 and later. To enable the agent, the
211+
Java process should be launched with `-Djdk.attach.allowAttachSelf`. CIDER will
212+
do it automatically during jack-in if `cider-enable-nrepl-jvmti-agent` is set to
213+
`t`.
214+
207215
==== Leiningen Options
208216

209217
* `cider-lein-command` - the name of the Leiningen executable (`lein` by default)

doc/modules/ROOT/pages/usage/code_evaluation.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ NOTE: CIDER internally increases the timeout to 30 seconds for the first sync ev
161161

162162
== Configuration
163163

164+
=== Enable evaluation interrupts on Java 21 and newer
165+
166+
The configuration variable `cider-enable-nrepl-jvmti-agent` has to be enabled
167+
for interrupts to work properly on Java 21+. See
168+
xref:basics/up_and_running.adoc#enabling-nrepl-jvmti-agent[JVMTI agent] section.
169+
164170
=== Display Spinner During Evaluation
165171

166172
Some evaluation operations take a while to complete, so CIDER will display a

test/cider-tests.el

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@
147147
(setq-local cider-injected-middleware-version "0.49.0")
148148
(setq-local cider-jack-in-nrepl-middlewares '("cider.nrepl/cider-middleware"))
149149
(setq-local cider-jack-in-dependencies-exclusions '())
150-
(setq-local cider-enrich-classpath t))
150+
(setq-local cider-enrich-classpath t)
151+
(setq-local cider-enable-nrepl-jvmti-agent t))
151152

152153
(it "can inject dependencies in a lein project"
153154
(expect (cider-inject-jack-in-dependencies "" "repl :headless" 'lein)
@@ -157,6 +158,7 @@
157158
(shell-quote-argument "[cider/cider-nrepl \"0.49.0\"]")
158159
" -- update-in :plugins conj "
159160
(shell-quote-argument "[mx.cider/lein-enrich-classpath \"1.19.3\"]")
161+
" -- update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"
160162
" -- update-in :middleware conj cider.enrich-classpath.plugin-v2/middleware"
161163
" -- repl :headless")))
162164

@@ -170,6 +172,7 @@
170172
(shell-quote-argument "[cider/cider-nrepl \"0.49.0\"]")
171173
" -- update-in :plugins conj "
172174
(shell-quote-argument "[mx.cider/lein-enrich-classpath \"1.19.3\"]")
175+
" -- update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"
173176
" -- update-in :middleware conj cider.enrich-classpath.plugin-v2/middleware"
174177
" -- repl :headless")))
175178

@@ -182,6 +185,7 @@
182185
(shell-quote-argument "[cider/cider-nrepl \"0.49.0\"]")
183186
" -- update-in :plugins conj "
184187
(shell-quote-argument "[mx.cider/lein-enrich-classpath \"1.19.3\"]")
188+
" -- update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"
185189
" -- update-in :middleware conj cider.enrich-classpath.plugin-v2/middleware"
186190
" -- repl :headless")))
187191

@@ -201,6 +205,7 @@
201205
(it "can inject dependencies in a gradle project"
202206
(expect (cider-inject-jack-in-dependencies "--no-daemon" ":clojureRepl" 'gradle)
203207
:to-equal (concat "--no-daemon "
208+
"-Pjdk.attach.allowAttachSelf "
204209
(shell-quote-argument "-Pdev.clojurephant.jack-in.nrepl=nrepl:nrepl:0.9.0,cider:cider-nrepl:0.49.0")
205210
" :clojureRepl "
206211
(shell-quote-argument "--middleware=cider.nrepl/cider-middleware")))))
@@ -221,6 +226,7 @@
221226
(shell-quote-argument "[cider/cider-nrepl \"0.49.0\"]")
222227
" -- update-in :plugins conj "
223228
(shell-quote-argument "[mx.cider/lein-enrich-classpath \"1.19.3\"]")
229+
" -- update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"
224230
" -- update-in :middleware conj cider.enrich-classpath.plugin-v2/middleware"
225231
" -- repl :headless")))
226232

@@ -256,6 +262,7 @@
256262
(shell-quote-argument "[cider/cider-nrepl \"0.49.0\"]")
257263
" -- update-in :plugins conj "
258264
(shell-quote-argument "[mx.cider/lein-enrich-classpath \"1.19.3\"]")
265+
" -- update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"
259266
" -- update-in :middleware conj cider.enrich-classpath.plugin-v2/middleware"
260267
" -- repl :headless")))
261268
(it "can concat in a boot project"
@@ -272,6 +279,7 @@
272279
(it "can concat in a gradle project"
273280
(expect (cider-inject-jack-in-dependencies "--no-daemon" ":clojureRepl" 'gradle)
274281
:to-equal (concat "--no-daemon "
282+
"-Pjdk.attach.allowAttachSelf "
275283
(shell-quote-argument "-Pdev.clojurephant.jack-in.nrepl=nrepl:nrepl:0.9.0,cider:cider-nrepl:0.49.0")
276284
" :clojureRepl "
277285
(shell-quote-argument "--middleware=cider.nrepl/cider-middleware")))))
@@ -337,6 +345,7 @@
337345
(shell-quote-argument "[cider/cider-nrepl \"0.49.0\"]")
338346
" -- update-in :plugins conj "
339347
(shell-quote-argument "[mx.cider/lein-enrich-classpath \"1.19.3\"]")
348+
" -- update-in :jvm-opts conj -Djdk.attach.allowAttachSelf"
340349
" -- update-in :middleware conj cider.enrich-classpath.plugin-v2/middleware"
341350
" -- repl :headless"))))
342351

@@ -446,21 +455,22 @@
446455
(it "uses main opts in an alias to prevent other mains from winning"
447456
(setq-local cider-jack-in-dependencies nil)
448457
(setq-local cider-jack-in-nrepl-middlewares '("cider.nrepl/cider-middleware"))
449-
(let ((expected (string-join `("clojure -Sdeps "
458+
(let ((expected (string-join `("clojure -J-Djdk.attach.allowAttachSelf -Sdeps "
450459
,(shell-quote-argument "{:deps {nrepl/nrepl {:mvn/version \"0.9.0\"} cider/cider-nrepl {:mvn/version \"0.49.0\"}} :aliases {:cider/nrepl {:main-opts [\"-m\" \"nrepl.cmdline\" \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}}}")
451460
" -M:cider/nrepl")
452461
"")))
453462
(setq-local cider-allow-jack-in-without-project t)
454463
(setq-local cider-clojure-cli-command "clojure")
455464
(setq-local cider-inject-dependencies-at-jack-in t)
456465
(setq-local cider-clojure-cli-aliases nil)
466+
(setq-local cider-enable-nrepl-jvmti-agent t)
457467
(spy-on 'cider-project-type :and-return-value 'clojure-cli)
458468
(spy-on 'cider-jack-in-resolve-command :and-return-value "clojure")
459469
(expect (plist-get (cider--update-jack-in-cmd nil) :jack-in-cmd)
460470
:to-equal expected)))
461471

462472
(it "allows specifying custom aliases with `cider-clojure-cli-aliases`"
463-
(let ((expected (string-join `("clojure -Sdeps "
473+
(let ((expected (string-join `("clojure -J-Djdk.attach.allowAttachSelf -Sdeps "
464474
,(shell-quote-argument "{:deps {nrepl/nrepl {:mvn/version \"0.9.0\"} cider/cider-nrepl {:mvn/version \"0.49.0\"}} :aliases {:cider/nrepl {:main-opts [\"-m\" \"nrepl.cmdline\" \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}}}")
465475
" -M:dev:test:cider/nrepl")
466476
"")))
@@ -469,6 +479,7 @@
469479
(setq-local cider-allow-jack-in-without-project t)
470480
(setq-local cider-clojure-cli-command "clojure")
471481
(setq-local cider-inject-dependencies-at-jack-in t)
482+
(setq-local cider-enable-nrepl-jvmti-agent t)
472483
(spy-on 'cider-project-type :and-return-value 'clojure-cli)
473484
(spy-on 'cider-jack-in-resolve-command :and-return-value "clojure")
474485
(expect (plist-get (cider--update-jack-in-cmd nil) :jack-in-cmd)
@@ -477,7 +488,8 @@
477488
(dolist (command '("clojure" "powershell"))
478489
(it (format "should remove duplicates, yielding the same result (for %S command invocation)" command)
479490
;; repeat the same test for PowerShell too
480-
(let ((expected (string-join `("-Sdeps "
491+
(let ((expected (string-join `("-J-Djdk.attach.allowAttachSelf "
492+
"-Sdeps "
481493
,(cider--shell-quote-argument "{:deps {cider/cider-nrepl {:mvn/version \"0.49.0\"} nrepl/nrepl {:mvn/version \"0.9.0\"}} :aliases {:cider/nrepl {:main-opts [\"-m\" \"nrepl.cmdline\" \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}}}"
482494
command)
483495
" -M:dev:test:cider/nrepl")
@@ -487,7 +499,8 @@
487499
command)
488500
:to-equal expected))))
489501
(it "handles aliases correctly"
490-
(let ((expected (string-join `("-Sdeps "
502+
(let ((expected (string-join `("-J-Djdk.attach.allowAttachSelf "
503+
"-Sdeps "
491504
,(shell-quote-argument "{:deps {cider/cider-nrepl {:mvn/version \"0.49.0\"} nrepl/nrepl {:mvn/version \"0.9.0\"}} :aliases {:cider/nrepl {:main-opts [\"-m\" \"nrepl.cmdline\" \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}}}")
492505
" -M:test:cider/nrepl")
493506
""))
@@ -515,25 +528,26 @@
515528
(expect (cider-clojure-cli-jack-in-dependencies nil nil deps)
516529
:to-equal expected)))))
517530
(it "allows for global options"
518-
(let ((expected (string-join `("-J-Djdk.attach.allowAttachSelf -Sdeps "
531+
(let ((expected (string-join `("-J-Xverify:none -J-Djdk.attach.allowAttachSelf -Sdeps "
519532
,(shell-quote-argument "{:deps {cider/cider-nrepl {:mvn/version \"0.49.0\"} nrepl/nrepl {:mvn/version \"0.9.0\"}} :aliases {:cider/nrepl {:main-opts [\"-m\" \"nrepl.cmdline\" \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}}}")
520533
" -M:test:cider/nrepl")
521534
""))
522535
(deps '(("nrepl/nrepl" "0.9.0"))))
523536
(let ((cider-clojure-cli-aliases ":test"))
524-
(expect (cider-clojure-cli-jack-in-dependencies "-J-Djdk.attach.allowAttachSelf" nil deps)
537+
(expect (cider-clojure-cli-jack-in-dependencies "-J-Xverify:none" nil deps)
525538
:to-equal expected))))
526539
(it "allows to specify git coordinate as cider-jack-in-dependency"
527540
(setq-local cider-jack-in-dependencies '(("org.clojure/tools.deps" (("git/sha" . "6ae2b6f71773de7549d7f22759e8b09fec27f0d9")
528541
("git/url" . "https://github.com/clojure/tools.deps/")))))
529-
(let ((expected (string-join `("clojure -Sdeps "
542+
(let ((expected (string-join `("clojure -J-Djdk.attach.allowAttachSelf -Sdeps "
530543
,(shell-quote-argument "{:deps {nrepl/nrepl {:mvn/version \"0.9.0\"} cider/cider-nrepl {:mvn/version \"0.49.0\"} org.clojure/tools.deps { :git/sha \"6ae2b6f71773de7549d7f22759e8b09fec27f0d9\" :git/url \"https://github.com/clojure/tools.deps/\" }} :aliases {:cider/nrepl {:main-opts [\"-m\" \"nrepl.cmdline\" \"--middleware\" \"[cider.nrepl/cider-middleware]\"]}}}")
531544
" -M:cider/nrepl")
532545
"")))
533546
(setq-local cider-allow-jack-in-without-project t)
534547
(setq-local cider-clojure-cli-command "clojure")
535548
(setq-local cider-inject-dependencies-at-jack-in t)
536549
(setq-local cider-clojure-cli-aliases nil)
550+
(setq-local cider-enable-nrepl-jvmti-agent t)
537551
(spy-on 'cider-project-type :and-return-value 'clojure-cli)
538552
(spy-on 'cider-jack-in-resolve-command :and-return-value "clojure")
539553
(expect (plist-get (cider--update-jack-in-cmd nil) :jack-in-cmd)

0 commit comments

Comments
 (0)