Skip to content

Instantly share code, notes, and snippets.

@cichli
Last active May 7, 2024 14:49
Show Gist options
  • Save cichli/54d91face43893f3fbcc4246c76228e9 to your computer and use it in GitHub Desktop.
Save cichli/54d91face43893f3fbcc4246c76228e9 to your computer and use it in GitHub Desktop.
POC: stop threads using JDWP
package nrepl;
public class EvaluationInterrupted extends Throwable {
public static EvaluationInterrupted t = new EvaluationInterrupted();
}
(ns nrepl.middleware.stop-thread-poc
(:import
(com.sun.jdi Bootstrap
ClassType
Field
ObjectReference
ThreadReference
VirtualMachine
VirtualMachineManager)
(com.sun.jdi.connect AttachingConnector Connector$Argument)
(java.lang ProcessHandle)
(nrepl EvaluationInterrupted)))
;; N.B. JVM must be started with the following arguments:
;; -agentlib:jdwp=transport=dt_socket,server=y,suspend=n
;; -Djdk.attach.allowAttachSelf
(defn ^VirtualMachine connect! [^VirtualMachineManager manager]
(let [^AttachingConnector connector (first (.attachingConnectors manager))
args (.defaultArguments connector)
pid (str (.pid (ProcessHandle/current)))]
(.setValue ^Connector$Argument (get args "pid") pid)
(.attach connector args)))
(defn ^VirtualMachine vm []
(let [manager (Bootstrap/virtualMachineManager)]
(or (first (.connectedVirtualMachines manager))
(connect! manager))))
(defn ^ThreadReference thread-ref [^Thread thread]
(first (filter #(= (.getName thread) (.name ^ThreadReference %))
(.allThreads (vm)))))
(defn ^ObjectReference err-ref []
(let [[^ClassType clazz] (.classesByName (vm) "nrepl.EvaluationInterrupted")
^Field field (.fieldByName clazz "t")]
(.getValue clazz field)))
(defn stop! [^Thread thread]
(.stop (thread-ref thread) (err-ref)))
@cichli
Copy link
Author

cichli commented May 7, 2024

15:21:47 [griffithsm:~/clojure/nrepl] master+*
± lein repl
Listening for transport dt_socket at address: 58260
nREPL server started on port 58266 on host 127.0.0.1 - nrepl://127.0.0.1:58266
REPL-y 0.5.1, nREPL 1.1.1
Clojure 1.11.1
OpenJDK 64-Bit Server VM 21.0.2+13-LTS
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (require 'nrepl.middleware.stop-thread-poc)
nil
user=> (in-ns 'nrepl.middleware.stop-thread-poc)
#namespace[nrepl.middleware.stop-thread-poc]
nrepl.middleware.stop-thread-poc=> (stop! (Thread/currentThread))
Execution error (EvaluationInterrupted) at nrepl.EvaluationInterrupted/<clinit> (EvaluationInterrupted.java:5).
null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment