Giter Site home page Giter Site logo

puniverse / pulsar Goto Github PK

View Code? Open in Web Editor NEW
906.0 51.0 54.0 3.93 MB

Fibers, Channels and Actors for Clojure

Home Page: http://docs.paralleluniverse.co/pulsar/

License: Other

Clojure 69.64% Java 29.77% Shell 0.59%
clojure fibers actors jvm concurrency

pulsar's Introduction

Pulsar
Fibers, Channels and Actors for Clojure

Build Status Dependency Status Version License License

Pulsar wraps the Quasar library with a Clojure API that's very similar to Erlang.

Requirements

Java 7 and up and Clojure 1.5 and up are required to run Pulsar.

Getting started

Add the following dependencies to Leiningen's project.clj:

[co.paralleluniverse/quasar-core "0.7.9"]
[co.paralleluniverse/pulsar "0.7.9"]

Then, the following must be added to the project.clj file:

:java-agents [[co.paralleluniverse/quasar-core "0.7.9"]]

or, add the following to the java command line:

-javaagent:path-to-quasar-jar.jar

Alternatively, to build Pulsar from the source, clone the repository and run:

lein midje

You can run the examples like this:

lein -o run -m co.paralleluniverse.pulsar.examples.pingpong

For benchmarks, you should use lein trampoline, like so:

lein trampoline run -m co.paralleluniverse.pulsar.examples.ring-benchmark 1000 1000

Usage

Documentation and examples can be found here.

You can also read the introductory blog post.

When running code that uses Pulsar, the instrumentation agent must be run by adding the following to the java command line or to the :jvm-opts section in project.clj:

-javaagent:path-to-quasar-jar.jar

Documentation

Community

Contributions (including Pull Requests)

Please have a look at some brief information for contributors.

License

Pulsar is free software published under the following license:

Copyright © 2013-2017 Parallel Universe

This program and the accompanying materials are dual-licensed under
either the terms of the Eclipse Public License v1.0 as published by
the Eclipse Foundation

  or (per the licensee's choosing)

under the terms of the GNU Lesser General Public License version 3.0
as published by the Free Software Foundation.

githalytics.com alpha

pulsar's People

Contributors

agis avatar alexandergunnarson avatar andreiursan avatar bmabey avatar calam1 avatar circlespainter avatar dimasalakhov avatar ekarlsso avatar ianbishop avatar joanis avatar jstepien avatar mhluongo avatar ordnungswidrig avatar piranha avatar pron avatar pubot avatar samstiles avatar stig avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pulsar's Issues

NPE when spawning "gen-server"-generated actor in a fiber; the "handle-call" method must containing a "receive" call

Against 2013/11/04 morning's 0.4.0-SNAPSHOT of quasar and pulsar:

java.lang.NullPointerException
    at co.paralleluniverse.fibers.JMXFibersMonitor.setRunawayFibers(JMXFibersMonitor.java:205)
    at co.paralleluniverse.fibers.FiberTimedScheduler.reportProblemFibers(FiberTimedScheduler.java:440)
    at co.paralleluniverse.fibers.FiberTimedScheduler.work(FiberTimedScheduler.java:137)
    at co.paralleluniverse.fibers.FiberTimedScheduler.access$000(FiberTimedScheduler.java:44)
    at co.paralleluniverse.fibers.FiberTimedScheduler$1.run(FiberTimedScheduler.java:76)
    at java.lang.Thread.run(Thread.java:744)

To reproduce, see test functions below, "test1-y" is the only one triggering the exception. Please note that there's no need to invoke the created actor to trigger the exception, it's just enough that the actor is spawn in a fiber and that the "handle-call" method contains a "receive" call.

(ns test-npe
  (:require
    [co.paralleluniverse.pulsar.core :as pc]
    [co.paralleluniverse.pulsar.actors :as pa]))

(defn test1-y []
  (let
      [fib
       (pc/spawn-fiber
         #(pa/spawn
           (pa/gen-server
             (reify pa/Server
               (handle-call [_ _ _ _] (pa/receive [x] x))))))]
    (pc/join fib)))

(defn test2-n []
  (let
      [fib
       (pc/spawn-fiber
         #(pa/spawn
           (pa/gen-server
             (reify pa/Server
               (handle-call [_ _ _ _])))))]
    (pc/join fib)))

(defn test3-n []
  (pa/spawn
    (pa/gen-server
      (reify pa/Server
        (handle-call [_ _ _ _] (pa/receive [x] x))))))

promise shadowed when requiring pulsar.actors

When loading this namespace to repl second time

(ns test
  (:refer-clojure :exclude [promise])
  (:require [co.paralleluniverse.pulsar.core :refer :all] :reload
            [co.paralleluniverse.pulsar.actors :as a] :reload))

I get following error:

IllegalStateException promise already refers to: #'co.paralleluniverse.pulsar.core/promise in namespace: co.paralleluniverse.pulsar.actors clojure.lang.Namespace.warnOrFailOnReplace (Namespace.java:88)

It looks like that the problem is in actors namespace where it is not declared that the promise is shadowed by pulsar.core's implementation.

I made pull request that fixes this for me at least
#13

Automatic instrumentation

Two questions about automatic instrumentation.

The first is with respect to this quote, from the documentation:

According to our benchmarks, the performance impact of automatic instrumentation should not exceed 20% in worst-case situations like articulated and math-intensive Clojure code, while in more common-case scenarios the slow-down should not be noticeable at all.

Are these benchmarks made available to the public? If so, where? And will this performance hit apply only when "math-intensive functions" (whatever that means with that level of generality, as math is ubiquitous in and essential to code of virtually any complexity) are actually executed, or is it a blanket hit, dragging down the performance ("up to 20%") of all components of a JVM containing this type of instrumented code?

The second is this: is it possible to do AOT automatic instrumentation in such a way that the performance hit is not incurred, or is it incurred because of inherent inefficiencies in the bytecode generated by automatic instrumentation?

Thanks for your help!

Spawning fn from other namespace doesn't work

Apologies for the vagueness of the title of this issue, but here's what's happening:

  1. create function in a namespace, e.g. n/f
  2. in a different namespace try to spawn this function, e.g. (a/spawn n/f)
  3. exception happens:
Exception in Fiber "fiber-10000001" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.ClassCastException: co.paralleluniverse.pulsar.actors$reify__6559 cannot be cast to clojure.lang.IFn
    at sliver.node$f.invoke(node.clj:203)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:213)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:200)
    at co.paralleluniverse.actors.PulsarActor.doRun(PulsarActor.java:92)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1024)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at sliver.node$f.invoke (node.clj:203) **
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke (ClojureHelper.java:213) (optimized)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run (ClojureHelper.java:200)
    at co.paralleluniverse.actors.PulsarActor.doRun (PulsarActor.java:92)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1024)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1019)
Exception in Fiber "fiber-10000001" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.ClassCastException: co.paralleluniverse.pulsar.actors$reify__6559 cannot be cast to clojure.lang.IFn
    at sliver.node$f.invoke(node.clj:203)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:213)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:200)
    at co.paralleluniverse.actors.PulsarActor.doRun(PulsarActor.java:92)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1024)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at sliver.node$f.invoke (node.clj:203) **
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke (ClojureHelper.java:213) (optimized)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run (ClojureHelper.java:200)
    at co.paralleluniverse.actors.PulsarActor.doRun (PulsarActor.java:92)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1024)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1019)

relevant bits of code:

  • project.clj:
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [co.paralleluniverse/pulsar "0.7.3"]]
  :java-agents [[co.paralleluniverse/quasar-core "0.7.3"]]
  • node.clj (namespace where actor stuff happens):
(ns sliver.node
  (:require [co.paralleluniverse.pulsar.actors :as a]))

(defn f [] (println (a/self)))
  • core.clj (namespace where spawning happens):
(ns sliver.core
  (:require [sliver.node :as n]
            [co.paralleluniverse.pulsar.actors :as a]))

(a/spawn n/f)

If this is a case of RTFM, that's great, please point me to the docs. If not, then :(

NullPointerException on ReentrantLock in fiber

When the second fiber in this example tries to lock the lock, there is a NullPointerException.

(ns lock-test
  (:import co.paralleluniverse.strands.concurrent.ReentrantLock)
  (:use clojure.tools.logging
        [co.paralleluniverse.pulsar.core :only [defsfn promise spawn-fiber]]))

(defsfn blocking [p lock]
  (.lockInterruptibly lock)
  (try
    (debug "locked")
    (deref p)
    (finally
      (.unlock lock)
      (debug "unlocked"))))

(def p (promise))

(def l (ReentrantLock.))

(def f1 (spawn-fiber (fn [] (debug (blocking p l)))))

(Thread/sleep 1000)

(def f2 (spawn-fiber (fn [] (debug (blocking p l)))))

yields:

Exception in Fiber "fiber-10000002" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.NullPointerException
    at co.paralleluniverse.strands.Strand.park(Strand.java:485)
    at co.paralleluniverse.strands.concurrent.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:838)
    at co.paralleluniverse.strands.concurrent.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:899)
    at co.paralleluniverse.strands.concurrent.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1231)
    at co.paralleluniverse.strands.concurrent.ReentrantLock.lockInterruptibly(ReentrantLock.java:339)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
    at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:313)
    at lock_test$blocking.invoke(form-init7720836874273720665.clj:2)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:40)
    at lock_test$fn__2075$fn__2076.invoke(form-init7720836874273720665.clj:1)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:185)
    at co.paralleluniverse.pulsar.ClojureHelper$3.run(ClojureHelper.java:172)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1003)

