<< Back to previous view

[ASYNC-51] Core.async memory leak in Safari and Mobile Safari Created: 21/Jan/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Bruce Hauman Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Mobile Safari on iOS 7.0; Safari 6.1 on OSX Lion



 Description   

Chaining together channels apparently leaks memory in Safari.

A statement such as

(def test [input-chan]
(map< identity (map< identity (map< identity input-chan))))

will leak memory when the channels are used. The longer the chain the more memory.

I have created an example repository and an example page.

The repo and the example code is here:
https://github.com/bhauman/checkmemleak/blob/master/src/checking_safari_leak/core.cljs

The demonstration page is here:
This link will leak
http://rigsomelight.com/checkmemleak/?leak=true
This link will not
http://rigsomelight.com/checkmemleak

The leak is pretty darn severe.



 Comments   
Comment by Bruce Hauman [ 21/Jan/14 4:55 PM ]

I have just confirmed this is also a problem in Safari Version 7.0.1 (9537.73.11) on Mavericks.

Comment by Bruce Hauman [ 23/Jan/14 7:13 PM ]

I updated the example page.

http://rigsomelight.com/checkmemleak/index.html

This link wont leak:
http://rigsomelight.com/checkmemleak/index.html#comp-partial

This link will leak:
http://rigsomelight.com/checkmemleak/index.html#map<

There is navigation to try the different implementations and optimization modes.

To be clear map<-chain, custom-map, map<, and map> all exhibit the leak in :none and simple optimization modes.





[ASYNC-46] Add optional default channel to 'pub' Created: 09/Dec/13  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Steffen Dienst Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-Add-default-channel-for-pub.patch    
Patch: Code and Test

 Description   

If there is no subscriber for a topic the message gets silently dropped. I suggest to add an optional default channel that receives all those messages. The default channel can then be used in scenarios, where the complete set of topics might be unknown beforehand.
This functionality resembles the 'dead letter' pattern in messaging systems.






[ASYNC-42] (try (catch :default)) inside a cljs go block raises an exception Created: 07/Dec/13  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Travis Vachon Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: cljs

Attachments: Text File async_42.patch     Text File try-catch-default.patch    

 Description   

test demonstrating issue and patch fixing it here: https://github.com/clojure/core.async/pull/39



 Comments   
Comment by Travis Vachon [ 08/Dec/13 8:51 PM ]

code + test

Comment by Travis Vachon [ 10/Dec/13 9:53 AM ]

add {{git am}}able patch





[ASYNC-43] queue-dispatcher should fall back to process.nextTick if setImmediate is not available Created: 07/Dec/13  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Travis Vachon Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: cljs

Attachments: Text File async_43.patch     Text File nextTick.patch    

 Description   

discussion here:

https://groups.google.com/forum/#!searchin/clojurescript/nextTick/clojurescript/RW1FMv0UoPE/hsMHI4SLKXYJ

discussion of the differences between setImmediate and nextTick here:

http://stackoverflow.com/questions/15349733/setimmediate-vs-nexttick

it sounds to me like nextTick should be ok, but I'm not familiar with the design decisions in the current implementation

I'm happy to create a patch - will do that shortly.



 Comments   
Comment by Travis Vachon [ 07/Dec/13 7:28 PM ]

patch here: https://github.com/clojure/core.async/pull/40

Comment by Travis Vachon [ 08/Dec/13 8:52 PM ]

just the code, not entirely sure how to test this, but have tested manually in the parse.com cloud code environment

Comment by Travis Vachon [ 10/Dec/13 9:53 AM ]

add git am able patch

Comment by Travis Vachon [ 05/Mar/14 5:21 PM ]

just want to ping this issue - anything else it needs to be mergable? I'm using a core.async fork at the moment and would love to get back on the main line!





[ASYNC-68] Improve error handling for map< and map> Created: 09/May/14  Updated: 14/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Timothy Baldridge Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

How can we deal with error handling better. For example, map< will throw an exception in the taker's thread if the function throws an exception. map> throws an exception on the put!. So this can crash an entire chain of ops. For example a pipe into map> will crash the pipe go to crash if the map function throws an error. We can add try/catch to all of this, but what do we do with the exceptions, and how do we recover?



 Comments   
Comment by Timothy Baldridge [ 14/May/14 12:25 PM ]

<Comment Removed> I misunderstood. But the original problem still stands.





[ASYNC-72] CLJS: mult becomes blocked after putting to a closed channel Created: 15/May/14  Updated: 06/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Logan Linn Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File cljs_mult_dec.patch    
Patch: Code

 Description   

A mult can become blocked after a putting to a closed tap channel due to an off-by-one error in triggering the end condition.

It appears the issue was recently fixed in the Clojure version of mult, but not the ClojureScript version.
https://github.com/clojure/core.async/commit/8864214ed9fa9aa8dc12297c6cf99ad0be65a6ae

