Skip to content

Commit 70183b1

Browse files
ghadishaybanpuredanger
authored andcommitted
ASYNC-254: direct return of blocking ops, avoiding dispatch
1 parent 57b4fca commit 70183b1

File tree

4 files changed

+37
-29
lines changed

4 files changed

+37
-29
lines changed

src/main/clojure/clojure/core/async.clj

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ to catch and handle."
5656
(lock-id [_] 0)
5757
(commit [_] f))))
5858

59+
(defn- on-caller [f]
60+
(with-meta f {:on-caller? true}))
61+
5962
(defn buffer
6063
"Returns a fixed buffer of size n. When full, puts will block/park."
6164
[n]
@@ -133,7 +136,7 @@ to catch and handle."
133136
namespace docs)."
134137
[port]
135138
(let [p (promise)
136-
ret (impl/take! port (fn-handler (fn [v] (deliver p v))))]
139+
ret (impl/take! port (fn-handler (on-caller #(deliver p %))))]
137140
(if ret
138141
@ret
139142
(deref p))))
@@ -156,7 +159,7 @@ to catch and handle."
156159
Returns nil."
157160
([port fn1] (take! port fn1 true))
158161
([port fn1 on-caller?]
159-
(let [ret (impl/take! port (fn-handler fn1))]
162+
(let [ret (impl/take! port (fn-handler (if on-caller? (on-caller fn1) fn1)))]
160163
(when ret
161164
(let [val @ret]
162165
(if on-caller?
@@ -172,7 +175,7 @@ to catch and handle."
172175
namespace docs)."
173176
[port val]
174177
(let [p (promise)
175-
ret (impl/put! port val (fn-handler (fn [open?] (deliver p open?))))]
178+
ret (impl/put! port val (fn-handler (on-caller #(deliver p %))))]
176179
(if ret
177180
@ret
178181
(deref p))))
@@ -204,7 +207,7 @@ to catch and handle."
204207
true))
205208
([port val fn1] (put! port val fn1 true))
206209
([port val fn1 on-caller?]
207-
(if-let [retb (impl/put! port val (fn-handler fn1))]
210+
(if-let [retb (impl/put! port val (fn-handler (if on-caller? (on-caller fn1) fn1)))]
208211
(let [ret @retb]
209212
(if on-caller?
210213
(fn1 ret)
@@ -309,7 +312,7 @@ to catch and handle."
309312
namespace docs)."
310313
[ports & opts]
311314
(let [p (promise)
312-
ret (do-alts (partial deliver p) ports (apply hash-map opts))]
315+
ret (do-alts (on-caller #(deliver p %)) ports (apply hash-map opts))]
313316
(if ret
314317
@ret
315318
(deref p))))
@@ -512,11 +515,7 @@ to catch and handle."
512515
(defn- pipeline*
513516
([n to xf from close? ex-handler type]
514517
(assert (pos? n))
515-
(let [ex-handler (or ex-handler (fn [ex]
516-
(-> (Thread/currentThread)
517-
.getUncaughtExceptionHandler
518-
(.uncaughtException (Thread/currentThread) ex))
519-
nil))
518+
(let [ex-handler (or ex-handler dispatch/ex-handler)
520519
jobs (chan n)
521520
results (chan n)
522521
process (fn [[v p :as job]]

src/main/clojure/clojure/core/async/impl/channels.clj

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
(cleanup [_])
3131
(abort [_]))
3232

33+
(defn appm
34+
"returns closure that applies f to arg and has the metadata of f"
35+
[f arg]
36+
(with-meta #(f arg) (meta f)))
37+
3338
(deftype ManyToManyChannel [^LinkedList takes ^LinkedList puts ^Queue buf closed ^Lock mutex add!]
3439
MMC
3540
(cleanup
@@ -58,7 +63,7 @@
5863
(let [put-cb (and (impl/active? putter) (impl/commit putter))]
5964
(.unlock putter)
6065
(when put-cb
61-
(dispatch/run (fn [] (put-cb true))))
66+
(dispatch/run (appm put-cb true)))
6267
(when (.hasNext iter)
6368
(recur (.next iter)))))))
6469
(.clear puts)
@@ -97,7 +102,7 @@
97102
(if ret
98103
(let [val (impl/remove! buf)]
99104
(.remove iter)
100-
(recur (conj takers (fn [] (ret val)))))
105+
(recur (conj takers (appm ret val))))
101106
(recur takers))))
102107
takers))]
103108
(if (seq take-cbs)
@@ -137,7 +142,7 @@
137142
(if (and put-cb take-cb)
138143
(do
139144
(.unlock mutex)
140-
(dispatch/run (fn [] (take-cb val)))
145+
(dispatch/run (appm take-cb val))
141146
(box true))
142147
(if (and buf (not (impl/full? buf)))
143148
(do
@@ -195,7 +200,7 @@
195200
(abort this))
196201
(.unlock mutex)
197202
(doseq [cb cbs]
198-
(dispatch/run #(cb true)))
203+
(dispatch/run (appm cb true)))
199204
(box val))
200205
(do (.unlock mutex)
201206
nil))
@@ -221,7 +226,7 @@
221226
(if (and put-cb take-cb)
222227
(do
223228
(.unlock mutex)
224-
(dispatch/run #(put-cb true))
229+
(dispatch/run (appm put-cb true))
225230
(box val))
226231
(if @closed
227232
(do
@@ -266,22 +271,16 @@
266271
(.unlock taker)
267272
(when take-cb
268273
(let [val (when (and buf (pos? (count buf))) (impl/remove! buf))]
269-
(dispatch/run (fn [] (take-cb val)))))
274+
(dispatch/run (appm take-cb val))))
270275
(.remove iter)
271276
(when (.hasNext iter)
272277
(recur (.next iter)))))))
273278
(when buf (impl/close-buf! buf))
274279
(.unlock mutex)
275280
nil))))
276281

277-
(defn- ex-handler [ex]
278-
(-> (Thread/currentThread)
279-
.getUncaughtExceptionHandler
280-
(.uncaughtException (Thread/currentThread) ex))
281-
nil)
282-
283282
(defn- handle [buf exh t]
284-
(let [else ((or exh ex-handler) t)]
283+
(let [else ((or exh dispatch/ex-handler) t)]
285284
(if (nil? else)
286285
buf
287286
(impl/add! buf else))))

src/main/clojure/clojure/core/async/impl/dispatch.clj

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,17 @@
2929
(when (.get ^ThreadLocal in-dispatch)
3030
(throw (IllegalStateException. "Invalid blocking call in dispatch thread"))))
3131

32+
(defn ex-handler
33+
"conveys given Exception to current thread's default uncaught handler. returns nil"
34+
[ex]
35+
(-> (Thread/currentThread)
36+
.getUncaughtExceptionHandler
37+
(.uncaughtException (Thread/currentThread) ex))
38+
nil)
39+
3240
(defn run
33-
"Runs Runnable r in a thread pool thread"
41+
"Runs Runnable r on current thread when :on-caller? meta true, else in a thread pool thread."
3442
[^Runnable r]
35-
(impl/exec @executor r))
43+
(if (-> r meta :on-caller?)
44+
(try (.run r) (catch Throwable t (ex-handler t)))
45+
(impl/exec @executor r)))

src/test/clojure/clojure/core/async_test.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@
5959
"The written value is the value provided to the read callback."))
6060

6161
(deftest take!-on-caller?
62-
(is (apply not= (let [starting-thread (Thread/currentThread)
62+
(is (apply = (let [starting-thread (Thread/currentThread)
6363
test-channel (chan nil)
6464
read-promise (promise)]
6565
(take! test-channel (fn [_] (deliver read-promise (Thread/currentThread))) true)
6666
(>!! test-channel :foo)
6767
[starting-thread @read-promise]))
6868
"When on-caller? requested, but no value is immediately
69-
available, take!'s callback executes on another thread.")
69+
available, take!'s callback executes putter's thread.")
7070
(is (apply = (let [starting-thread (Thread/currentThread)
7171
test-channel (chan nil)
7272
read-promise (promise)]
@@ -101,14 +101,14 @@
101101
[starting-thread @write-promise]))
102102
"When on-caller? is false, but a reader can consume the value,
103103
put!'s callback executes on a different thread.")
104-
(is (apply not= (let [starting-thread (Thread/currentThread)
104+
(is (apply = (let [starting-thread (Thread/currentThread)
105105
test-channel (chan nil)
106106
write-promise (promise)]
107107
(put! test-channel :foo (fn [_] (deliver write-promise (Thread/currentThread))) true)
108108
(take! test-channel (fn [_] nil))
109109
[starting-thread @write-promise]))
110110
"When on-caller? requested, but no reader can consume the value,
111-
put!'s callback executes on a different thread."))
111+
put!'s callback executes on a taker's thread."))
112112

113113

114114
(deftest limit-async-take!-put!

0 commit comments

Comments
 (0)