Turning on verifiyInstrumentation doesn't show anything and anyways I don't think it's an instrumentation problem. The line of code that NPE's curiously can't throw an NPE in theory:

            Fiber.park(blocker);

I traced it in the debugger and blocker is not null, not that it would matter. Must be something at the byte code level that's screwy.

Watching actors from a gen-server

My understanding is that a gen-server with a watch! on an actor should receive a message via it's handle-info when the watched actor terminates.

The following example is based on code from the tests and my expectation is that both actor2 and gs should receive messages indicating that actor1 has terminated.

On running, actor2 does indeed receive the exit, but gs does not receive anything.

(let [actor1 (spawn (fn [] (Fiber/sleep 2000)))
      actor2 (spawn (fn []
                      (let [w (watch! actor1)]
                        (receive
                            [:exit w actor reason] (println "actor2: got :exit")))))
      gs (spawn
          (gen-server (reify Server
                        (init [_]
                          (println "GS: init called")
                          (set-state! {:watch (watch! actor1)}))
                        (terminate [_ cause]
                          (println "GS: terminate called"))
                        (handle-info [_ message]
                          (println "GS: handle-info called")
                          (println message)))))
      gs-term (spawn (fn []
                       (Fiber/sleep 5000)
                       (println "Shutting down GS")
                       (shutdown! gs)))]
  (join actor1)
  (join actor2)
  (join gs)
  (join gs-term))

Help on this issue would be greatly appreciated.

Thank you.

Call! consumes others' exit messages

If actor1 is call!-ing a Server and observable acotr2 exits, then bad things happen.

Scenario1:
Actor1 watches Actor2 and traps lifetime events. Actor1 is calling Server1 and before Server1 responds, Actor2 exits.
In that case Actor1 will never know about Actor2's death, this message will be thrown away inside call's SelectiveReceiveHelper.

Scenario2:
Actor1 links Actor2 and traps lifetime events. Actor1 is calling Server1 and before Server1 responds, Actor2 exits.
In that case unhandled exception will leak outside and kill all humans. Here is a stack trace:

Exception in Fiber "fiber-10000007" co.paralleluniverse.actors.LifecycleException: ExitMessage{actor: ActorRef@5e007c49{PulsarActor@6e191ac8a713[owner: fiber-10000009]}, cause: null}
at co.paralleluniverse.actors.Actor.handleLifecycleMessage(Actor.java:755)
    at co.paralleluniverse.actors.PulsarActor.handleLifecycleMessage(PulsarActor.java:121)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.handleLifecycleMessage(SelectiveReceiveHelper.java:298)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper$1.handleLifecycleMessage(RequestReplyHelper.java:169)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(SelectiveReceiveHelper.java:121)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(RequestReplyHelper.java:174)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:102)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:80)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(actors.clj:669)

Here is a small working example:

(ns failzzz
  (require [co.paralleluniverse.pulsar.actors :refer :all]
           [clojure.core.match :refer [match]])
  (:import (co.paralleluniverse.strands Strand)))

(defn dodgy-server []
  (reify Server
    (init [this])
    (handle-call [this from id message]
      (match message
             [:ping actor2] (do (! actor2 [:headshot])
                                (Strand/sleep 5000)
                                "pong")))
    (terminate [this cause]
      (println "Terminating server"))))

(defn spawn-actor1 []
  (let [srv (spawn (gen-server (dodgy-server)))
        actor2 (spawn
                 (fn []
                   (receive m (println "I'm done here, exit"))))]
    (spawn :trap true
           (fn []
             (link! actor2)
             (loop []
               (let [m (receive)]
                 (match m
                        [:exit _ a reason] (println "Received exit")
                        m (do
                            (println (str "received message" m))
                            (println (str "called result "
                                          (call! srv [:ping actor2]))))))
               (recur))))))

(defn kaboom []
  (let [actor1 (spawn-actor1)]
    (! actor1 [:start])))

watch! fails when called from within a receive with an :else clause

Running with Clojure 1.8.0 and

[co.paralleluniverse/quasar-core "0.7.5"]
[co.paralleluniverse/pulsar "0.7.5"]

I have two actors setup like this:

(defsfn act1 []
        (receive [m]
                 [peer message] (do
                                  (println "got message " + message + " from peer " peer)
                                  (watch! peer))
                 [:exit w peer reason] (println "peer left" peer)
                 :else (println "got unhandled message " m))
        (recur))

(defsfn act2 [] (receive [m] :xx (println "bye") :else (do (println "got " m) (recur))))

Running this in nREPL:

(def a1 (spawn act1))
(def a2 (spawn act2))