The issue occurs because the counter that indicates the mult has finished a putting to all taps, dctr is decremented out of band and the zero? triggering condition in done function is missed.
https://github.com/clojure/core.async/blob/65b2d6c81350ba8b4bb3a8b82ad45ba984c0037c/src/main/clojure/cljs/core/async.cljs#L457

The done function passed to put! appears to be called regardless of whether the channel is closed. Because of this, we don't need to (swap! dctr dec) or necessarily call (done nil) (the CLJ fix) to fix this issue.

Demonstration: https://gist.github.com/loganlinn/e840139a9ab5503970fd



 Comments   
Comment by Gijs Stuurman [ 06/Jun/14 11:03 AM ]

The title of this issue says it's CLJS only, but the double done/counter-decrement applies to the CLJ version as well. As is briefly mentioned at the end of this issue.

For closed channels the done function is called twice in mult, because put! returns false for closed channels and calls the callback:
https://github.com/clojure/core.async/blob/65b2d6c81350ba8b4bb3a8b82ad45ba984c0037c/src/main/clojure/clojure/core/async.clj#L684

In the CLJ version this will not lead to blocking but it violates the behavior in the docstring of "each tap must accept before the next item is distributed" when a tap is closed.





[ASYNC-73] try-catch-finally broken inside go-blocks Created: 21/Jun/14  Updated: 21/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Moritz Ulrich Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

clojure 1.6.0, clojurescript 0.0-2234, core.async 0.1.303.0-886421-alpha1



 Description   

The following will cause the failed assertion (ioc_helpers.cljs:155)
when evaluated as a whole, and will correctly catch the Error when
just the `try' gets evaluated. The `finally' block runs only if the
inner block is evaluated:

(go
  (try
    (throw (js/Error. "asdf"))
    (catch ExceptionInfo e
      (println "ExceptionInfo"))
    (catch js/Error e
      (println "js/Error"))
    (finally
      (println "finally"))))

