2024 Clojure状态调查! 中分享您的看法。

欢迎!请查看关于页面,了解更多关于其工作方式的信息。

0投票
ClojureScript

退出并尝试使用相同的JVM/REPL环境重新连接可能会锁定

`
$ clj
Clojure 1.9.0
user=> (require '[cljs.repl :as repl])
nil
user=> (require '[cljs.repl.browser :as browser])
nil
user=> (def env (browser/repl-env))

'user/env

user=> (repl/repl env)
ClojureScript 1.10.339
cljs.user=> 3
3
cljs.user=> :cljs/quit
nil
user=> (repl/repl env)
`

此时,事情锁定。以下是线程堆栈

`
$ jstack 97709
2018-10-13 13:26:33
Java HotSpot(TM) 64位服务器VM (25.172-b11 混合模式) 完整线程转储

"Attach Listener" #156 守护进程髮佈=9 os_髮佈=31 tid=0x00007ff1d4a14000 nid=0x9f0b 等待条件 [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"clojure-agent-send-off-pool-1" #14 鬮佈=5 os_髮佈=31 tid=0x00007ff1d4963800 nid=0x4003 等待条件 [0x000070000cd57000]
java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000006c1859760> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

"clojure-agent-send-off-pool-0" #13 鬮佈=5 os_髮佈=31 tid=0x00007ff1d41e9800 nid=0x4203 等待条件 [0x000070000cc54000]
java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000006c1859760> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

"process reaper" #12 守护进程髮佈=10 os_髮佈=31 tid=0x00007ff1d4967800 nid=0x3c03 等待条件 [0x000070000cb51000]
java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000006c209c4a8> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

"Service Thread" #8 守护进程髮佈=9 os_髮佈=31 tid=0x00007ff1d206a800 nid=0x4403 可运行 [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #7 守护进程髮佈=9 os_髮佈=31 tid=0x00007ff1d1814000 nid=0x3603 等待条件 [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 守护进程髮佈=9 os_髮佈=31 tid=0x00007ff1d2057800 nid=0x3503 等待条件 [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 守护进程髮佈=9 os_髮佈=31 tid=0x00007ff1d2058800 nid=0x4703 等待条件 [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 守护进程髮佈=9 os_髮佈=31 tid=0x00007ff1d2057000 nid=0x490b 可运行 [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Finalizer" #3 守护进程髮佈=8 os_髮佈=31 tid=0x00007ff1d2018000 nid=0x5103 在 Object.wait() [0x000070000c411000]
java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c01466f8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000006c01466f8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 守护进程髮佈=10 os_髮佈=31 tid=0x00007ff1d2017800 nid=0x2e03 在 Object.wait() [0x000070000c30e000]
java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c0146980> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000006c0146980> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 髮佈=5 os_髮佈=31 tid=0x00007ff1d2005000 nid=0x2103 等待条件 [0x000070000bcfa000]
java.lang.Thread.State: WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x0000000792c08ed8> (a java.util.concurrent.CountDownLatch$Sync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
at clojure.core$promise$reify__8144.deref(core.clj:7029)
at clojure.core$deref.invokeStatic(core.clj:2312)
at clojure.core$deref.invoke(core.clj:2298)
at cljs.repl.browser$browser_eval.invokeStatic(browser.clj:283)
at cljs.repl.browser$browser_eval.invoke(browser.clj:272)
at cljs.repl.browser.BrowserEnv._evaluate(browser.clj:373)
at cljs.repl$evaluate_form.invokeStatic(repl.cljc:568)
at cljs.repl$evaluate_form.invoke(repl.cljc:498)
at cljs.repl$repl_STAR_.invokeStatic(repl.cljc:946)
at cljs.repl$repl_STAR_.invoke(repl.cljc:855)
at cljs.repl$repl.invokeStatic(repl.cljc:1100)
at cljs.repl$repl.doInvoke(repl.cljc:1030)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at user$eval2535.invokeStatic(NO_SOURCE_FILE:8)
at user$eval2535.invoke(NO_SOURCE_FILE:8)
at clojure.lang.Compiler.eval(Compiler.java:7062)
at clojure.lang.Compiler.eval(Compiler.java:7025)
at clojure.core$eval.invokeStatic(core.clj:3206)
at clojure.core$eval.invoke(core.clj:3202)
at clojure.main$repl$read_eval_print__8572$fn__8575.invoke(main.clj:243)
at clojure.main$repl$read_eval_print__8572.invoke(main.clj:243)
at clojure.main$repl$fn__8581.invoke(main.clj:261)
at clojure.main$repl.invokeStatic(main.clj:261)
at clojure.main$repl_opt.invokeStatic(main.clj:325)
at clojure.main$main.invokeStatic(main.clj:424)
at clojure.main$main.doInvoke(main.clj:387)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.main.main(main.java:37)

"VM Thread" os_髮佈=31 tid=0x00007ff1d1811000 nid=0x2d03 可运行

"GC task thread#0 (ParallelGC)" os_髮佈=31 tid=0x00007ff1d2010800 nid=0x1e07 可运行

"GC task thread#1 (ParallelGC)" os_髮佈=31 tid=0x00007ff1d2802800 nid=0x1d03 可运行

"GC task thread#2 (ParallelGC)" os_髮佈=31 tid=0x00007ff1d3006800 nid=0x2b03 可运行

"GC task thread#3 (ParallelGC)" os_髮佈=31 tid=0x00007ff1d2803000 nid=0x5403 可运行

"VM Periodic Task Thread" os_髮佈=31 tid=0x00007ff1d206b000 nid=0x3903 等待条件

JNI 全球引用: 248
`

2 个回答

0投票
by
_评论由:potetm_发表

我认为这里的问题是在{{cljs.repl.server/connq}}连接周围的竞争条件。当它似乎工作正常时,流程是这样的

1)退出clojure repl(通过{{:cljs/quit}})
{{connq}}仍然持有对现在已失效的连接的引用
2)启动一个新的repl,它通过{{setup}}进行操作
3)浏览器发起它的`:ready`请求,这会调用{{(.clear connq)}}
4)repl初始化会调用它的`init`函数(使用{{connq}}中的连接评估一个形式)

然而,如果4和5的顺序被调换(这可能会发生,因为这与浏览器初始请求的时序有关),你将得到{{connq}}中仍然存在的已失效连接,这会导致你永久挂起。

我的问题是:为什么我们不应该在浏览器repl的{{tear-down}}中清除{{connq}}?
0投票
by
参考资料:https://clojure.atlassian.net/browse/CLJS-2932(由mfikes报告)
...