(! a1 [a2 "hello])
(! a2 :xx)

The [:exit] clause never gets hit in act1. If I remove the :else clause, everything works as expected, i.e. the "peer left" message is being printed.

Cannot run the cluster ping/pong example

Running the cluster ping pong example either lead to:

WARNING: fiber Fiber@10000001:fiber-10000001[task: ParkableForkJoinTask@d758092(Fiber@10000001), target: co.paralleluniverse.actors.ActorRunner@65c19b15, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@30638489] is hogging the CPU or blocking a thread.

or (on the pong side)

WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.remote.galaxy.GlxGlobalRegistry.register(co.paralleluniverse.actors.Actor,co.paralleluniverse.actors.ActorRef) (GlxGlobalRegistry.java:89 bci: 779) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.actors.ActorRegistry.register (ActorRegistry.java:52 bci: 244)
    at co.paralleluniverse.actors.Actor.register (Actor.java:983 bci: 108)

followed by: (on the ping side)

14:31:42.092 [pool-8-thread-1]                     core.Cache [WARN ] {} TIMEOUT: Op.GET(line:3497f8, data:co.paralleluniverse.galaxy.core.StringRootManager$StringRootPageHandler@4da33907) 
14:31:42.095 [main]       galaxy.GlxGlobalRegistry [ERROR] {} Getting actor pong failed due to timeout 
Exception in thread "main" java.lang.RuntimeException: Actor discovery failed, compiling:(/private/var/folders/j0/cj4y4dyn5xjfcf9shts0d7tr0000gn/T/form-init8487154891595077328.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Actor discovery failed
    at co.paralleluniverse.remote.galaxy.GlxGlobalRegistry.getActor0(GlxGlobalRegistry.java:255)
    at co.paralleluniverse.remote.galaxy.GlxGlobalRegistry.getActor(GlxGlobalRegistry.java:156)
    at co.paralleluniverse.actors.ActorRegistry.getActor(ActorRegistry.java:83)
    at co.paralleluniverse.actors.ActorRegistry.getActor(ActorRegistry.java:93)
    at co.paralleluniverse.pulsar.actors$whereis.invoke(actors.clj:386)
    at co.paralleluniverse.pulsar.examples.cluster.ping$_main.invoke(ping.clj:18)
    at clojure.lang.Var.invoke(Var.java:375)
    at user$eval5.invoke(form-init8487154891595077328.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    ... 11 more

This using the peer.xml configuration .... with its different versions (server, no server, dumb server, zookeeper, jgroups ...).
I tried to run ping pong on the same machine, or two different machines.

Any idea on how to configure this to work ? I am not trying to tweak configurations, but just getting this to run.

Eventually, for the project I am working on, I would like to run pulsar actors on two different machines.

Pulsar fibers vs. core.async `go` blocks

I've done as extensive reading as I could find on this comparison (i.e., slim), but I still haven't found enough detail to satisfy my curiosity. My understanding is that fibers are instrumented in such a way to provide true "lightweight threads"/coroutines on the JVM, while go blocks are simply scheduled onto heavyweight threads in a lightweight way via an ExecutorService (really, a threadpool), but don't necessarily spawn new threads every time they're created. Both are able to be paused/parked, but do so in different ways. My understanding is based on this comment on StackOverflow from amalloy:

<!! ... would work fine if you don't mind having a Java thread sitting there doing nothing. ... [but] go blocks ... make logical processes much cheaper; to accomplish this, the go block rewrites the body of the block into a series of callbacks that are attached to the channel, so that internally a call to <! inside a go block gets turned into something like ... (take! c k) where k is a callback to the rest of the go block.

What is the performance advantage, if any, of fibers over core.async go blocks? Are there benchmarks available? What significant implementation differences have I missed? Intuitively, fibers seem more performant, but I may be quite wrong on that, especially given issue #64 that I just posted (part of which seeks clarification on the performance hit that automated instrumentation incurs).

Thanks for your help!

Messages appear not to be received in a case involving passing @self to a newly spawned actor right before (recur)

I may have come across a bug in a peculiar case I was trying to implement. Take a look at this expression:

(let [timer-fn (sfn [boss timeout msg]
                      (receive
                        :cancel nil
                        :after timeout (! boss msg)))
        print-actor (spawn #(do
                             (println (receive))
                             (spawn timer-fn @self 1000 :tick)
                             (recur)))]
    (! print-actor :tick))

This spawns a print-actor that continually prints the received message and spawns a timer actor which signals it after some time and dies. After setting the machine in motion in the last line you would expect print-actor to print :tick to the console in 1 second intervals, but this does not happen. From my investigation it seems that in this case the timer is spawned correctly and does send the message, only for some reason print-actor doesn't receive it.

java 8 support

Using this with Java 8 generates numerous "[quasar] ERROR: Unable to instrument ...". Does anyone know how to enable Java 8 support?

SupervisorActor has not been instrumented

I'm getting the following error when trying to use pulsar in a project that also includes elasticsearch as a dependency:

Exception in Fiber "fiber-10000001" java.lang.RuntimeException: co.paralleluniverse.fibers.SuspendExecution: Oops. Forgot to instrument a method...

When I run with instrumentation verification I get:

IllegalArgumentException Target class class co.paralleluniverse.actors.behaviors.SupervisorActor has not been instrumented. co.paralleluniverse.fibers.Fiber.verifyInstrumentedTarget (Fiber.java:244)

To trigger the exception I run a file that only has:

(ns pulsar-testing.core                                                                 
  (:require [co.paralleluniverse.pulsar.actors :as actors]))                                    

(actors/spawn (actors/supervisor :one-for-one (fn [] [])))

In a project that includes [org.elasticsearch/elasticsearch "1.3.0"], or any higher version of elasticsearch 1.3.x, in the project.clj. The exception does not occur with elasticsearch 1.2.x, or without elasticsearch at all, so I think there is some strange interaction between pulsar and newish versions of elasticsearch.

I've tested with pulsar version 0.6.1 and 0.7.0-SNAPSHOT, and both have the same behavior.

I'm happy to help track this down, just let me know what I can do.

pulsar/promise doesn't mimic clojure.core/promise

Pulsar's promises are different from clojure.core's promises:

clojure.core's promises can be delivered to multiple times. so you can e.g. create a promise once (def p (promise)) and repeatedly call e.g. (deliver p 42). only the first call will set the value to 42, subsequent calls with the same or different value have no effect whereas pulsar's promises throw an exception. however on clojure.core the return value is different. the first call to deliver will return the promise itself, the same way pulsar's promises do. subsequent calls return nil.

I don't know whether pulsar's promises are supposed to be an exact drop-in replacement for clojure.core's promises, but if they are to be, then there might be code out there that relies on the above behavior that needs to be respected.

I know my code relies on the multiple-delivery ability. it sort of makes 'deliver' idempotent, an important quality in functional programming. the different return values are not only not significant to me but seem to counter immutability principles, however there might be code out there that relies on them.

call! in gen-event handler

Not sure this is an issue or i am just using it in a wrong way, would be great to clarify this :)

Whenever i execute call! inside a handler of gen-event (EventSourceActor), it throws a NullPointerException at co.paralleluniverse.strands.Strand park

for example:

(def event-handler1 (spawn (gen-event (fn []
                                          (println "event handler 1 started"))
                                        (fn [cause]
                                          (println "event handelr 1 exited" {:cause cause})))))

(def server1 (spawn (gen-server (reify Server
                                    (init [_]
                                      (println "server1 started"))
                                    (handle-call [_ _ _ message]
                                      (do
                                        (println "server1 get message from handle call" {:message message})
                                        message))
                                    (handle-cast [_ _ _ message]
                                      (println "server1 get message from handle cast" {:message message}))))))

(def handler1 (fn [& args]
                  (println "handling event with handler1")
                  (call! server1 [:add 1])
                  (println "finished handling event with handler1")))


(add-handler! event-handler1 handler1)

(notify! event-handler1 [:go {}])

Exceptions:

Exception in Fiber "fiber-10000364" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.NullPointerException
    at co.paralleluniverse.strands.Strand.park(Strand.java:493)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)
    at co.paralleluniverse.actors.Mailbox.await(Mailbox.java:90)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(SelectiveReceiveHelper.java:145)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(RequestReplyHelper.java:174)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:102)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:80)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(actors.clj:669)
    at flow_manager.event_handler_test$handler1.doInvoke(form-init8243819381685639938.clj:3)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(actors.clj:720)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers(EventSourceActor.java:245)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage(EventSourceActor.java:225)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior(BehaviorActor.java:237)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:293)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:36)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1026)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.strands.Strand.park(java.lang.Object) (Strand.java:493 bci: 57)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(int) (ConditionSynchronizer.java:54 bci: 255)
    at co.paralleluniverse.actors.Mailbox.await(int) (Mailbox.java:90 bci: 99)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(long,java.util.concurrent.TimeUnit,co.paralleluniverse.actors.MessageProcessor) (SelectiveReceiveHelper.java:145 bci: 917)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(co.paralleluniverse.actors.ActorRef,co.paralleluniverse.actors.behaviors.RequestMessage,long,java.util.concurrent.TimeUnit) (RequestReplyHelper.java:174 bci: 663)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object,long,java.util.concurrent.TimeUnit) (Server.java:102 bci: 192)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object) (Server.java:80 bci: 274)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(java.lang.Object,java.lang.Object) (actors.clj:669 bci: 133)
    at flow_manager.event_handler_test$handler1.doInvoke(java.lang.Object) (form-init8243819381685639938.clj:3 bci: 200)
    at clojure.lang.RestFn.invoke (RestFn.java:408 bci: 50)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:36 bci: 5)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(java.lang.Object) (actors.clj:720 bci: 8) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers (EventSourceActor.java:245 bci: 81) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage (EventSourceActor.java:225 bci: 645) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior (BehaviorActor.java:237 bci: 137)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:293 bci: 122)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:36 bci: 1) (optimized)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691 bci: 222)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51 bci: 148)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1026 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1021 bci: 1)
Exception in Fiber "fiber-10000364" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.NullPointerException
    at co.paralleluniverse.strands.Strand.park(Strand.java:493)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)
    at co.paralleluniverse.actors.Mailbox.await(Mailbox.java:90)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(SelectiveReceiveHelper.java:145)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(RequestReplyHelper.java:174)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:102)
    at co.paralleluniverse.actors.behaviors.Server.call(Server.java:80)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(actors.clj:669)
    at flow_manager.event_handler_test$handler1.doInvoke(form-init8243819381685639938.clj:3)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(actors.clj:720)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers(EventSourceActor.java:245)
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage(EventSourceActor.java:225)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior(BehaviorActor.java:237)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:293)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:36)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1026)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack: 
    at co.paralleluniverse.strands.Strand.park(java.lang.Object) (Strand.java:493 bci: 57)
    at co.paralleluniverse.strands.ConditionSynchronizer.await(int) (ConditionSynchronizer.java:54 bci: 255)
    at co.paralleluniverse.actors.Mailbox.await(int) (Mailbox.java:90 bci: 99)
    at co.paralleluniverse.actors.SelectiveReceiveHelper.receive(long,java.util.concurrent.TimeUnit,co.paralleluniverse.actors.MessageProcessor) (SelectiveReceiveHelper.java:145 bci: 917)
    at co.paralleluniverse.actors.behaviors.RequestReplyHelper.call(co.paralleluniverse.actors.ActorRef,co.paralleluniverse.actors.behaviors.RequestMessage,long,java.util.concurrent.TimeUnit) (RequestReplyHelper.java:174 bci: 663)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object,long,java.util.concurrent.TimeUnit) (Server.java:102 bci: 192)
    at co.paralleluniverse.actors.behaviors.Server.call(java.lang.Object) (Server.java:80 bci: 274)
    at co.paralleluniverse.pulsar.actors$call_BANG_.invoke(java.lang.Object,java.lang.Object) (actors.clj:669 bci: 133)
    at flow_manager.event_handler_test$handler1.doInvoke(java.lang.Object) (form-init8243819381685639938.clj:3 bci: 200)
    at clojure.lang.RestFn.invoke (RestFn.java:408 bci: 50)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:36 bci: 5)
    at co.paralleluniverse.pulsar.actors.PulsarEventHandler.handleEvent(java.lang.Object) (actors.clj:720 bci: 8) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.notifyHandlers (EventSourceActor.java:245 bci: 81) **
    at co.paralleluniverse.actors.behaviors.EventSourceActor.handleMessage (EventSourceActor.java:225 bci: 645) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.actors.behaviors.BehaviorActor.behavior (BehaviorActor.java:237 bci: 137)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:293 bci: 122)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun (BehaviorActor.java:36 bci: 1) (optimized)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691 bci: 222)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51 bci: 148)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1026 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1021 bci: 1)

the way i dealt with it at the moment is wrapping the whole handler logic in a fiber and it works pretty well :)

Thanks!