Another notable observation is that changing the order of the `catch'
blocks will change the behavior: If the (catch js/Error ...) is the
first catch block, it will work just as expected.






[ASYNC-4] Record literals become ordinary maps Created: 15/Jul/13  Updated: 23/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Alex Miller Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

CLJS


Approval: Triaged

 Description   
(require '[clojure.core.async :refer (<!! go)])
(defrecord Foo [x])
(def f (Foo. 4))
(<!! (go f))
;; => #user.Foo{:x 4}
;; OK

(<!! (go #clojure.core.async.Foo{:x 4}))
;; CLJ: => #user.Foo{:x 4}   ;; expected
;; CLJS => {:x 4}            ;; wrong

Approach: Query the analyzer to know if we have a record or not.

(Copied from GitHub issue #13 - https://github.com/clojure/core.async/issues/13)



 Comments   
Comment by Ghadi Shayban [ 03/Aug/13 2:08 PM ]

0c6e663493 contains a fix on the Clojure side, would appreciate help porting to cljs.

Comment by David Nolen [ 08/Aug/13 8:35 AM ]

I think on the ClojureScript we'll have to query the analyzer to know if we have a record or not.





[ASYNC-32] onto-chan retains head of input sequence causing OutOfMemoryError Created: 06/Nov/13  Updated: 23/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Brian Lubeski Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: memory
Environment:

org.clojure/core.async 0.1.242.0-44b1e3-alpha


Attachments: File patch.clj    
Patch: Code
Approval: Triaged

 Description   
(require '[clojure.core.async :as a])
(let [c (a/chan)]
  (a/onto-chan c (iterate inc 0))
  (while true
    (a/<!! c)))

onto-chan is holding on to the head of the input sequence as it is unfolded, resulting in an (eventual) OutOfMemoryError.

I've attached a diff showing changes I made to onto-chan that fixed the problem for me.






[ASYNC-64] Race condition when closing mults Created: 29/Apr/14  Updated: 23/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: James Reeves Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: mult

Approval: Triaged

 Description   

When a mult is tapped at around the same time as the source channel is closed, the tapped channel may not be closed.

(require '[clojure.core.async :refer (chan mult tap close!)])
(let [s (chan)
      m (mult s)
      c (chan)]
  (tap m c)
  (close! s)
  (impl/closed? c))

The above code will sometimes return true, and sometimes return false.

Cause: This is caused by the following code in the mult function:

(if (nil? val)
  (doseq [[c close?] @cs]
    (when close? (close! c)))

Any channels tapped after cs is dereferenced will not be closed.

Approach: A possible solution to this could be to always close channels tapped to a closed source. i.e.

(let [s (chan)
      m (mult s)
      c (chan)]
  (close! s)
  (tap m c))  ;; will always close c

This could be achieved by adding a flag to the cs atom to denote whether the mult is open or closed. If it's closed, any tapped channel is closed automatically.



 Comments   
Comment by James Reeves [ 30/Apr/14 6:05 AM ]

For reference, below is the custom fix for mult I'm using:

(defn mult [ch]
  (let [state (atom [true {}])
        m (reify
            Mux
            (muxch* [_] ch)
            Mult
            (tap* [_ ch close?]
              (let [add-ch    (fn [[o? cs]] [o? (if o? (assoc cs ch close?) cs)])
                    [open? _] (swap! state add-ch)]
                (when-not open? (close! ch))
                nil))
            (untap* [_ ch]
              (swap! state (fn [[open? cs]] [open? (dissoc cs ch)]))
              nil)
            (untap-all* [_]
              (swap! state (fn [[open? _]] [open? {}]))))
        dchan (chan 1)
        dctr (atom nil)
        done (fn [_] (when (zero? (swap! dctr dec))
                       (put! dchan true)))]
    (go-loop []
      (let [val (<! ch)]
        (if (nil? val)
          (let [[_ cs] (swap! state (fn [[_ cs]] [false cs]))]
            (doseq [[c close?] cs]
              (when close? (close! c))))
          (let [chs (keys (second @state))]
            (reset! dctr (count chs))
            (doseq [c chs]
              (when-not (put! c val done)
                (swap! dctr dec)
                (untap* m c)))
            (when (seq chs)
              (<! dchan))
            (recur)))))
    m))




[ASYNC-58] mult channel deadlocks when untapping a consuming channel whilst messages are being queued/blocked Created: 20/Feb/14  Updated: 23/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mathieu Gauthron Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: deadlock, mult, untap
Environment:

Mac 10.7.5; java version "1.7.0_40"; [org.clojure/clojure "1.5.1"]; [org.clojure/core.async "0.1.267.0-0d7780-alpha"]; Tested with cider and emacs 24.3


Approval: Triaged

 Description   

I have two (or more) listeners tapped onto a mult channel. I want to use them all then have one (or more) of them to leave at will without blocking the other consumer(s) or the publisher. Initially they work fine until one of them wants to stop listening. I thought the listener which drops out needs to (be a good citizen and) untap its channel from mult (otherwise a deadlock is systematic). However if messages are put into the mult before the leaving listener has had a chance to untap its channel, it creates a deadlock on the main thread (which is putting more messages simultaneously). I do not find a way to guarantee that I can untap the channel in time to avoid this race condition.

Once I have reproduced the deadlock, the repl is frozen until I interrupt with ctrl-c.
I have also tried to close the tapped channel before untapping it but the result was the same.

In the following snippet, the last (println "I'm done. You will never see this") is never reached. The publisher and the remaining consumer (consumer 1) are deadlocked even though consumer 2 was trying to leave in good terms.

(require '[clojure.core.async :refer (chan go <! >!! mult tap untap)])
(let [to-mult (chan 1)
      m (mult to-mult)]

  ;;consumer 1
  (let [c (chan 1)]
    (tap m c)
    (go (loop []
          (when-let [v (<! c)]
            (println "1 Got! " v)
            (recur))
          (println "1 Exiting!"))))

  ;;consumer 2
  (let [c (chan 1)]
    (tap m c)
    (go (loop []
          (when-let [v (<! c)]
            (when (= v 42)  ;; exit when value is not 42
              (println "2 Got! " v)
              (recur)))
          (println "2 about to leave!")
          (Thread/sleep 5000) ;; wait a bit to exacerbate the race condition
          (untap m c) ;; before unsubscribing this reader
          (println "2 Exiting."))))

   (println "about to put a few messages that work")
   (doseq [a (range 10)]
     (>!! to-mult 42))
   (println "about to put a message that will force the exit of 2")
   (>!! to-mult 43)
   (println "about to put a few more messages before reader 2 is unsubscribed to show the deadlock")
   (doseq [a (range 10)]
     (println "putting msg" a)
     (>!! to-mult 42))
   (println "I'm done. You will never see this"))
about to put a few messages that work
2 Got!  42
1 Got!  42
2 Got!  42
1 Got!  42
1 Got!  42
2 Got!  42
1 Got!  42
1 Got!  42
2 Got!  42
2 Got!  42
2 Got!  42
2 Got!  1 Got!  42
422 Got!  42

1 Got!  42
1 Got!  42
2 Got!  42
1 Got!  42
about to put a message that will force the exit of 2
1 Got!  42
2 Got!  about to put a few more messages before reader 2 is unsubscribed to show the deadlock
42
putting msg 1 Got!  0
2 about to leave!
43
1 Got!  42
putting msg 1
putting msg 2
putting msg 3
1 Got!  42
2 Exiting.


 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 10:18 AM ]

Mathieu, this is probably expected. It's important to note that to guarantee correct ordering/flow when using a mult, you should enforce it on the source/producer side of the mult, and not asynchronously on the tap side.

Mult will deref a stable set taps just before distributing a value to them, and does not adjust dynamically during value distribution except when a tap has been closed [1]. If you would like to stably untap without closing the tap you can/should let the 'producer' do it in an ordered fashion in between values on the input channel.

Knowing that a put occurred to a closed channel is new on release 0.1.278.

In general, walking away on the consuming side of a channel is tricky. Depending on the semantics of your processes, if the producer side of a channel isn't aware that a close! can happen from the consumer side, you might have to launch a draining operation.

(defn drain [c] (go (when (some? (<! c)) (recur))))

Golang disallows closing a read-only channel FWIW [2]

Better documentation is probably warranted.

[1] https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L680-L682
[2] http://golang.org/ref/spec#Close





[ASYNC-74] Provide a chan? function to determine if a given var is a channel Created: 23/Jun/14  Updated: 30/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Reno Reckling Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None

Attachments: File drupp-async-74.diff    

 Description   

When using channels, for example for streaming http bodies, it would be really helpful if there would be a chan? function to check whether a given var is a channel or not.

Aleph already does it like that in it's http-server/client implementation using lamina channels and it feels quite consistent.

It would of course also be more consistent with the rest of clojure to provide a type checking function for basic objects.



 Comments   
Comment by David Rupp [ 30/Jun/14 9:58 AM ]

Implement chan? predicate.

Comment by Timothy Baldridge [ 30/Jun/14 10:50 AM ]

I'm in favor of this, but last time I asked Rich about it his quote was "do you want a predicate for every single interface?".

Due to the implementation of core.async you'd probably need two additional predicates. One for read-port? and write-port?. You can use (satisfies? clojure.core.async.impl.protocols/ReadPort ...) but that's an internal implementation, so I'd rather have a new predicate than to tell people to touch the innards of core.async. But this call is up to Rich.

Comment by Reno Reckling [ 30/Jun/14 11:07 AM ]

I understand that reasoning. But then we would have to step up on documentation and provide a way to easily determine which interfaces are implemented by the return values of for example (chan). For me, going into the innards of core.async and trying to determine which interfaces I want, especially on very basic things like a channel, is not a user friendly approach at all.





[ASYNC-78] deadlock in multi catch Created: 05/Jul/14  Updated: 05/Jul/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Lars Bohl Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

ubuntu 14.04
Leiningen 2.4.2 on Java 1.7.0_60 Java HotSpot(TM) 64-Bit Server VM
[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]



 Description   

The following apparently never returns:

(defn thread-death []
  (<!! (go
        (<!
         (let [ch (chan 1)]
           (>! ch 0)
           (>! ch (try (<! ch)
                       (assert false)
                       (catch Exception _ 5)
                       (catch AssertionError _ 4)))
           ch)))))

After removing the (catch Exception _ 5) catch block it returns 4 as expected.






[ASYNC-27] Compilation errors inside go block always reported as first line of block Created: 08/Oct/13  Updated: 09/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: errormsgs


 Description   

I've noticed that when there are any errors inside a go block, the line number of the error is always the line containing the go symbol.

I suspect that some meta data on the forms that are converted into a state machine is being lost in the process.

This is quite annoying and quite leaky (in the abstraction sense). It makes it that much harder to track down the source of errors.



 Comments   
Comment by Timothy Baldridge [ 22/Nov/13 2:49 PM ]

Working on this, may be a few weeks out yet.

Comment by Hugo Duncan [ 11/Feb/14 5:18 PM ]

This effects both compilation errors and line numbers in stack trace frames.

Comment by Timothy Baldridge [ 09/May/14 11:26 AM ]

Completed in CLJ, once we get a tools.analyzer.cljs I'll add this to CLJS as well.





[ASYNC-79] (ClojureScript) go macro not correctly transforming (case) within a macro Created: 23/Jul/14  Updated: 23/Jul/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Tom Locke Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: cljs, macro
Environment:

[org.clojure/clojure "1.6.0"]
[org.clojure/clojurescript "0.0-2234"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]


Attachments: File core_async_bug.tgz    

 Description   

(case-let) is a macro to handle messages of the form [:message-tag, arg1, arg2, ...] with the arguments bound to local variables. It fails to work correctly when used within a go block. Note that a simple macro with a case, e.g. (defmacro my-case [expr & cases] `(case ~expr ~@cases)) does work.