(spawn-fiber #(rcv channel)) failing in the REPL

Entering the following in the REPL should return "got: 123" immediately:

; Example 1:
; With Pulsar 0.7.5
(def ch1 (channel))

(def fi1 (->> (spawn-fiber (fn one [ch] (rcv ch 10000 :ms)) ch1)
              (spawn-fiber (fn two [v] (str "got: " @v)))))

(snd ch1 123)
@fi1
;;=> "got: "

But when using Pulsar 0.7.5 @fi1 blocks until the 'rcv' times out. Though (snd ch1 123) does accept the value immediately/does not block, the rcv ch seems to never receive the value.

When I macroexpand one level and run:

; Example 2:
(def ch1 (channel))

(def fi1 (spawn-fiber (fn two [v] (str "got: " @v)) 
                      (spawn-fiber (fn one [ch] (rcv ch 10000 :ms)) ch1)))

(snd ch1 123)
@fi1
;;=> "got: 123"

I get the expected outcome: "got: 123". However if I enter the same four expressions again @fi1 blocks and I get "got: ".

If I then rename the channel the process works again:

(def ch2 (channel))

(def fi1 (spawn-fiber (fn two [v] (str "got: " @v)) 
                      (spawn-fiber (fn one [ch] (rcv ch 10000 :ms)) ch2)))

(snd ch2 123)
@fi1
;;=> "got: 123"

But I can only run this once per channel name. (This seems related to #60)

Running the following code always succeeds (in Pulsar 0.7.5 and 0.7.6) - I can enter it repeatedly in the REPL and it shows the same expected outcome:

; With Pulsar 0.7.5 or 0.7.6
(def ch1 (channel))

(def fi3 (let [fi1 (spawn-fiber #(rcv % 10000 :ms) ch1)
               fi2 (spawn-fiber #(str "got: " @%) fi1)]
           fi2))

(snd ch1 123)
@fi3
;;=> "got: 123"

With Pulsar 0.7.6 this succeeds in the first run:

; Example 1 (first run):
; With Pulsar 0.7.6
(def ch1 (channel))

(def fi1 (->> (spawn-fiber (fn one [ch] (rcv ch 10000 :ms)) ch1)
              (spawn-fiber (fn two [v] (str "got: " @v)))))

(snd ch1 123)
@fi1
;;=> "got: 123"

Also the second example succeeds as it did with Pulsar 0.7.5:

; Example 2 (first run):
; With Pulsar 0.7.6
(def ch1 (channel))

(def fi1 (spawn-fiber (fn two [v] (str "got: " @v)) 
                      (spawn-fiber (fn one [ch] (rcv ch 10000 :ms)) ch1)))

(snd ch1 123)
@fi1
;;=> "got: 123"

But entering example 1 or example 2 a second time will fail as it did with 0.7.5.
Curiously, renaming the channel does not help with 0.7.6 as it did with 0.7.5:

; Example 2 (nth run):
; With Pulsar 0.7.6
(def ch2 (channel))

(def fi1 (spawn-fiber (fn two [v] (str "got: " @v)) 
                      (spawn-fiber (fn one [ch] (rcv ch 10000 :ms)) ch2)))

(snd ch2 123)
@fi1
;;=> "got: "

(Note: I'm currently preferring 0.7.5 as 0.7.6 seems to increase REPL startup time significantly in mid-sized projects. I could document this in a separate issue if it helps)

Need better doc of "FlightRecorder" mode...

While searching for a CSP library that can log all (Channel-)Events for monitoring/analysis (think of things like FDR model checker),
I stumbled upon some logging in Pulsar by ways of a flightrecorder (?)

Can you make some documentation of this feature availale ?
Will it give me:

  • on what Channel happened what Send / Receive of which Object/Data at which Time ?

That would be a great analysis/debugging feature !

Best,
Joerg

`Deref clojure.core/promise` in fiber outputs stream of warnings

Derefing a clojure.core/promise in a fiber

(def p1 (clojure.core/promise))
(def f1 (fiber (deref p1)))

starts outputting this warning repeatedly:

WARNING: fiber Fiber@10000050:fiber-10000050[task: ParkableForkJoinTask@71e54873(Fiber@10000050), target: co.paralleluniverse.pulsar.ClojureHelper$4@4010beaf, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@23eede1b] is blocking a thread (Thread[ForkJoinPool-default-fiber-pool-worker-5,5,main]).
        at sun.misc.Unsafe.park(Native Method)
        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__7005.deref(core.clj:6823)
        at clojure.core$deref.invokeStatic(core.clj:2228)
        at clojure.core$deref.invoke(core.clj:2214)
        at rt_comm.connect_auth$fn__44050$fn__44051.invoke(connect_auth.clj:175)
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
        at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:218)
        at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:205)
        at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1072)
...

until the promise is resolved:

(deliver p1 123)
(join f1)
> 123

I have the same situation when using a manifold/deferred:

(def d1 (manifold.deferred/deferred))
(def f1 (fiber (deref d1)))

This starts printing a stream of similar warnings:

WARNING: fiber Fiber@10000034:fiber-10000034[task: ParkableForkJoinTask@5398e323(Fiber@10000034), target: co.paralleluniverse.pulsar.ClojureHelper$4@726f386b, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@23eede1b] is blocking a thread (Thread[ForkJoinPool-default-fiber-pool-worker-5,5,main]).
        at sun.misc.Unsafe.park(Native Method)
        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 manifold.deferred.Deferred.deref(deferred.clj:439)
        at clojure.core$deref.invokeStatic(core.clj:2228)
        at clojure.core$deref.invoke(core.clj:2214)
        at rt_comm.connect_auth$eval43600$fn__43601.invoke(connect_auth.clj:175)
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
        at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:218)
        at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:205)
        at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1072)

While the fiber still returns the resolved value just fine:

(d/success! d1 123)
(join f1)
> 123

Using Pulsar and Manifold in conjunction would allow to use Pulsar with Aleph effectively and would allow to combine the strengths of Pulsars promises with Manifolds features.

E.g. this works fine already:

(def p1 (pulsar.core/promise))

(def r1 (-> (p/promise #(inc @p1))
            (d/chain inc #(/ 1 %))
            (d/catch (fn [e] :err))))

(deliver p1 -2)
(deref r1)
> :err

But using (def p1 (clojure.core/promise)) or (def p1 (manifold.dererred/dererred)) instead of (def p1 (pulsar.core/promise)) will produce a stream of warnings, e.g. (def p1 (clojure.core/promise)) produces this warning:

WARNING: fiber Fiber@10000055:fiber-10000055[task: ParkableForkJoinTask@75d03a22(Fiber@10000055), target: co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable@39043fc3, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@23eede1b] is blocking a thread (Thread[ForkJoinPool-default-fiber-pool-worker-5,5,main]).
        at sun.misc.Unsafe.park(Native Method)
        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__7005.deref(core.clj:6823)
        at clojure.core$deref.invokeStatic(core.clj:2228)
        at clojure.core$deref.invoke(core.clj:2214)
        at rt_comm.connect_auth$fn__44181.invokeStatic(connect_auth.clj:195)
        at rt_comm.connect_auth$fn__44181.invoke(connect_auth.clj:195)
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
        at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:218)
        at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:205)
        at co.paralleluniverse.strands.dataflow.Val$1.run(Val.java:68)
        at co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable.run(SuspendableUtils.java:44)
        at co.paralleluniverse.strands.SuspendableUtils$VoidSuspendableCallable.run(SuspendableUtils.java:32)
        at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1072)

Exception when running skynet example

Here's my skynet example:

(ns skynet.main
  (:require
   [co.paralleluniverse.pulsar
    [core :refer :all]
    [actors :refer :all]])
  (:refer-clojure :exclude [promise await])
  (:gen-class))


(declare skynet)

(defsfn subnet [num size div]
  (loop [i 0
         children []]
    (if (= i div)
        children
        (recur
          (+ i 1)
          (conj children (fiber (skynet (int (+ num (* i (/ size div))))  ;;fiber blows up
                                        (int (/ size div))
                                        div)))
            ))))

(defsfn skynet [num size div]
  ;;(print (str "skynet " num "|" size "|" div "\n"))
  (if (= size 1)
      num
      (let [res (subnet num size div)
            joined (join res)]
        (->> res            
             join              ;;comment if not fiber
             (reduce +)))
      ))

(defn -main []
  (println (skynet 0 100 10)))

If I remove the fiber creation and the join call the code works, but using fibers I get a NPE exception somewhere. I'm a clojure newbie so I may be doing something wrong, but I cannot see where.
Here's the stack:

Exception in thread "main" java.lang.NullPointerException, compiling:(/tmp/form-init2436751602057577490.clj:1:7[17/8407]
        at clojure.lang.Compiler.load(Compiler.java:7391)
        at clojure.lang.Compiler.loadFile(Compiler.java:7317)
        at clojure.main$load_script.invokeStatic(main.clj:275)
        at clojure.main$init_opt.invokeStatic(main.clj:277)
        at clojure.main$init_opt.invoke(main.clj:277)
        at clojure.main$initialize.invokeStatic(main.clj:308)
        at clojure.main$null_opt.invokeStatic(main.clj:342)
        at clojure.main$null_opt.invoke(main.clj:339)
        at clojure.main$main.invokeStatic(main.clj:421)
        at clojure.main$main.doInvoke(main.clj:384)
        at clojure.lang.RestFn.invoke(RestFn.java:421)
        at clojure.lang.Var.invoke(Var.java:383)
        at clojure.lang.AFn.applyToHelper(AFn.java:156)
        at clojure.lang.Var.applyTo(Var.java:700)
        at clojure.main.main(main.java:37)
Caused by: java.lang.NullPointerException
        at co.paralleluniverse.strands.Strand.park(Strand.java:493)
        at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)
        at co.paralleluniverse.strands.dataflow.Val.get(Val.java:154)
        at co.paralleluniverse.fibers.Fiber.get(Fiber.java:1315)
        at co.paralleluniverse.pulsar.core$join_STAR_.invokeStatic(core.clj:434)
        at co.paralleluniverse.pulsar.core$join_STAR_.invoke(core.clj:430)
        at co.paralleluniverse.pulsar.core$join.invokeStatic(core.clj:468)
        at co.paralleluniverse.pulsar.core$join.invoke(core.clj:450)
        at clojure.core$map$fn__4785.invoke(core.clj:2644)
        at clojure.lang.LazySeq.sval(LazySeq.java:40)
        at clojure.lang.LazySeq.seq(LazySeq.java:49)
        at clojure.lang.RT.seq(RT.java:521)
        at clojure.core$seq__4357.invokeStatic(core.clj:137)
        at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:24)
        at clojure.core.protocols$fn__6738.invokeStatic(protocols.clj:75)
        at clojure.core.protocols$fn__6738.invoke(protocols.clj:75)
        at clojure.core.protocols$fn__6684$G__6679__6697.invoke(protocols.clj:13)
        at clojure.core$reduce.invokeStatic(core.clj:6541)
        at clojure.core$reduce.invoke(core.clj:6527)
        at skynet.main$skynet.invokeStatic(main.clj:26)
        at skynet.main$skynet.invoke(main.clj:10)
        at skynet.main$skynet$fn__7297$fn__7298.invoke(main.clj:19)
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
        at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:213)
        at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:200)
        at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1027)
        at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1022)
        at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:732)
        at co.paralleluniverse.fibers.FiberForkJoinScheduler$FiberForkJoinTask.exec1(FiberForkJoinScheduler.java:265)
        at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.doExec(ParkableForkJoinTask.java:117)
        at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.exec(ParkableForkJoinTask.java:74)
        at jsr166e.ForkJoinTask.doExec(ForkJoinTask.java:261)
        at jsr166e.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:988)
        at jsr166e.ForkJoinPool.runWorker(ForkJoinPool.java:1628)
        at jsr166e.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

Class JavaLaunchHelper is implemented in both .../java and .../libinstrument.dylib

When adding the quasar-core Java agent to my project.clj I get this warning when running Leiningen:

% lein repl
objc[4600]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.

This is my project.clj:

(defproject pulsar-toy "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.7.0"]
                 [co.paralleluniverse/quasar-core "0.7.3"]
                 [co.paralleluniverse/pulsar "0.7.3"]
                 [org.clojure/tools.logging "0.3.1"]
                 [org.slf4j/slf4j-log4j12 "1.7.12"]
                 [log4j/log4j "1.2.17"]]

  :main ^:skip-aot pulsar-toy.core
  :target-path "target/%s"
  :java-agents [[co.paralleluniverse/quasar-core "0.7.3"]])

can a fiber be blocked?

Hi!!...sorry for the super noob question..but I was recently reading this article

http://martintrojer.github.io/clojure/2013/07/07/coreasync-and-blocking-io/

seems than clojure core.async go blocks can be blocked and I would need use threads and a thread pool, this is not optimal...in a comment (I don't know if who comment works for paralleluniverse) says than fiber hasn't that problem, is it true?...

I try replicate the code but I get almost the same result than using cor async and this warning

WARNING: fiber Fiber@10000028[task: ParkableForkJoinTask@176cd783(Fiber@10000028), target: co.paralleluniverse.pulsar.ClojureHelper$3@3592b423, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@6d25f36b] is hogging the CPU or blocking a thread.
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at org.apache.http.impl.io.AbstractSessionInputBuffer.read(AbstractSessionInputBuffer.java:198)
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:178)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:137)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at clj_http.core.proxy$java.io.FilterInputStream$ff19274a.read(Unknown Source)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at clj_http.core.proxy$java.io.FilterInputStream$ff19274a.read(Unknown Source)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1792)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:462)
at clj_http.util$force_byte_array.invoke(util.clj:63)
at clj_http.client$eval11476$fn__11479.invoke(client.clj:386)
at clojure.lang.MultiFn.invoke(MultiFn.java:231)
at clj_http.client$wrap_output_coercion$fn__11484.invoke(client.clj:400)
at clj_http.client$wrap_exceptions$fn__11327.invoke(client.clj:164)
at clj_http.client$wrap_accept$fn__11524.invoke(client.clj:522)
at clj_http.client$wrap_accept_encoding$fn__11530.invoke(client.clj:536)
at clj_http.client$wrap_content_type$fn__11519.invoke(client.clj:512)
at clj_http.client$wrap_form_params$fn__11610.invoke(client.clj:683)
at clj_http.client$wrap_nested_params$fn__11627.invoke(client.clj:707)
at clj_http.client$wrap_method$fn__11570.invoke(client.clj:624)
at clj_http.cookies$wrap_cookies$fn__7993.invoke(cookies.clj:122)
at clj_http.links$wrap_links$fn__9872.invoke(links.clj:50)
at clj_http.client$wrap_unknown_host$fn__11635.invoke(client.clj:726)
at clj_http.client$get.doInvoke(client.clj:829)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at alepthbenchmark.bmch$blocking_get.invoke(form-init7142513807440439850.clj:2)
at alepthbenchmark.bmch$eval11770$fn__11775.invoke(form-init7142513807440439850.clj:6)
at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
at co.paralleluniverse.pulsar.async$f__GT_chan$fn__7817$fn__7818.invoke(async.clj:213)
at co.paralleluniverse.pulsar.async$f__GT_chan$fn__7817.invoke(async.clj:213)
at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:185)
at co.paralleluniverse.pulsar.ClojureHelper$3.run(ClojureHelper.java:172)
at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1003)

do you have any benchmark of clojure core.async with respect to the paralleluniverse implementation?...

NullPointerException on channel receive

I believe we've found a race condition that is triggered by invoking core/rcv on the channel returned by a Pulsar async/thread. When iterating through a large list of channels and invoking rcv on them we occasionally see NullPointerException raised by rcv. If we slow down the rate at which we map rcv on the list we don't see the exception. The channels is the list are the output of Pulsar's async/thread method, and as far we can tell totally uniform. We are executing rcv inside of a Pulsar actor.

I've included the stack trace:

18268 [ForkJoinPool-default-fiber-pool-worker-29] INFO co.paralleluniverse.actors.behaviors.ServerActor - Exception! 
java.lang.NullPointerException                                                                                       
        at co.paralleluniverse.strands.Strand.park(Strand.java:485)                                                  
        at co.paralleluniverse.strands.ConditionSynchronizer.await(ConditionSynchronizer.java:54)                    
        at co.paralleluniverse.strands.channels.QueueChannel.receive(QueueChannel.java:342)                          
        at co.paralleluniverse.pulsar.core$rcv.invoke(core.clj:584)                                                  
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)                                
        at elasticsearch_loader.elasticsearch$check_for_bulk_response_error.invoke(elasticsearch.clj:207)            
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)                                
        at clojure.core$map$fn__4245.invoke(core.clj:2557)                                                           
        at clojure.lang.LazySeq.sval(LazySeq.java:40)                                                                
        at clojure.lang.LazySeq.seq(LazySeq.java:49)                                                                 
        at clojure.lang.RT.seq(RT.java:484)                                                                          
        at clojure.core$seq.invoke(core.clj:133)                                                                     
        at clojure.core$apply.invoke(core.clj:624)                                                                   
        at clojure.core$mapcat.doInvoke(core.clj:2586)                                                               
        at clojure.lang.RestFn.invoke(RestFn.java:423)                                                               
        at elasticsearch_loader.elasticsearch$wait_for_bulk_responses.invoke(elasticsearch.clj:218)                  
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)                                
        at elasticsearch_loader.merchant_actor$stop_reload_BANG_.invoke(merchant_actor.clj:88)                       
        at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)                                
        at elasticsearch_loader.merchant_actor$merchant_actor$reify__8248.handle_cast(merchant_actor.clj:154)        
        at co.paralleluniverse.pulsar.actors$Server$reify__2666.handleCast(actors.clj:618)                           
        at co.paralleluniverse.actors.behaviors.ServerActor.handleCast(ServerActor.java:325)                         
        at co.paralleluniverse.actors.behaviors.ServerActor.handleMessage(ServerActor.java:220)                      
        at co.paralleluniverse.actors.behaviors.ServerActor.behavior(ServerActor.java:194)                           
        at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:286)                          
        at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:34)                           
        at co.paralleluniverse.actors.Actor.run0(Actor.java:667)                                                     
        at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)                                           
        at co.paralleluniverse.actors.Actor.run(Actor.java:236)                                                      
        at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1003)                                                     
        at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:998)                                                     
        at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:710)                                                     
        at co.paralleluniverse.fibers.FiberForkJoinScheduler$FiberForkJoinTask.exec1(FiberForkJoinScheduler.java:248)
        at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.doExec(ParkableForkJoinTask.java:116)        
        at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.exec(ParkableForkJoinTask.java:73)           
        at jsr166e.ForkJoinTask.doExec(ForkJoinTask.java:261)                                                        
        at jsr166e.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:988)                                             
        at jsr166e.ForkJoinPool.runWorker(ForkJoinPool.java:1628)                                                    
        at jsr166e.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

Unfortunately we've yet to be able to reproduce the issue on anything less then our full project. Any suggestions welcome.

Thanks!

Clojure 1.8 Upgrade

I recently tried upgrading my pulsar application to clojure 1.8 with no success.

This is the new stack trace I'm seeing when running 1.8 (this error does not happen when running 1.7)

                                        jsr166e.ForkJoinWorkerThread.run    ForkJoinWorkerThread.java:  107
                                           jsr166e.ForkJoinPool.runWorker            ForkJoinPool.java: 1628
                                   jsr166e.ForkJoinPool$WorkQueue.runTask            ForkJoinPool.java:  988
                                              jsr166e.ForkJoinTask.doExec            ForkJoinTask.java:  261
        co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.exec    ParkableForkJoinTask.java:   73
      co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.doExec    ParkableForkJoinTask.java:  116