(Sample project attached)

(case-let) definition:

(ns core-async-bug.macros)

(defmacro case-let [expr & cases]
  (let [msg (gensym)]
    `(let [~msg ~expr]
       (case (first ~msg)
         ~@(apply concat (for [[key [args & body]] (partition 2 cases)]
                    [key `(let [~args (rest ~msg)] ~@body)]))))))

ClojureScript test code:

(ns core-async-bug.core
  (:require-macros [cljs.core.async.macros :refer [go]]
                   [core-async-bug.macros :refer [case-let]])
  (:require [cljs.core.async :refer[<! put! chan]]))

(enable-console-print!)

; go block with manual case + lets - works
(let [c (chan)]
  (go
    (let [msg (<! c)]
      (case (first msg)
        :a (let [[x] (rest msg)] (println "First :a" x))
        :b (let [[y] (rest msg)] (println "First :b" y)))))
  (put! c [:b 123]))

; case-let outside of go - works
(case-let [:b 123]
  :a ([x] (println "Second :a" x))
  :b ([y] (println "Second :b" y)))

; case-let inside go - broken
(let [c (chan)]
  (go
    (case-let (<! c)
      :a ([x] (println "Third :a" x))
      :b ([y] (println "Third :b" y))))
  (put! c [:b 123]))