co.paralleluniverse.fibers.FiberForkJoinScheduler$FiberForkJoinTask.exec1  FiberForkJoinScheduler.java:  265
                                    co.paralleluniverse.fibers.Fiber.exec                   Fiber.java:  730
                                    co.paralleluniverse.fibers.Fiber.run1                   Fiber.java: 1019
                                     co.paralleluniverse.fibers.Fiber.run                   Fiber.java: 1024
                           co.paralleluniverse.pulsar.ClojureHelper$4.run           ClojureHelper.java:  200
               co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke           ClojureHelper.java:  213
                        co.paralleluniverse.pulsar.InstrumentedIFn.invoke         InstrumentedIFn.java:   32
                              co.paralleluniverse.pulsar.async/f->chan/fn                    async.clj:  306
                           co.paralleluniverse.pulsar.async/f->chan/fn/fn                    async.clj:  306
                        co.paralleluniverse.pulsar.InstrumentedIFn.invoke         InstrumentedIFn.java:   32
                           myapp.handlers.matcher/kick-off-interaction/fn                  matcher.clj:   79
                            myapp.handlers.matcher/match-dispatch-mapping                  matcher.clj:   42
                        myapp.matcher/match-dispatch-mapping/invokeStatic                  matcher.clj:   49
                        co.paralleluniverse.pulsar.InstrumentedIFn.invoke         InstrumentedIFn.java:   40
                                  co.paralleluniverse.pulsar.actors/call!                   actors.clj:  665
                     co.paralleluniverse.pulsar.actors/call!/invokeStatic                   actors.clj:  669
                         co.paralleluniverse.actors.behaviors.Server.call                  Server.java:   80
                         co.paralleluniverse.actors.behaviors.Server.call                  Server.java:  102
             co.paralleluniverse.actors.behaviors.RequestReplyHelper.call      RequestReplyHelper.java:  174
                co.paralleluniverse.actors.SelectiveReceiveHelper.receive  SelectiveReceiveHelper.java:  141
                                 co.paralleluniverse.actors.Mailbox.await                 Mailbox.java:   90
                  co.paralleluniverse.strands.ConditionSynchronizer.await   ConditionSynchronizer.java:   54
                                  co.paralleluniverse.strands.Strand.park                  Strand.java:  493
java.lang.NullPointerException:

This is a pretty printed exception (so it goes backwards which the top of the stack at the bottom).
The stack leaves my code in on matcher.clj: 49 which is a call! to a gen-server.

We have auto instrumentation turned on. This error happens with both pulsar 0.7.3 and 0.7.4

Any insights would be great.

Exception: "co.paralleluniverse.actors.behaviors.ServerActor cannot be cast to co.paralleluniverse.actors.PulsarActor" when "receive" gets called in "handle-call" ("gen-server"-produced actor)

I can't remember reading about it not being allowed (but I might have overlooked), Happens against current pulsar 0.4.0-SNAPSHOT in maven repos, quasar from local build (yesterday afternoon's 0.4.0-SNAPSHOT).

Code to reproduce it:

(ns test-receive-in-server
  (:require
    [co.paralleluniverse.pulsar.core :as pc]
    [co.paralleluniverse.pulsar.actors :as pa]))

(defn -main []
  (let
      [act
       (pa/spawn
         (pa/gen-server
           (reify pa/Server
             (init [_])
             (handle-call [self from id msg] (pa/receive [x] x)))))]
    (pa/call! act "msg")))

Full exception:

Exception in thread "main" java.lang.ClassCastException: co.paralleluniverse.actors.behaviors.ServerActor cannot be cast to co.paralleluniverse.actors.PulsarActor
    at co.paralleluniverse.actors.PulsarActor.currentActor(PulsarActor.java:39)
    at test_receive_in_server$_main$reify__1899.handle_call(test_receive_in_server.clj:13)
    at co.paralleluniverse.pulsar.actors$Server$reify__1827.handleCall(actors.clj:580)
    at co.paralleluniverse.actors.behaviors.ServerActor.handleCall(ServerActor.java:269)
    at co.paralleluniverse.actors.behaviors.ServerActor.handleMessage(ServerActor.java:209)
    at co.paralleluniverse.actors.behaviors.ServerActor.behavior(ServerActor.java:192)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:275)
    at co.paralleluniverse.actors.behaviors.BehaviorActor.doRun(BehaviorActor.java:33)
    at co.paralleluniverse.actors.Actor.run(Actor.java:571)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:905)
    at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:900)
    at co.paralleluniverse.fibers.Fiber.exec1(Fiber.java:659)
    at co.paralleluniverse.fibers.Fiber.access$100(Fiber.java:64)
    at co.paralleluniverse.fibers.Fiber$FiberForkJoinTask.exec1(Fiber.java:1428)
    at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.doExec(ParkableForkJoinTask.java:107)
    at co.paralleluniverse.concurrent.forkjoin.ParkableForkJoinTask.exec(ParkableForkJoinTask.java:69)
    at co.paralleluniverse.fibers.Fiber$FiberForkJoinTask.exec(Fiber.java:1502)
    at jsr166e.ForkJoinTask.doExec(ForkJoinTask.java:261)
    at jsr166e.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:988)
    at jsr166e.ForkJoinPool.runWorker(ForkJoinPool.java:1628)
    at jsr166e.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

Expose sleep function un core namespace.

It would be nice to have sleep function or core.async timeout function in core namespace.

Is there any reason that core ns should not have function like this?

Thanks!
Andrey

`spawn` not marking functions as suspendable

Hi,

A call like (spawn foo) will mark foo as suspendable (as in (suspendable! foo)), but a call like (spawn foo arg1 arg2) will not. To test:

a) create a new pulsar project (here is a gist: https://gist.github.com/hsgrott/258e419db4a6ea31f76e)
b) run a REPL;
c) call (suspendable? ping) and (suspendable? pong) in the main ns; both should return false;
d) call (main); the function should hang with "Pong received ping" in the standard output;
f) break the execution, call (suspendable? ping) and (suspendable? pong); the first should return false, the last should return true;

Additionally, calling (suspendable! ping) will make things work as expected.

The code was tested with Clojure 1.7.0 (Java 1.8.0_66-b17) and Pulsar 0.7.3 on an Ubuntu 15.10 machine (Linux 4.2.0-18-generic #22-Ubuntu SMP x86_64).

Regards.

Problems with defsfn

I was running in the REPL some examples derived from this post:

http://yogthos.net/posts/2015-06-17-Using-Pulsar.html

Problem is, every time I redefined one of the suspendable functions (the ones created with defsfn), the -main method would hang, no matter which method was used (clojure.tools.namespace.repl/refresh, using CIDER commands, etc).

I've looked into the definition of the defsfn macro, and found the following:

(defmacro defsfn
  "Defines a suspendable function that can be used by a fiber or actor.
  Used exactly like `defn`"
  [& expr]
  `(do
     (defn ~@expr)
     (def ~(first expr) (suspendable! ~(first expr)))))

It seems that there is some kind of weird bug/interaction going on (or maybe I'm extremely unlucky :D). Anyways, here is an alternative version that seems to correct the problem:

(defmacro defsfnp
  "Walks through a 'defn' macroexpansion and wraps the generated fn* in
  a 'suspendable!' call." 
  [& expr]
  (-> (cons 'defn expr)
      walk/macroexpand-all
      zip/seq-zip
      zip/down
      zip/rightmost
      (zip/edit (fn [loc] `(suspendable! ~loc)))
      zip/root))

It might be a good idea to look up the actual fn* node instead of using zip/rightmost to make this macro more robust, but that is left as an exercise to the reader.

The code was tested in an Ubuntu 15.10 machine (Linux 4.2.0-18-generic #22-Ubuntu SMPx86_64 x86_64 x86_64 GNU/Linux) and a Mac using OSX El Capitan, both running JDK 1.8.0_66-b17, Clojure 1.7.0, pulsar 0.7.3 and quasar-core 0.7.3, with the same results.

Here is a gist with a sample project.clj, a sample test file and a bunch of tests adapted from the "def" tests in the main clojure repo:

https://gist.github.com/anonymous/dc9f501e8c52b3a7166c

I hope it helps.

priority.clj example fails

I am running the priority.clj example, and when I run main I get the following error. Unfortunately I cannot make any sense of this as far as rectifying it.

I am running clojure 1.6.0, Thanks for any feedback!

pulsar-tutorial.priority> (-main)
IllegalMonitorStateException attempt by Fiber@10000011[task: ParkableForkJoinTask@3c4ecbf(Fiber@10000011), target: co.paralleluniverse.actors.PulsarActor@7592f187, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@29e2b917] but owned by Fiber@10000011[task: ParkableForkJoinTask@3c4ecbf(Fiber@10000011), target: co.paralleluniverse.actors.PulsarActor@7592f187, scheduler: co.paralleluniverse.fibers.FiberForkJoinScheduler@29e2b917] co.paralleluniverse.strands.OwnedSynchronizer.register (OwnedSynchronizer.java:36)

NPE when blocking in reduce fn (even with auto instrument)

If making a blocking call in a reduce (or map) a NPE exception is thrown.
Even with auto instrumentation turned on we are unable to instrument the reduce.

Here is a snippit which reproduces the issue:

(ns actors.test
  (:refer-clojure :exclude [promise await])
  (:require [co.paralleluniverse.pulsar
             [core :refer :all]
             [actors :refer :all]]))

(defsfn action-fn []
  (reduce (fn [acc v]
            (conj acc (join (fiber (inc v)))))
          [] (range 20)))

(defn start-test []
  (join (fiber (action-fn))))

I'm using JDK8 and clojure 1.7.0-RC2 with pulsar 0.7.1-SNAPSHOT

ClassNotFoundException: co.paralleluniverse.fibers.SuspendExecution

I created an empty leiningen project with pulsar, but any attempt to load the REPL or load the environment in any way (there's no code except for lein boilerplate), result in the following exception:

$ lein repl
Exception in thread "main" java.lang.NoClassDefFoundError: co/paralleluniverse/fibers/SuspendExecution
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:186)
    at clojure.core_proxy__init.load(Unknown Source)
    at clojure.core_proxy__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at clojure.lang.RT.loadClassForName(RT.java:2098)
    at clojure.lang.RT.load(RT.java:430)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5018.invoke(core.clj:5530)
    at clojure.core$load.doInvoke(core.clj:5529)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core__init.load(Unknown Source)
    at clojure.core__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at clojure.lang.RT.loadClassForName(RT.java:2098)
    at clojure.lang.RT.load(RT.java:430)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.lang.RT.doInit(RT.java:447)
    at clojure.lang.RT.<clinit>(RT.java:329)
    at clojure.main.<clinit>(main.java:20)
Caused by: java.lang.ClassNotFoundException: co.paralleluniverse.fibers.SuspendExecution
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 22 more

Here's more info about my system. The OS is OS X 10.9.2.

$ lein version
Leiningen 2.3.4 on Java 1.7.0_09 Java HotSpot(TM) 64-Bit Server VM

$ java -version
java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)

$ cat project.clj
(defproject pulsar-text "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
                :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]
                           [co.paralleluniverse/pulsar "0.5.0"]]
  :java-agents [[co.paralleluniverse/quasar-core "0.5.0"]])

I tried removing ~/.m2 dir, it didn't help. Tried reproducing it on a Linux system with OpenJDK, but same sample project worked fine. Here's some info about the Linux system (plain Ubuntu VM on DigitalOcean):

$ lein version
Leiningen 2.3.4 on Java 1.7.0_55 OpenJDK 64-Bit Server VM

$ uname -a
Linux bs-bench-ny 3.8.0-29-generic #42~precise1-Ubuntu SMP Wed Aug 14 16:19:23 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Any ideas?

Thanks!

supervisor does not appear to handle gen-server crashing

I'm trying to get a handle on the supervisor in pulsar and running into an issue when using it to manage gen-servers.

The supervisor does not appear to do anything if the gen-server throws an exception in the init.

The gen-server code is as follows:

(defn test-gen-server
  [name]
  (gen-server
   (reify Server
     (init [_]
       (println "Starting Server...")
       ;; Intentionally crash the gen-server
       (throw (Exception. "Blah"))
       (register! name @self)
       (println "Started Server."))
     (terminate [_ cause]
       (println "Stopping Server...")
       (unregister! @self)
       (println "Stopped Server."))
     (handle-call [_ from id [command param]]
       ))))

And I'm launching it as follows:

(defn run-server-via-supervisor
  []
  (spawn
   (supervisor "entry-point" :one-for-one
               (fn []
                 [["test/test-server" :permanent 20 5 :sec 100
                   (test-gen-server "test/test-server")]]))))

Running it produces:

> (run-server-via-supervisor)
#object[co.paralleluniverse.actors.behaviors.Supervisor 0x41f14811 "Supervisor{ActorRef@41f14811{SupervisorActor@entry-point[owner: entry-point]}}"]
Starting Server...
Stopping Server...
Stopped Server.

It does not appear that the supervisor is attempting the 20 restarts as indicated in the spec.

Additionally the output is identical to simply spawning the gen-server directly.

> (spawn (test-gen-server "test/test-server"))
#object[co.paralleluniverse.actors.behaviors.Server 0x129ff808 "Server{ActorRef@129ff808{ServerActor@6becac41[owner: fiber-10000007]}}"]
Starting Server... 
Stopping Server...
Stopped Server.

I've attached a minimum test project for reference — pulsar-test.zip

Please let me know if there is any additional information I can provide to help debug this, or if my understanding of the supervisor is incorrect.

actors/receive with :after statement fails on some patterns

The following example from the comments in the code to actors/receive fails: (receive :else m :after 30 :foo)

This is because :after statements, e.g. :after 20 :foo, have an odd number of expressions, so adding an :after statement turns a body with an otherwise even count of expressions into a body with an odd count. The assert-args statement https://github.com/puniverse/pulsar/blob/master/src/main/clojure/co/paralleluniverse/pulsar/actors.clj#L480 counts the expressions before removal of the :after statement, it should do so after, e.g. like so:

  ([& body]
   (let [[body after-clause] (if (= :after (nth-from-last body 2 nil)) (split-at-from-last 2 body) [body nil])
         _ (assert-args
              (or (even? (count body)) (vector? (first body))) "a vector for its binding")
         odd-forms   (odd? (count body))

receiving using the actor's internal representation, (rcv @self) (mailbox-of @self) breaks

According to the docs the following should be possible:

(defsfn actor-name []
   (println (rcv @self))
   (recur))
(defsfn actor-name []
  (println (rcv (mailbox-of @self))
  (recur))

In my case it throws an error, here is the repl output:

clojure-actors.core=> (defsfn actor-name []
                 #_=> (println (rcv (mailbox-of @self))))
#'clojure-actors.core/actor-name
clojure-actors.core=> (register! :o (spawn actor-name))
Exception in Fiber "fiber-10000004" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.ClassCastException: co.paralleluniverse.actors.ActorRef cannot be cast to co.paralleluniverse.strands.channels.ReceivePort
    at co.paralleluniverse.pulsar.core$rcv.invoke(core.clj:593)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at clojure_actors.core$actor_name.invoke(form-init4486106094382776745.clj:2)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:213)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:200)
    at co.paralleluniverse.actors.PulsarActor.doRun(PulsarActor.java:92)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1024)
nil
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack:
    at co.paralleluniverse.pulsar.core$rcv.invoke(java.lang.Object) (core.clj:593 bci: 3) (optimized) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:36 bci: 5)
    at clojure_actors.core$actor_name.invoke (form-init4486106094382776745.clj:2 bci: 294)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:32 bci: 4)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke (ClojureHelper.java:213 bci: 1) (optimized)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run (ClojureHelper.java:200 bci: 83)
    at co.paralleluniverse.actors.PulsarActor.doRun (PulsarActor.java:92 bci: 76)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691 bci: 222)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51 bci: 148)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1024 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1019 bci: 1)
Exception in Fiber "fiber-10000004" If this exception looks strange, perhaps you've forgotten to instrument a blocking method. Run your program with -Dco.paralleluniverse.fibers.verifyInstrumentation to catch the culprit!
java.lang.ClassCastException: co.paralleluniverse.actors.ActorRef cannot be cast to co.paralleluniverse.strands.channels.ReceivePort
    at co.paralleluniverse.pulsar.core$rcv.invoke(core.clj:593)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at clojure_actors.core$actor_name.invoke(form-init4486106094382776745.clj:2)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:213)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run(ClojureHelper.java:200)
    at co.paralleluniverse.actors.PulsarActor.doRun(PulsarActor.java:92)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:691)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1024)
WARNING: Uninstrumented methods (marked '**') or call-sites (marked '!!') detected on the call stack:
    at co.paralleluniverse.pulsar.core$rcv.invoke(java.lang.Object) (core.clj:593 bci: 3) (optimized) !! (instrumented suspendable calls at: [])
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:36 bci: 5)
    at clojure_actors.core$actor_name.invoke (form-init4486106094382776745.clj:2 bci: 294)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke (InstrumentedIFn.java:32 bci: 4)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke (ClojureHelper.java:213 bci: 1) (optimized)
    at co.paralleluniverse.pulsar.ClojureHelper$4.run (ClojureHelper.java:200 bci: 83)
    at co.paralleluniverse.actors.PulsarActor.doRun (PulsarActor.java:92 bci: 76)
    at co.paralleluniverse.actors.Actor.run0 (Actor.java:691 bci: 222)
    at co.paralleluniverse.actors.ActorRunner.run (ActorRunner.java:51 bci: 148)
    at co.paralleluniverse.fibers.Fiber.run (Fiber.java:1024 bci: 11)
    at co.paralleluniverse.fibers.Fiber.run1 (Fiber.java:1019 bci: 1)

Fibers interfere with Clojure's Reflector

lein exec -p this snippet

(import java.io.ByteArrayOutputStream
        java.awt.image.BufferedImage
        javax.imageio.ImageIO)
(require '[co.paralleluniverse.pulsar.actors :refer [spawn]]
         '[co.paralleluniverse.pulsar.core :refer [defsfn]])
(defsfn test-screen [image]
  (let [baos (ByteArrayOutputStream.)]
    (ImageIO/write image "png" baos)))
(let [image (BufferedImage. 1 1 BufferedImage/TYPE_INT_ARGB)]
  (test-screen image)
  (spawn #(test-screen %) image))

and you get this beauty.

Exception in Fiber "fiber-10000001" java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
    at clojure.lang.Reflector.invokeStaticMethod(Reflector.java:207)
    at user$test_screen.invoke(test.clj:8)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at user$eval2252$fn__2255$fn__2256.invoke(test.clj:11)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:624)
    at user$eval2252$fn__2255.invoke(test.clj:11)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:185)
    at co.paralleluniverse.pulsar.ClojureHelper$3.run(ClojureHelper.java:172)
    at co.paralleluniverse.actors.PulsarActor.doRun(PulsarActor.java:90)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:667)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.actors.Actor.run(Actor.java:236)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1003)
Exception in Fiber "fiber-10000001" java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
    at clojure.lang.Reflector.invokeStaticMethod(Reflector.java:207)
    at user$test_screen.invoke(test.clj:8)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:36)
    at user$eval2252$fn__2255$fn__2256.invoke(test.clj:11)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:624)
    at user$eval2252$fn__2255.invoke(test.clj:11)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:185)
    at co.paralleluniverse.pulsar.ClojureHelper$3.run(ClojureHelper.java:172)
    at co.paralleluniverse.actors.PulsarActor.doRun(PulsarActor.java:90)
    at co.paralleluniverse.actors.Actor.run0(Actor.java:667)
    at co.paralleluniverse.actors.ActorRunner.run(ActorRunner.java:51)
    at co.paralleluniverse.actors.Actor.run(Actor.java:236)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1003)