Browser console output:

Second :b 123
First :b 123
Third :a 123          <-- Should not be there!
Third :b 123


 Comments   
Comment by Tom Locke [ 23/Jul/14 3:46 AM ]

More discussion here: https://groups.google.com/forum/#!topic/clojurescript/w21nNWkKR-c

Comment by Tom Locke [ 23/Jul/14 1:58 PM ]

I've discovered an easy workaround for this problem. During macro-expansion core names like case become fully qualified, i.e. cljs.core/case, and it seems that the go macro then fails to recognise the case as such. Replacing case with ~'case in the definition of let-case fixes the problem.

I would hope this leads to an easy fix for someone who knows the core.async codebase.

The working macro is:

(defmacro case-let [expr & cases]
  (let [msg (gensym)]
    `(let [~msg ~expr]
       (~'case (first ~msg)
         ~@(apply concat (for [[key [args & body]] (partition 2 cases)]
                    [key `(let [~args (rest ~msg)] ~@body)]))))))




[ASYNC-49] cljs IOC macro issue with double-dot form Created: 12/Jan/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Paul Butcher Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

ClojureScript 0.0-2138
core.async 0.1.267.0-0d7780-alpha



 Description   

This ClojureScript compiles and runs as expected:

(let [circle (dom/getElement "circle")]
  (go-loop [x 20]
    (<! (timeout 10))
    (set! (.-value (.-baseVal (.-cx circle))) x)
    (recur (inc x))))

But if I change the set! line to:

(set! (.. circle -cx -baseVal -value) x)

I get the following error:

Wrong number of args (3) passed to: core$-DOT

For further discussion see https://groups.google.com/d/topic/clojurescript/ONMaEho4K0c/discussion






[ASYNC-71] exception behavior for thread macro is hard coded Created: 15/May/14  Updated: 06/Aug/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: exceptions
Environment:

0.1.278.0-76b25b-alpha



 Description   

Currently, the thread macro's behavior when an exception occurs is to print the exception (with println), and swallow it.

Although I make a habit of wrapping a try around code inside a thread form, I still find this a bit limited; it would be nice if there was a function that could be dynamically bound, that handled the case of an exception inside a thread.



 Comments   
Comment by Alex Miller [ 06/Aug/14 10:29 AM ]

Patches on ASYNC-76 have been applied and exceptions will now flow up to the top of the thread, where they can be caught by the standard Thread uncaught exception handler mechanism or ultimately by the default uncaught exception handler, which can be set for the application. There may still be further changes to support exception handling in thread/go.





[ASYNC-84] Issue with (require [clojure.core.async :as async]) Created: 08/Aug/14  Updated: 11/Aug/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Adam Krieg Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I was attempting to try out the new transducer stuff with core.async, but was thwarted by namespace issues.

(ns my-ns
(require [clojure.core.async :as async]))

Yields:

java.lang.IllegalArgumentException: No single method: add_BANG_STAR of interface: clojure.core.async.impl.protocols.Buffer found for function: add!* of protocol: Buffer

My dependencies are as follows:

<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.7.0-alpha1</version>
</dependency>

<dependency>
<groupId>org.clojure</groupId>
<artifactId>core.async</artifactId>
<version>0.1.319.0-6b1aca-alpha</version>
</dependency>



 Comments   
Comment by Ghadi Shayban [ 11/Aug/14 11:30 PM ]

This sounds like a code reloading issue. Have you tried removing your target/ directory and restarting the REPL?

Totally unrelated, but ns declarations take keyword :require instead of symbol.





[ASYNC-86] Update tools.analyzer.jvm dep Created: 14/Aug/14  Updated: 18/Aug/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-update-to-tools.analyzer.jvm-0.5.3.patch    
Patch: Code
Waiting On: Timothy Baldridge

 Comments   
Comment by Nicola Mometto [ 18/Aug/14 1:17 PM ]

This patch also adds a bunch of :op nodes that -item-to-ssa might hit but were not implemented, such as :set! and :host-interop
It also improves/simplifies the passes done by core.async by using info already collected by t.a.jvm passes





[ASYNC-40] do not transform forms that have :no-transform metadata attached Created: 29/Nov/13  Updated: 30/Nov/13

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Interaction between core.match clauses and the core.async transform is undesirable. core.async should respect some hook so that some forms are left alone. For example:

(match [x y]
  [1 2] ...
  [3 4] ...)

All code generated for [1 2] and [3 4] would have this metadata attached to it.



 Comments   
Comment by Rich Hickey [ 30/Nov/13 9:25 AM ]

Can you be more specific? This seems like a bad idea, and I wonder why it's desired.

Comment by David Nolen [ 30/Nov/13 2:12 PM ]

To show how bad the interaction is between core.async and a library like core.match that also generates a lot of code consider the following:

(defn foo [e]
  (match [e]
    [{:type :mouse :client-x x :client-y y}] [x y]
    [{:type :mouse :page-x x :page-y y}] [x y]
    [{:type :touch :page-x x :page-y y}] [x y]
    [{:type :key :char-code c}] c))

Without core.async, core.match produces a reasonable amount of code for this typical use of core.match to efficiently match maps - ~230 lines of pretty printed JavaScript.

But if the user wraps this typical expression in a go block:

(defn foo [in]
  (go (while true
        (let [[e c] (<! in)]
          (match [e]
            [{:type :mouse :client-x x :client-y y}] [x y]
            [{:type :mouse :page-x x :page-y y}] [x y]
            [{:type :touch :page-x x :page-y y}] [x y]
            [{:type :key :char-code c}] c)))))

It generates nearly 4200 lines of pretty-printed JavaScript. I fail to see the value of core.async transforming the optimized conditionals generated by core.match, it just generates 18X more code and the extra generated code is obviously useless - a user is matching a value, they cannot put arbitrary computations in the patterns.

https://gist.github.com/swannodette/7723758





[ASYNC-59] Channel returned by cljs.core.async/map> is missing protocol method Channel.closed? Created: 08/Mar/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Kevin Neaton Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug, patch
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2173"]
[org.clojure/core.async "0.1.278.0-76b25b-alpha"]


Attachments: Text File 0001-Fixed-map-by-including-impl.-for-closed.patch    
Patch: Code

 Description   

E.g.

(let [ch (->> (chan) (map> inc) (filter> even?))]
  (doseq [i (range 10)] (put! ch i)))

When filter> checks to see if the channel returned by map> is closed?, this code fails because the channel returned by map> does not implement the Channel.closed? protocol method.






[ASYNC-63] Variable called 'new' in vector in go block in CLJS causes "Object has no method 'call'" error Created: 07/Apr/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: James Henderson Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug, cljs
Environment:

ClojureScript 0.0-2202, core.async 0.1.267.0-0d7780-alpha, openjdk 7u51


Attachments: File compiled-cljs.js     File test_cases.clj    

 Description   

I seem to be having trouble with the combination of:

  • a variable named 'new'
  • wrapped in a vector
  • after a <! call in a go block.

Removing any of these conditions seems to work fine.

I've attached a few minimal examples in test_cases.clj and the JavaScript that the first error compiles down to in compiled-cljs.js - the errors occur on line 4 (I think inst_39771 is 21 in this case)

An obvious workaround is not to name the variable 'new'

Please let me know if you need anything more from me, and please go easy on me if this is in the wrong place/badly labelled etc - it's my first Clojure JIRA bug report

Thanks,

James



 Comments   
Comment by James Henderson [ 07/Apr/14 4:07 PM ]

Sorry, just spotted there's a newer release of core.async - I've reproduced this with 0.1.278.0-76b25b-alpha as well.

James





[ASYNC-50] Add bang(!) to the names of channel ops with side effects Created: 16/Jan/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Jozef Wagner Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Some channel ops immediatelly change the given channel, thus they have side effects. This include async/map, filter<, remove<, mapcat<, pipe, split, reduce, onto-chan, etc. All 'mutating' basic channel operations have bang at the end of their name (<Unable to render embedded object: File (, >) not found., alt!, ...). If we want to be consistent with this, bang should be added to every channel function which has side effects.






[ASYNC-55] Notification of items dropped from sliding/dropping buffers Created: 12/Feb/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Chris Perkins Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File drop-notification.diff    
Patch: Code and Test

 Description   

I would like to know when items are dropped from sliding or dropping buffers, so that I can do things like logging and keeping metrics.

The attached patch has one possible mechanism for doing this, by adding an optional second argument to sliding-buffer and dropping-buffer - a one-argument function that will be called with dropped items.



 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 10:41 AM ]

Hi Chris, I think this use-case can be handled the combination of a go process + collection directly without modification to the existing buffer impls. I'd be concerned about making buffers pay for a non-essential field.

I like using the library primitives to make sure they are minimally complete.

(If you really really want to make your own buffer, no one will stop you =) It's still an impl protocol, but it's relatively stable. Just beware that buffer operations run within the context of a channel lock, so make sure to dispatch the overflow function to the async threadpool using dispatch/run).





[ASYNC-31] put! does not throw on closed channel Created: 02/Nov/13  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Chris Perkins Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Environment:

rev 1bf8cf4



 Description   

The docstring of put! says "Will throw if closed". However, put!-ing to a closed channel appears to succeed, and even calls the supplied callback.

I'm not sure which is incorrect - the behavior or the docstring (or my intepretation of it) - but it does appear that the implementation of mult is expecting an exception from put!, in order to do cleanup.



 Comments   
Comment by Justin Balthrop [ 10/Feb/14 4:53 PM ]