relevant parts of my project.clj

:dependencies [[org.clojure/clojure "1.6.0"]
                 [co.paralleluniverse/pulsar "0.6.2"]]
:java-agents [[co.paralleluniverse/quasar-core "0.6.2"]]
:jvm-opts ["-Dco.paralleluniverse.fibers.detectRunawayFibers=false"]

Running (clojure.reflect/reflect ImageIO) with a variety of prints and filters both inside and outside an actor don't show any obvious differences.

Am I missing something? I hope this is just misconfiguration- sorry in advance if so!

EDIT:

Running the above with spawn-fiber throws a similar exception, but spawn-thread works fine. As a temporary work-around, maybe there's a way to run the actor on a thread instead of a fiber?

JVM details:

java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-1ubuntu1~0.13.10.1)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)

I also tried Oracle, same thing.

java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

println in fiber: java.lang.IllegalArgumentException: wrong number of arguments

Just starting out with pulsar (0.6.2), maybe I'm doing something wrong, but

(ns borked
  (:require [co.paralleluniverse.pulsar.core :as p]))

(p/spawn-fiber (fn [] (println "test")))

results in

Exception in Fiber "fiber-10000002" java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
    at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
    at clojure.tools.nrepl.middleware.session$session_out$fn__1390.doInvoke(session.clj:41)
    at clojure.lang.RestFn.invoke(RestFn.java:460)
    at clojure.tools.nrepl.middleware.session.proxy$java.io.Writer$ff19274a.write(Unknown Source)
    at java.io.PrintWriter.write(PrintWriter.java:456)
    at java.io.PrintWriter.write(PrintWriter.java:473)
    at clojure.core$fn__5471.invoke(core_print.clj:191)
    at clojure.lang.MultiFn.invoke(MultiFn.java:231)
    at clojure.core$pr_on.invoke(core.clj:3392)
    at clojure.core$pr.invoke(core.clj:3404)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at clojure.core$apply.invoke(core.clj:624)
    at clojure.core$prn.doInvoke(core.clj:3437)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:624)
    at clojure.core$println.doInvoke(core.clj:3457)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at borked$eval2177$fn__2178.invoke(NO_SOURCE_FILE:1)
    at co.paralleluniverse.pulsar.InstrumentedIFn.invoke(InstrumentedIFn.java:32)
    at co.paralleluniverse.pulsar.ClojureHelper.suspendableInvoke(ClojureHelper.java:185)
    at co.paralleluniverse.pulsar.ClojureHelper$3.run(ClojureHelper.java:172)
    at co.paralleluniverse.fibers.Fiber.run(Fiber.java:1003)

NullPointerException when trying instrument log4j

Hi!

I found https://github.com/puniverse/comsat project and I want implement same ideas with clojure ring adapter.

And in my experiment, I found this exception:

[3/5.0.5]niwi@niwi:~/devel/experiments/ring-jetty-adapter> lein test
Initializing core.typed ...
Loading Clojurescript...
Clojurescript not found
"Elapsed time: 3229.662482 msecs"
core.typed initialized.
[quasar] WARNING: Can't determine super class of org/apache/log4j/Level
[quasar] WARNING: Can't determine super class of org/apache/log4j/Priority
[quasar] ERROR: Unable to instrument org/apache/commons/logging/impl/Log4JLogger
java.lang.NullPointerException
    at org.objectweb.asm.Item.a(Unknown Source)
    at org.objectweb.asm.ClassWriter.c(Unknown Source)
    at org.objectweb.asm.ClassWriter.a(Unknown Source)
    at org.objectweb.asm.Frame.a(Unknown Source)
    at org.objectweb.asm.Frame.a(Unknown Source)
    at org.objectweb.asm.MethodWriter.visitMaxs(Unknown Source)
    at org.objectweb.asm.tree.MethodNode.accept(Unknown Source)
    at org.objectweb.asm.commons.JSRInlinerAdapter.visitEnd(Unknown Source)
    at org.objectweb.asm.MethodVisitor.visitEnd(Unknown Source)
    at co.paralleluniverse.fibers.instrument.InstrumentClass$1.visitEnd(InstrumentClass.java:164)
    at org.objectweb.asm.ClassReader.b(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at org.objectweb.asm.ClassReader.accept(Unknown Source)
    at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.instrumentClass(QuasarInstrumentor.java:84)
    at co.paralleluniverse.fibers.instrument.QuasarInstrumentor.instrumentClass(QuasarInstrumentor.java:67)
    at co.paralleluniverse.fibers.instrument.JavaAgent$Transformer.transform(JavaAgent.java:175)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:270)
    at org.apache.commons.logging.impl.LogFactoryImpl.createLogFromClass(LogFactoryImpl.java:998)
    at org.apache.commons.logging.impl.LogFactoryImpl.discoverLogImplementation(LogFactoryImpl.java:844)
    at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:541)
    at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:292)
    at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:269)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:657)
    at org.apache.http.conn.ssl.AbstractVerifier.<init>(AbstractVerifier.java:82)
    at org.apache.http.conn.ssl.AllowAllHostnameVerifier.<init>(AllowAllHostnameVerifier.java:40)
    at org.apache.http.conn.ssl.SSLSocketFactory.<clinit>(SSLSocketFactory.java:145)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:190)
    at clj_http.conn_mgr$eval1022$loading__4910__auto____1023.invoke(conn_mgr.clj:1)
    at clj_http.conn_mgr$eval1022.invoke(conn_mgr.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6619)
    at clojure.lang.Compiler.eval(Compiler.java:6608)
    at clojure.lang.Compiler.load(Compiler.java:7064)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5018.invoke(core.clj:5530)
    at clojure.core$load.doInvoke(core.clj:5529)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5336)
    at clojure.core$load_lib$fn__4967.invoke(core.clj:5375)
    at clojure.core$load_lib.doInvoke(core.clj:5374)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$load_libs.doInvoke(core.clj:5413)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$require.doInvoke(core.clj:5496)
    at clojure.lang.RestFn.invoke(RestFn.java:457)
    at clj_http.client$eval804$loading__4910__auto____805.invoke(client.clj:1)
    at clj_http.client$eval804.invoke(client.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6619)
    at clojure.lang.Compiler.eval(Compiler.java:6608)
    at clojure.lang.Compiler.load(Compiler.java:7064)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5018.invoke(core.clj:5530)
    at clojure.core$load.doInvoke(core.clj:5529)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5336)
    at clojure.core$load_lib$fn__4967.invoke(core.clj:5375)
    at clojure.core$load_lib.doInvoke(core.clj:5374)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$load_libs.doInvoke(core.clj:5413)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$require.doInvoke(core.clj:5496)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at ring.adapter.test.jetty$eval182$loading__4910__auto____183.invoke(jetty.clj:1)
    at ring.adapter.test.jetty$eval182.invoke(jetty.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6619)
    at clojure.lang.Compiler.eval(Compiler.java:6608)
    at clojure.lang.Compiler.load(Compiler.java:7064)
    at clojure.lang.RT.loadResourceScript(RT.java:370)
    at clojure.lang.RT.loadResourceScript(RT.java:361)
    at clojure.lang.RT.load(RT.java:440)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5018.invoke(core.clj:5530)
    at clojure.core$load.doInvoke(core.clj:5529)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5336)
    at clojure.core$load_lib$fn__4967.invoke(core.clj:5375)
    at clojure.core$load_lib.doInvoke(core.clj:5374)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$load_libs.doInvoke(core.clj:5413)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$require.doInvoke(core.clj:5496)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:619)
    at user$eval85.invoke(form-init7725653654435306477.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6619)
    at clojure.lang.Compiler.eval(Compiler.java:6609)
    at clojure.lang.Compiler.load(Compiler.java:7064)
    at clojure.lang.Compiler.loadFile(Compiler.java:7020)
    at clojure.main$load_script.invoke(main.clj:294)
    at clojure.main$init_opt.invoke(main.clj:299)
    at clojure.main$initialize.invoke(main.clj:327)
    at clojure.main$null_opt.invoke(main.clj:362)
    at clojure.main$main.doInvoke(main.clj:440)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:419)
    at clojure.lang.AFn.applyToHelper(AFn.java:163)
    at clojure.lang.Var.applyTo(Var.java:532)
    at clojure.main.main(main.java:37)

I really don't know that it happens, but seems that quasar can not instrument some java classes.

I don't know if I am wrong opening this issue on pulsar...

Project url: https://github.com/niwibe/ring-pulsar-jetty9-adapter/blob/master/src/ring/adapter/pulsar/jetty9.clj#L26

Thanks.
Andrey

Selective receive breaks when spawning an actor on a redefined `defsfn`

Thank you for Pulsar, it looks amazing!

It seems I can't reload suspendable functions in the REPL. Entering this in the REPL works as expected (printing "one"):

(defsfn a1 []
  (receive
    :ab (println "one")))

(def aa (spawn a1))

(! aa :ab)

However when entering the expressions again (slightly changed) (or alternatively calling (clojure.tools.namespace.repl/refresh)), I won't see a result printed:

(defsfn a1 []
  (receive
    :ab (println "two")))

(def aa (spawn a1))

(! aa :ab)

I'm using

  :dependencies [[org.clojure/clojure "1.8.0"] 
                 [co.paralleluniverse/quasar-core "0.7.5"]
                 [co.paralleluniverse/pulsar "0.7.5"]
                 ]
  :java-agents  [[co.paralleluniverse/quasar-core "0.7.5"]]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.