The doc string for put! no longer says "Will throw if closed" for clojure.core.async, though it does still say this for cljs.core.async (and doesn't seem to work).

It looks like Rich started switching put! to return true unless the channel is closed in cf8dc1bf207e646c14b2bf44763737fcb5f08c78. The docstring reflects this change, but from my testing, put! still always returns nil.

Comment by Sung Pae [ 02/Apr/14 3:25 PM ]

Since this is likely a docstring mismatch, I'd like to add that the docstring for clojure.core.async/put states:

Asynchronously puts a val into port, calling fn1 (if supplied) when complete, passing true iff port is already closed.

fn1 is passed `false` when the port is closed, not `true`.





[ASYNC-39] Processes spawned by mix never terminate Created: 21/Nov/13  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Leon Grapenthin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: chan, mix
Environment:

"0.1.256.0-1bf8cf-alpha"



 Description   

Once a mix has been created, the go-loop inside mix will always recur. Obviously, input-channels can be unmixed and the output-channel could be closed, but the process would still never terminate.

Probably mixes should support something like (stop) to to make the mix-associated process garbage-collectable. Operations on a stopped mix should probably throw.



 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 10:44 AM ]

On 0.1.278 the mix process terminates when its output channel closes [1].

[1] https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L778

Comment by Leon Grapenthin [ 24/Apr/14 3:16 AM ]

Yes, it has been fixed using the new return behavior of put!. (I can't find an option to close this issue)





[ASYNC-57] reify in go macro compile error Created: 20/Feb/14  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Lijin Liu Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.5.1"]
[org.clojure/core.async "0.1.267.0-0d7780-alpha"]



 Description   

(go
(reify java.util.Collection
(add [this o]
(println o)
(println this)
true)))

clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: this in this context



 Comments   
Comment by Ghadi Shayban [ 22/Apr/14 9:55 AM ]

Reassigning to minor. The go macro will obviously not rewrite parking ops inside the reify. Lifting the reify into a var is a decent workaround.





[ASYNC-38] keep</> instead of map</> Created: 18/Nov/13  Updated: 05/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Leon Grapenthin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: documentation, enhancement, errormsgs


 Description   

One problem with using map< is when the supplied function returns nil. In such case (using the latest implementation from core.async [org.clojure/core.async "0.1.256.0-1bf8cf-alpha"]) one can take nil from a channel created with map<. This is otherwise only possible with closed channels. Putting nil on a channel normally throws an IllegalArgumentException.

With the current implementation of map< it is not possible to determine whether the source-channel was closed or the supplied function returned nil.

Notice that putting onto a channel created with map> throws an IllegalArgumentException when the supplied function returns nil as if you would put nil onto a channel.

My proposal is to add keep</> (where nil values returned from the supplied function are ignored and nothing is put) to the core library or to implement map</> as keep</> since having a real map</> instead of keep</> hardly makes sense when nil is not permitted anyways.



 Comments   
Comment by Leon Grapenthin [ 24/Apr/14 3:44 AM ]

It is still an issue in "0.1.278.0-76b25b-alpha" that you can only use impl.protocols/closed? to consistently determine whether a channel created with map</> was closed - if nil is one of your predicates return values.

Of course, you could use a predicate that never returns nil. But what should be the benefit of map</> being able to magically pass nil while everything else isn't?





[ASYNC-65] Change chan returned from pipe to internal go block out channel Created: 09/May/14  Updated: 09/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Can (pipe src dest close?) return the chan of its internal go block instead of 'dest'? This would provide a useful 'done' channel.






[ASYNC-67] Can we get a generic sink operation? Created: 09/May/14  Updated: 09/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Can we get a generic sink operation?

(defn sink
 "Fully consumes and discards a channel, applying f to each val. Returns a channel that
  closes when ch is fully drained"
 [f ch]
 (go-loop []
   (when-some [v (<! ch))]
     (f v)
     (recur))))





[ASYNC-66] Add drain! to consume and discard a channel Created: 09/May/14  Updated: 09/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Ghadi Shayban Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Do we want this for consumer walkaway scenarios or something baked into the channel impl?

(defn drain!
 "Fully consumes and discards a channel. Returns a channel that
  closes when ch is fully drained"
 [ch]
 (go-loop []
   (if (some? (<! ch))
     (recur))))





[ASYNC-69] How to better communicate "mix" lifecycle wrt coordination Created: 09/May/14  Updated: 09/May/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Timothy Baldridge Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Approval: Vetted

 Description   

Confusion regarding 'mix' lifecycle. Users have a false expectation that a mix's output should magically close when its source channels close, not realizing its a dynamic coordination process. Actually ensuring correctness when using mult/mix/pub isn't so straightforward, people need to control consistency from the producer end, and not ad hoc from the consumer side (e.g. late taps of a mult).






[ASYNC-77] StackOverflowError in go macro with cemerick.cljs.test (CLJS) Created: 04/Jul/14  Updated: 04/Jul/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Daniel Skarda Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "0.1.303.0-886421-alpha"]
[org.clojure/clojurescript "0.0-2261"]
[com.cemerick/clojurescript.test "0.3.1"]



 Description   

I got an StackOverflowError during compilation of CLJS tests using clojurescript.test from Chas Emerick.

I narrowed the problem to following code:

(ns async.overflow.cljs
  (:require-macros [cljs.core.async.macros :refer [go]]
                   [cemerick.cljs.test :refer [deftest is]])
  (:require [cemerick.cljs.test]))

(deftest foobar
  (go
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))
    (is (= 1 1))))

If you do not get the exception, try to increase number of repetitions of 'is' call.

I was not able to replicate the issue in CLJ. cemerick.cljs.test/is macro is probably far more complex than original CLJ version in clojure.test/is.






[ASYNC-83] Taking from channels in anonymous functions inside go-loops does not work Created: 05/Aug/14  Updated: 05/Aug/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Knighton Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

latest core.async release, latest core.async built from source



 Description   

This seems to be related/comparable to the issue posted on this mailing-list thread:
https://groups.google.com/forum/#!topic/clojure/vtvk7warLE4

Minimal testcases to reproduce:

(def ch (chan))

(go-loop []
(>! ch "test"))

(go-loop []
(println (<! ch))) ;;prints "test"

(future (println (<!! ch))) ;;prints "test"

(future (println (#(<!! ch)))) ;;prints "test"

(go-loop []
(println (#(<! ch)))) ;;CompilerExpection java.lang.IllegalArgumentException:
;; No method in multimethod '-item-to-ssa' for dispatch
;; value :fn



 Comments   
Comment by Joel Knighton [ 05/Aug/14 12:41 PM ]

It appears the go-loop isn't even necessary -
(go (println (#(<! ch)))) reproduces the issue.

Comment by Kevin Downey [ 05/Aug/14 1:39 PM ]

I think this is expected behaviour, the go transformation macro doesn't attempt to descending in to called functions to transform their bodies, since their bodies are not transformed the <! and >! operators, which do not work in untransformed code, do not work.

the following which explicitly transforms the body of the inner function using the go macro should work:

(go (println (#(go (<! ch)))))

it will print out a channel though, because the result of (go ...) is a channel that will contain the result of ...

Comment by Joel Knighton [ 05/Aug/14 1:45 PM ]

Okay - thanks for the feedback. This doesn't cause an issue for me, and your explanation makes sense.





[ASYNC-61] Exceptions thrown inside go/thread blocks propagate up and out of ThreadPoolExcecutor Created: 24/Mar/14  Updated: 06/Aug/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Howard Lewis Ship Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: exceptions
Environment:

core.async 0.1.267.0-0d7780-alpha on JDK 1.7



 Description   

If a go or thread blocks throws an exception, there is nothing in Clojure to catch and handle (or report) the exception. Instead, it propagates up to the ThreadExcecutor which invokes its NO-OP afterExecute() method and is re-thrown, ultimately being displayed on the System.err:

Exception in thread "async-dispatch-32" java.lang.IllegalStateException: Fall down, go boom!
at flashiz.resources.orders$index.invoke(orders.clj:26)
at clojure.lang.Var.invoke(Var.java:411)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.core$apply.invoke(core.clj:617)
at io.aviso.rook$rook_dispatcher.invoke(rook.clj:225)
at flashiz.async$wrap_sync_handler$fn__9005.invoke(async.clj:34)
at flashiz.resources$authorize_async_rook_middleware$fn_9356$fn9402$state_machine3245auto__9403$fn_9405.invoke(resources.clj:21)
at flashiz.resources$authorize_async_rook_middleware$fn_9356$fn9402$state_machine3245auto___9403.invoke(resources.clj:21)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:945)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:949)
at clojure.core.async.impl.ioc_macros$take_BANG_$fn__3261.invoke(ioc_macros.clj:958)
at clojure.core.async.impl.channels.ManyToManyChannel$fn__2256.invoke(channels.clj:80)
at clojure.lang.AFn.run(AFn.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)

It would be nice if execution of the go/thread block was wrapped in an exception handler that delegated to a default function to report the exception. My goal is to be able to alter that function to report it more nicely and/or write it to a persistent log file.



 Comments   
Comment by Alex Miller [ 06/Aug/14 10:30 AM ]

Patches on ASYNC-76 have been applied and exceptions will now flow up to the top of the thread, where they can be caught by the standard Thread uncaught exception handler mechanism or ultimately by the default uncaught exception handler, which can be set for the application. There may still be further changes to support exception handling in thread/go.





[ASYNC-54] MAX-QUEUE-SIZE has a wrong type-hint Created: 11/Feb/14  Updated: 23/Jun/14

Status: Open
Project: core.async
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-Fix-MAX-QUEUE-SIZE-type-hint-def-evaluates-the-metad.patch    

 Description   

Since `def` evaluated the metadata on the symbol by design, primitive type hints needs to be quoted to avoid resolving to the homonimous clojure.core function



 Comments   
Comment by Alex Miller [ 23/Jun/14 3:22 PM ]

Actually, I think no hint is needed here at all and it should just be removed. Clojure will just inline a primitive long for the MAX-QUEUE-SIZE where it is used.





Generated at Wed Aug 20 05:59:45 CDT 2014 using JIRA 4.4#649-r158309.