You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2017/07/21 17:01:57 UTC

[01/20] qpid-proton git commit: PROTON-1400: [C++ example] Use multiple threads in broker example if available

Repository: qpid-proton
Updated Branches:
  refs/heads/master 6f88f525e -> b17671eef


PROTON-1400: [C++ example] Use multiple threads in broker example if available


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b17671ee
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b17671ee
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b17671ee

Branch: refs/heads/master
Commit: b17671eefa3a13579f858cd7a72df4231058a429
Parents: 2a60653
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 26 17:01:00 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b17671ee/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 2cb2b36..01dab36 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -44,11 +44,19 @@
 #include <map>
 #include <string>
 
+#if PN_CPP_SUPPORTS_THREADS
+#include <thread>
+#endif
+
 #include "fake_cpp11.hpp"
 
 // This is a simplified model for a message broker, that only allows for messages to go to a
 // single receiver.
 //
+// This broker is multithread safe and if compiled with C++11 with a multithreaded Proton
+// binding library will use as many threads as there are thread resources available (usually
+// cores)
+//
 // Queues are only created and never destroyed
 //
 // Broker Entities (that need to be individually serialised)
@@ -387,7 +395,12 @@ class broker {
     }
 
     void run() {
-        container_.run(/* std::thread::hardware_concurrency() */);
+#if PN_CPP_SUPPORTS_THREADS
+        std::cout << "starting " << std::thread::hardware_concurrency() << " listening threads\n";
+        container_.run(std::thread::hardware_concurrency());
+#else
+        container_.run();
+#endif
     }
 
   private:


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[02/20] qpid-proton git commit: PROTON-1400: [C++ binding] Make proactor container thread safe

Posted by as...@apache.org.
PROTON-1400: [C++ binding] Make proactor container thread safe


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/e4eca5c3
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/e4eca5c3
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/e4eca5c3

Branch: refs/heads/master
Commit: e4eca5c3d92b917edca4629c6bc01155c4678baf
Parents: 8aee73b
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 26 17:00:31 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/container.hpp   |  22 +++-
 .../cpp/include/proton/internal/config.hpp      |   4 +
 proton-c/bindings/cpp/src/container.cpp         |   6 +-
 .../cpp/src/include/proactor_container_impl.hpp |  28 +++-
 .../cpp/src/proactor_container_impl.cpp         | 127 +++++++++++++++----
 5 files changed, 155 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e4eca5c3/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index 0739517..8b517bf 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -29,11 +29,11 @@
 #include "./internal/export.hpp"
 #include "./internal/pn_unique_ptr.hpp"
 
-#ifdef PN_CPP_HAS_STD_FUNCTION
-#include <functional>
-#endif
 #include <string>
 
+/// If the library can support multithreaded containers then PN_CPP_SUPPORTS_THREADS will be set.
+#define PN_CPP_SUPPORTS_THREADS PN_CPP_HAS_STD_THREAD && PN_CPP_HAS_STD_MUTEX && PN_CPP_HAS_STD_ATOMIC
+
 namespace proton {
 
 /// A top-level container of connections, sessions, senders, and
@@ -55,6 +55,13 @@ class PN_CPP_CLASS_EXTERN container {
     /// Create a container.
     PN_CPP_EXTERN container(const std::string& id="");
 
+    /// Destroy a container.
+    /// Note that you may not delete a container from within any of the threads running
+    /// any of the container's messaging_handlers. Specifically if you delete the container
+    /// from within a handler you cause a deadlock or a crash.
+    ///
+    /// The only safe place to delete a container is after all of the threads running a container
+    /// have finished and all of the run functions have returned.
     PN_CPP_EXTERN ~container();
 
     /// Connect to `url` and send an open request to the remote peer.
@@ -95,9 +102,16 @@ class PN_CPP_CLASS_EXTERN container {
     /// Returns when the container stops.
     /// @see auto_stop() and stop().
     ///
-    /// With a multithreaded container, call run() in multiple threads to create a thread pool.
+    /// If you are using C++11 or later you may use a multithreaded container. In this case you may
+    /// call run() in multiple threads to create a thread pool. Or aternatively call run with an
+    /// integer parameter specifying the number of threads for the thread pool.
     PN_CPP_EXTERN void run();
 
+#if PN_CPP_SUPPORTS_THREADS
+    /// @copydoc run()
+    PN_CPP_EXTERN void run(int threads);
+#endif
+
     /// If true, stop the container when all active connections and listeners are closed.
     /// If false the container will keep running till stop() is called.
     ///

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e4eca5c3/proton-c/bindings/cpp/include/proton/internal/config.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/config.hpp b/proton-c/bindings/cpp/include/proton/internal/config.hpp
index 79d201c..54b014b 100644
--- a/proton-c/bindings/cpp/include/proton/internal/config.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/config.hpp
@@ -103,6 +103,10 @@
 #define PN_CPP_HAS_STD_ATOMIC PN_CPP_HAS_CPP11
 #endif
 
+#ifndef PN_CPP_HAS_STD_THREAD
+#define PN_CPP_HAS_STD_THREAD PN_CPP_HAS_CPP11
+#endif
+
 #endif // PROTON_INTERNAL_CONFIG_HPP
 
 /// @endcond

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e4eca5c3/proton-c/bindings/cpp/src/container.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container.cpp b/proton-c/bindings/cpp/src/container.cpp
index c2af659..35f645c 100644
--- a/proton-c/bindings/cpp/src/container.cpp
+++ b/proton-c/bindings/cpp/src/container.cpp
@@ -81,7 +81,11 @@ returned<connection> container::connect(const std::string& url, const connection
 
 listener container::listen(const std::string& url, listen_handler& l) { return impl_->listen(url, l); }
 
-void container::run() { impl_->run(); }
+void container::run() { impl_->run(1); }
+
+#if PN_CPP_SUPPORTS_THREADS
+void container::run(int threads) { impl_->run(threads); }
+#endif
 
 void container::auto_stop(bool set) { impl_->auto_stop(set); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e4eca5c3/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
index fc963f7..ac54156 100644
--- a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
@@ -43,6 +43,21 @@
 #include <string>
 #include <vector>
 
+#if PN_CPP_SUPPORTS_THREADS
+#include <atomic>
+#include <mutex>
+# define MUTEX(x) std::mutex x;
+# define GUARD(x) std::lock_guard<std::mutex> g(x)
+# define ONCE_FLAG(x) std::once_flag x;
+# define CALL_ONCE(x, ...) std::call_once(x, __VA_ARGS__)
+# define ATOMIC_INT(x) std::atomic<int> x;
+#else
+# define MUTEX(x)
+# define GUARD(x)
+# define ONCE_FLAG(x)
+# define CALL_ONCE(x, f, o) ((o)->*(f))()
+# define ATOMIC_INT(x) int x;
+#endif
 struct pn_proactor_t;
 struct pn_listener_t;
 struct pn_event_t;
@@ -70,7 +85,7 @@ class container::impl {
     class sender_options sender_options() const { return sender_options_; }
     void receiver_options(const proton::receiver_options&);
     class receiver_options receiver_options() const { return receiver_options_; }
-    void run();
+    void run(int threads);
     void stop(const error_condition& err);
     void auto_stop(bool set);
     void schedule(duration, work);
@@ -86,16 +101,23 @@ class container::impl {
     connection connect_common(const std::string&, const connection_options&);
 
     // Event loop to run in each container thread
-    static void thread(impl&);
+    void thread();
     bool handle(pn_event_t*);
     void run_timer_jobs();
 
+    ATOMIC_INT(threads_)
+    MUTEX(lock_)
+    ONCE_FLAG(start_once_)
+    ONCE_FLAG(stop_once_)
     container& container_;
 
     typedef std::set<container_work_queue*> work_queues;
     work_queues work_queues_;
     container_work_queue* add_work_queue();
     void remove_work_queue(container_work_queue*);
+    void start_event();
+    void stop_event();
+
     struct scheduled {
         timestamp time; // duration from epoch for task
         work task;
@@ -112,8 +134,8 @@ class container::impl {
     connection_options server_connection_options_;
     proton::sender_options sender_options_;
     proton::receiver_options receiver_options_;
+    error_condition disconnect_error_;
 
-    proton::error_condition stop_err_;
     bool auto_stop_;
     bool stopping_;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/e4eca5c3/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index 62115fd..b900d6f 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -41,21 +41,27 @@
 #include <algorithm>
 #include <vector>
 
+#if PN_CPP_SUPPORTS_THREADS
+# include <thread>
+#endif
+
 namespace proton {
 
 class container::impl::common_work_queue : public work_queue::impl {
   public:
-    common_work_queue(container::impl& c): container_(c), finished_(false) {}
+    common_work_queue(container::impl& c): container_(c), finished_(false), running_(false) {}
 
     typedef std::vector<work> jobs;
 
     void run_all_jobs();
-    void finished() { finished_ = true; }
+    void finished() { GUARD(lock_); finished_ = true; }
     void schedule(duration, work);
 
+    MUTEX(lock_)
     container::impl& container_;
     jobs jobs_;
     bool finished_;
+    bool running_;
 };
 
 void container::impl::common_work_queue::schedule(duration d, work f) {
@@ -68,11 +74,22 @@ void container::impl::common_work_queue::schedule(duration d, work f) {
 void container::impl::common_work_queue::run_all_jobs() {
     jobs j;
     // Lock this operation for mt
-    std::swap(j, jobs_);
+    {
+        GUARD(lock_);
+        // Ensure that we never run work from this queue concurrently
+        if (running_) return;
+        running_ = true;
+        // But allow adding to the queue concurrently to running
+        std::swap(j, jobs_);
+    }
     // Run queued work, but ignore any exceptions
     for (jobs::iterator f = j.begin(); f != j.end(); ++f) try {
         (*f)();
     } catch (...) {};
+    {
+        GUARD(lock_);
+        running_ = false;
+    }
     return;
 }
 
@@ -88,6 +105,7 @@ class container::impl::connection_work_queue : public common_work_queue {
 bool container::impl::connection_work_queue::add(work f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
+    GUARD(lock_);
     if (finished_) return false;
     jobs_.push_back(f);
     pn_connection_wake(connection_);
@@ -105,6 +123,7 @@ class container::impl::container_work_queue : public common_work_queue {
 bool container::impl::container_work_queue::add(work f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
+    GUARD(lock_);
     if (finished_) return false;
     jobs_.push_back(f);
     pn_proactor_set_timeout(container_.proactor_, 0);
@@ -116,15 +135,11 @@ class work_queue::impl* container::impl::make_work_queue(container& c) {
 }
 
 container::impl::impl(container& c, const std::string& id, messaging_handler* mh)
-    : container_(c), proactor_(pn_proactor()), handler_(mh), id_(id),
+    : threads_(0), container_(c), proactor_(pn_proactor()), handler_(mh), id_(id),
       auto_stop_(true), stopping_(false)
 {}
 
 container::impl::~impl() {
-    try {
-        stop(error_condition("exception", "container shut-down"));
-        //wait();
-    } catch (...) {}
     pn_proactor_free(proactor_);
 }
 
@@ -178,6 +193,7 @@ proton::returned<proton::connection> container::impl::connect(
     const proton::connection_options& user_opts)
 {
     connection conn = connect_common(addr, user_opts);
+    GUARD(lock_);
     return make_thread_safe(conn);
 }
 
@@ -186,6 +202,7 @@ returned<sender> container::impl::open_sender(const std::string &url, const prot
     lopts.update(o1);
     connection conn = connect_common(url, o2);
 
+    GUARD(lock_);
     return make_thread_safe(conn.default_session().open_sender(proton::url(url).path(), lopts));
 }
 
@@ -194,6 +211,7 @@ returned<receiver> container::impl::open_receiver(const std::string &url, const
     lopts.update(o1);
     connection conn = connect_common(url, o2);
 
+    GUARD(lock_);
     return make_thread_safe(
         conn.default_session().open_receiver(proton::url(url).path(), lopts));
 }
@@ -215,11 +233,13 @@ pn_listener_t* container::impl::listen_common_lh(const std::string& addr) {
 }
 
 proton::listener container::impl::listen(const std::string& addr) {
+    GUARD(lock_);
     pn_listener_t* listener = listen_common_lh(addr);
     return proton::listener(listener);
 }
 
 proton::listener container::impl::listen(const std::string& addr, const proton::connection_options& opts) {
+    GUARD(lock_);
     pn_listener_t* listener = listen_common_lh(addr);
     listener_context& lc=listener_context::get(listener);
     lc.connection_options_.reset(new connection_options(opts));
@@ -227,6 +247,7 @@ proton::listener container::impl::listen(const std::string& addr, const proton::
 }
 
 proton::listener container::impl::listen(const std::string& addr, proton::listen_handler& lh) {
+    GUARD(lock_);
     pn_listener_t* listener = listen_common_lh(addr);
     listener_context& lc=listener_context::get(listener);
     lc.listen_handler_ = &lh;
@@ -234,6 +255,7 @@ proton::listener container::impl::listen(const std::string& addr, proton::listen
 }
 
 void container::impl::schedule(duration delay, work f) {
+    GUARD(lock_);
     timestamp now = timestamp::now();
 
     // Record timeout; Add callback to timeout sorted list
@@ -247,18 +269,22 @@ void container::impl::schedule(duration delay, work f) {
 }
 
 void container::impl::client_connection_options(const connection_options &opts) {
+    GUARD(lock_);
     client_connection_options_ = opts;
 }
 
 void container::impl::server_connection_options(const connection_options &opts) {
+    GUARD(lock_);
     server_connection_options_ = opts;
 }
 
 void container::impl::sender_options(const proton::sender_options &opts) {
+    GUARD(lock_);
     sender_options_ = opts;
 }
 
 void container::impl::receiver_options(const proton::receiver_options &opts) {
+    GUARD(lock_);
     receiver_options_ = opts;
 }
 
@@ -294,13 +320,18 @@ bool container::impl::handle(pn_event_t* event) {
     switch (pn_event_type(event)) {
 
     case PN_PROACTOR_INACTIVE: /* listener and all connections closed */
-        return auto_stop_;
+        // If we're stopping interrupt all other threads still running
+        if (auto_stop_) pn_proactor_interrupt(proactor_);
+        return false;
 
-    // We never interrupt the proactor so ignore
+    // We only interrupt to stop threads
     case PN_PROACTOR_INTERRUPT:
-        return false;
+        // Interrupt any other threads still running
+        if (threads_>1) pn_proactor_interrupt(proactor_);
+        return true;
 
     case PN_PROACTOR_TIMEOUT: {
+        GUARD(lock_);
         // Can get an immediate timeout, if we have a container event loop inject
         if  ( deferred_.size()>0 ) {
             run_timer_jobs();
@@ -402,30 +433,78 @@ bool container::impl::handle(pn_event_t* event) {
     return false;
 }
 
-void container::impl::thread(container::impl& ci) {
-  bool finished = false;
-  do {
-    pn_event_batch_t *events = pn_proactor_wait(ci.proactor_);
-    pn_event_t *e;
-    while ((e = pn_event_batch_next(events))) {
-      finished = ci.handle(e) || finished;
-    }
-    pn_proactor_done(ci.proactor_, events);
-  } while(!finished);
+void container::impl::thread() {
+    ++threads_;
+    bool finished = false;
+    do {
+      pn_event_batch_t *events = pn_proactor_wait(proactor_);
+      pn_event_t *e;
+      try {
+        while ((e = pn_event_batch_next(events))) {
+          finished = handle(e);
+          if (finished) break;
+        }
+      } catch (proton::error& e) {
+        // If we caught an exception then shutdown the (other threads of the) container
+        disconnect_error_ = error_condition("exception", e.what());
+        if (!stopping_) stop(disconnect_error_);
+        finished = true;
+      } catch (...) {
+        // If we caught an exception then shutdown the (other threads of the) container
+        disconnect_error_ = error_condition("exception", "container shut-down by unknown exception");
+        if (!stopping_) stop(disconnect_error_);
+        finished = true;
+      }
+      pn_proactor_done(proactor_, events);
+    } while(!finished);
+    --threads_;
 }
 
-void container::impl::run() {
-    // Have to "manually" generate container events
+void container::impl::start_event() {
     if (handler_) handler_->on_container_start(container_);
-    thread(*this);
+}
+
+void container::impl::stop_event() {
     if (handler_) handler_->on_container_stop(container_);
 }
 
+void container::impl::run(int threads) {
+    // Have to "manually" generate container events
+    CALL_ONCE(start_once_, &impl::start_event, this);
+
+#if PN_CPP_SUPPORTS_THREADS
+    // Run handler threads
+    std::vector<std::thread> ts(threads-1);
+    if (threads>1) {
+      for (auto& t : ts) t = std::thread(&impl::thread, this);
+    }
+
+    thread();      // Use this thread too.
+
+    // Wait for the other threads to stop
+    if (threads>1) {
+      for (auto& t : ts) t.join();
+    }
+#else
+    // Run a single handler thread (As we have no threading API)
+    thread();
+#endif
+
+    if (threads_==0) CALL_ONCE(stop_once_, &impl::stop_event, this);
+
+    // Throw an exception if we disconnected the proactor because of an exception
+    if (!disconnect_error_.empty()) {
+      throw proton::error(disconnect_error_.description());
+    };
+}
+
 void container::impl::auto_stop(bool set) {
+    GUARD(lock_);
     auto_stop_ = set;
 }
 
 void container::impl::stop(const proton::error_condition& err) {
+    GUARD(lock_);
     auto_stop_ = true;
     stopping_ = true;
     pn_condition_t* error_condition = pn_condition();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[17/20] qpid-proton git commit: PROTON-1481: [C++ binding] Further work on C++03 convenience functions - Propagate the result of work_queue::add - Fix memory leak of proton::defer if the deferred function can't be called - Add make_work convenience in pl

Posted by as...@apache.org.
PROTON-1481: [C++ binding] Further work on C++03 convenience functions
- Propagate the result of work_queue::add
- Fix memory leak of proton::defer if the deferred function can't be called
- Add make_work convenience in place of std::bind
- Simplfy defer oveload options - have to specify work_queue


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/bf3a2b4b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/bf3a2b4b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/bf3a2b4b

Branch: refs/heads/master
Commit: bf3a2b4bd9c447bc7b28ecd339a7293f1fcf7ac9
Parents: efc899f
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu May 18 13:47:46 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         |  40 ++---
 .../bindings/cpp/include/proton/work_queue.hpp  | 170 ++++++++++---------
 proton-c/bindings/cpp/src/work_queue.cpp        |   2 +
 3 files changed, 110 insertions(+), 102 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bf3a2b4b/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index a1ef3a5..09a771c 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -99,8 +99,8 @@ public:
         sender_(s), senders_(ss), work_queue_(s.work_queue()), queue_(0), pending_credit_(0)
     {}
 
-    void add(proton::work f) {
-        work_queue_.add(f);
+    bool add(proton::work f) {
+        return work_queue_.add(f);
     }
 
 
@@ -139,7 +139,7 @@ class Queue {
             DOUT(std::cerr << "(" << current_->second << ") ";);
             if (current_->second>0) {
                 DOUT(std::cerr << current_->first << " ";);
-                proton::defer(&Sender::sendMsg, current_->first, messages_.front());
+                proton::defer(current_->first, &Sender::sendMsg, current_->first, messages_.front());
                 messages_.pop_front();
                 --current_->second;
                 ++current_;
@@ -155,8 +155,8 @@ public:
         work_queue_(c), name_(n), current_(subscriptions_.end())
     {}
 
-    void add(proton::work f) {
-        work_queue_.add(f);
+    bool add(proton::work f) {
+        return work_queue_.add(f);
     }
 
     void queueMsg(proton::message m) {
@@ -178,14 +178,14 @@ public:
         // If we're about to erase the current subscription move on
         if (current_ != subscriptions_.end() && current_->first==s) ++current_;
         subscriptions_.erase(s);
-        proton::defer(&Sender::unsubscribed, s);
+        proton::defer(s, &Sender::unsubscribed, s);
     }
 };
 
 // We have credit to send a message.
 void Sender::on_sendable(proton::sender &sender) {
     if (queue_) {
-        proton::defer(&Queue::flow, queue_, this, sender.credit());
+        proton::defer(queue_, &Queue::flow, queue_, this, sender.credit());
     } else {
         pending_credit_ = sender.credit();
     }
@@ -193,7 +193,7 @@ void Sender::on_sendable(proton::sender &sender) {
 
 void Sender::on_sender_close(proton::sender &sender) {
     if (queue_) {
-        proton::defer(&Queue::unsubscribe, queue_, this);
+        proton::defer(queue_, &Queue::unsubscribe, queue_, this);
     } else {
         // TODO: Is it possible to be closed before we get the queue allocated?
         // If so, we should have a way to mark the sender deleted, so we can delete
@@ -207,12 +207,12 @@ void Sender::boundQueue(Queue* q, std::string qn) {
     queue_ = q;
     queue_name_ = qn;
 
-    proton::defer(&Queue::subscribe, q, this);
+    proton::defer(q, &Queue::subscribe, q, this);
     sender_.open(proton::sender_options()
         .source((proton::source_options().address(queue_name_)))
         .handler(*this));
     if (pending_credit_>0) {
-        proton::defer(&Queue::flow, queue_, this, pending_credit_);
+        proton::defer(queue_, &Queue::flow, queue_, this, pending_credit_);
     }
     std::cout << "sending from " << queue_name_ << std::endl;
 }
@@ -237,7 +237,7 @@ class Receiver : public proton::messaging_handler {
     void queueMsgs() {
         DOUT(std::cerr << "Receiver: " << this << " queueing " << messages_.size() << " msgs to: " << queue_ << "\n";);
         while (!messages_.empty()) {
-            proton::defer(&Queue::queueMsg, queue_, messages_.front());
+            proton::defer(queue_, &Queue::queueMsg, queue_, messages_.front());
             messages_.pop_front();
         }
     }
@@ -247,8 +247,8 @@ public:
         receiver_(r), work_queue_(r.work_queue()), queue_(0)
     {}
 
-    void add(proton::work f) {
-        work_queue_.add(f);
+    bool add(proton::work f) {
+        return work_queue_.add(f);
     }
 
     void boundQueue(Queue* q, std::string qn) {
@@ -275,8 +275,8 @@ public:
         container_(c), work_queue_(c), next_id_(0)
     {}
 
-    void add(proton::work f) {
-        work_queue_.add(f);
+    bool add(proton::work f) {
+        return work_queue_.add(f);
     }
 
     template <class T>
@@ -295,7 +295,7 @@ public:
         } else {
             q = i->second;
         }
-        proton::defer(&T::boundQueue, &connection, q, qn);
+        proton::defer(&connection, &T::boundQueue, &connection, q, qn);
     }
 
     void findQueueSender(Sender* s, std::string qn) {
@@ -325,7 +325,7 @@ public:
         std::string qn = sender.source().dynamic() ? "" : sender.source().address();
         Sender* s = new Sender(sender, senders_);
         senders_[sender] = s;
-        proton::defer(&QueueManager::findQueueSender, &queue_manager_, s, qn);
+        proton::defer(&queue_manager_, &QueueManager::findQueueSender, &queue_manager_, s, qn);
     }
 
     // A receiver receives messages from a publisher to a queue.
@@ -341,7 +341,7 @@ public:
                 DOUT(std::cerr << "ODD - trying to attach to a empty address\n";);
             }
             Receiver* r = new Receiver(receiver);
-            proton::defer(&QueueManager::findQueueReceiver, &queue_manager_, r, qname);
+            proton::defer(&queue_manager_, &QueueManager::findQueueReceiver, &queue_manager_, r, qname);
         }
     }
 
@@ -352,7 +352,7 @@ public:
             if (j == senders_.end()) continue;
             Sender* s = j->second;
             if (s->queue_) {
-                proton::defer(&Queue::unsubscribe, s->queue_, s);
+                proton::defer(s->queue_, &Queue::unsubscribe, s->queue_, s);
             }
             senders_.erase(j);
         }
@@ -370,7 +370,7 @@ public:
             if (j == senders_.end()) continue;
             Sender* s = j->second;
             if (s->queue_) {
-                proton::defer(&Queue::unsubscribe, s->queue_, s);
+                proton::defer(s->queue_, &Queue::unsubscribe, s->queue_, s);
             }
         }
         delete this;            // All done.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bf3a2b4b/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index 1937e11..4d843c2 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -100,7 +100,7 @@ class PN_CPP_CLASS_EXTERN work_queue {
     /// deferred and possibly in another thread.
     ///
     /// @return true if f() has or will be called, false if the event_loop is ended
-    /// and f() cannot be injected.
+    /// or f() cannot be injected for any other reason.
     PN_CPP_EXTERN bool add(work f);
 
   private:
@@ -120,10 +120,11 @@ class PN_CPP_CLASS_EXTERN work_queue {
 // Utilities to make injecting functions/member functions palatable in C++03
 // Lots of repetition to handle functions with up to 3 arguments
 #if !PN_CPP_HAS_CPP11
+template <class R>
 struct work0 : public proton::void_function0 {
-    void (* fn_)();
+    R (* fn_)();
 
-    work0(void (* f)()) :
+    work0(R (* f)()) :
         fn_(f) {}
 
     void operator()() {
@@ -132,12 +133,12 @@ struct work0 : public proton::void_function0 {
     }
 };
 
-template <class A>
+template <class R, class A>
 struct work1 : public proton::void_function0 {
-    void (* fn_)(A);
+    R (* fn_)(A);
     A a_;
 
-    work1(void (* t)(A), A a) :
+    work1(R (* t)(A), A a) :
         fn_(t), a_(a) {}
 
     void operator()() {
@@ -146,13 +147,13 @@ struct work1 : public proton::void_function0 {
     }
 };
 
-template <class A, class B>
+template <class R, class A, class B>
 struct work2 : public proton::void_function0 {
-    void (* fn_)(A, B);
+    R (* fn_)(A, B);
     A a_;
     B b_;
 
-    work2(void (* t)(A, B), A a, B b) :
+    work2(R (* t)(A, B), A a, B b) :
         fn_(t), a_(a), b_(b) {}
 
     void operator()() {
@@ -161,14 +162,14 @@ struct work2 : public proton::void_function0 {
     }
 };
 
-template <class A, class B, class C>
+template <class R, class A, class B, class C>
 struct work3 : public proton::void_function0 {
-    void (* fn_)(A, B, C);
+    R (* fn_)(A, B, C);
     A a_;
     B b_;
     C c_;
 
-    work3(void (* t)(A, B, C), A a, B b, C c) :
+    work3(R (* t)(A, B, C), A a, B b, C c) :
         fn_(t), a_(a), b_(b), c_(c) {}
 
     void operator()() {
@@ -177,12 +178,12 @@ struct work3 : public proton::void_function0 {
     }
 };
 
-template <class T>
+template <class R, class T>
 struct work_pmf0 : public proton::void_function0 {
     T& holder_;
-    void (T::* fn_)();
+    R (T::* fn_)();
 
-    work_pmf0(void (T::* a)(), T& h) :
+    work_pmf0(R (T::* a)(), T& h) :
         holder_(h), fn_(a) {}
 
     void operator()() {
@@ -191,13 +192,13 @@ struct work_pmf0 : public proton::void_function0 {
     }
 };
 
-template <class T, class A>
+template <class R, class T, class A>
 struct work_pmf1 : public proton::void_function0 {
     T& holder_;
-    void (T::* fn_)(A);
+    R (T::* fn_)(A);
     A a_;
 
-    work_pmf1(void (T::* t)(A), T& h, A a) :
+    work_pmf1(R (T::* t)(A), T& h, A a) :
         holder_(h), fn_(t), a_(a) {}
 
     void operator()() {
@@ -206,14 +207,14 @@ struct work_pmf1 : public proton::void_function0 {
     }
 };
 
-template <class T, class A, class B>
+template <class R, class T, class A, class B>
 struct work_pmf2 : public proton::void_function0 {
     T& holder_;
-    void (T::* fn_)(A, B);
+    R (T::* fn_)(A, B);
     A a_;
     B b_;
 
-    work_pmf2(void (T::* t)(A, B), T& h, A a, B b) :
+    work_pmf2(R (T::* t)(A, B), T& h, A a, B b) :
         holder_(h), fn_(t), a_(a), b_(b) {}
 
     void operator()() {
@@ -222,15 +223,15 @@ struct work_pmf2 : public proton::void_function0 {
     }
 };
 
-template <class T, class A, class B, class C>
+template <class R, class T, class A, class B, class C>
 struct work_pmf3 : public proton::void_function0 {
     T& holder_;
-    void (T::* fn_)(A, B, C);
+    R (T::* fn_)(A, B, C);
     A a_;
     B b_;
     C c_;
 
-    work_pmf3(void (T::* t)(A, B, C), T& h, A a, B b, C c) :
+    work_pmf3(R (T::* t)(A, B, C), T& h, A a, B b, C c) :
         holder_(h), fn_(t), a_(a), b_(b), c_(c) {}
 
     void operator()() {
@@ -239,91 +240,96 @@ struct work_pmf3 : public proton::void_function0 {
     }
 };
 
-/// This version of proton::defer defers calling an object's member function to the object's work queue
-template <class T>
-void defer(void (T::*f)(), T* t) {
-    work_pmf0<T>* w = new work_pmf0<T>(f, *t);
-    t->add(*w);
+/// make_work is the equivalent of C++11 std::bind for C++03
+/// It will bind both free functions and pointers to member functions
+template <class R, class T>
+void_function0& make_work(R (T::*f)(), T* t) {
+    return *new work_pmf0<R, T>(f, *t);
 }
 
-template <class T, class A>
-void defer(void (T::*f)(A), T* t, A a) {
-    work_pmf1<T, A>* w = new work_pmf1<T, A>(f, *t, a);
-    t->add(*w);
+template <class R, class T, class A>
+void_function0& make_work(R (T::*f)(A), T* t, A a) {
+    return *new work_pmf1<R, T, A>(f, *t, a);
 }
 
-template <class T, class A, class B>
-void defer(void (T::*f)(A, B), T* t, A a, B b) {
-    work_pmf2<T, A, B>* w = new work_pmf2<T, A, B>(f, *t, a, b);
-    t->add(*w);
+template <class R, class T, class A, class B>
+void_function0& make_work(R (T::*f)(A, B), T* t, A a, B b) {
+    return *new work_pmf2<R, T, A, B>(f, *t, a, b);
 }
 
-template <class T, class A, class B, class C>
-void defer(void (T::*f)(A, B, C), T* t, A a, B b, C c) {
-    work_pmf3<T, A, B, C>* w = new work_pmf3<T, A, B, C>(f, *t, a, b, c);
-    t->add(*w);
+template <class R, class T, class A, class B, class C>
+void_function0& make_work(R (T::*f)(A, B, C), T* t, A a, B b, C c) {
+    return *new work_pmf3<R, T, A, B, C>(f, *t, a, b, c);
 }
 
-/// This version of proton::defer defers calling a member function to an arbitrary work queue
-template <class T, class U>
-void defer(U* wq, void (T::*f)(), T* t) {
-    work_pmf0<T>* w = new work_pmf0<T>(f, *t);
-    wq->add(*w);
+template <class R>
+void_function0& make_work(R (*f)()) {
+    return *new work0<R>(f);
 }
 
-template <class T, class U, class A>
-void defer(U* wq, void (T::*f)(A), T* t, A a) {
-    work_pmf1<T, A>* w = new work_pmf1<T, A>(f, *t, a);
-    wq->add(*w);
+template <class R, class A>
+void_function0& make_work(R (*f)(A), A a) {
+    return *new work1<R, A>(f, a);
 }
 
-template <class T, class U, class A, class B>
-void defer(U* wq, void (T::*f)(A, B), T* t, A a, B b) {
-    work_pmf2<T, A, B>* w = new work_pmf2<T, A, B>(f, *t, a, b);
-    wq->add(*w);
+template <class R, class A, class B>
+void_function0& make_work(R (*f)(A, B), A a, B b) {
+    return *new work2<R, A, B>(f, a, b);
 }
 
-template <class T, class U, class A, class B, class C>
-void defer(U* wq, void (T::*f)(A, B, C), T* t, A a, B b, C c) {
-    work_pmf3<T, A, B, C>* w = new work_pmf3<T, A, B, C>(f, *t, a, b, c);
-    wq->add(*w);
+template <class R, class A, class B, class C>
+void_function0& make_work(R (*f)(A, B, C), A a, B b, C c) {
+    return *new work3<R, A, B, C>(f, a, b, c);
 }
 
-/// This version of proton::defer defers calling a free function to an arbitrary work queue
-template <class U>
-void defer(U* wq, void (*f)()) {
-    work0* w = new work0(f);
-    wq->add(*w);
+namespace {
+template <class T>
+bool defer_helper(T t, void_function0& w) {
+    bool r = t->add(w);
+    if (!r) delete &w;
+    return r;
+}
 }
 
-template <class U, class A>
-void defer(U* wq, void (*f)(A), A a) {
-    work1<A>* w = new work1<A>(f, a);
-    wq->add(*w);
+/// defer is a convenience that is used for C++03 code to defer function calls
+/// to a work_queue
+template <class WQ, class F>
+bool defer(WQ wq, F f) {
+    return defer_helper(wq, make_work(f));
 }
 
-template <class U, class A, class B>
-void defer(U* wq, void (*f)(A, B), A a, B b) {
-    work2<A, B>* w = new work2<A, B>(f, a, b);
-    wq->add(*w);
+template <class WQ, class F, class A>
+bool defer(WQ wq, F f, A a) {
+    return defer_helper(wq, make_work(f, a));
 }
 
-template <class U, class A, class B, class C>
-void defer(U* wq, void (*f)(A, B, C), A a, B b, C c) {
-    work3<A, B, C>* w = new work3<A, B, C>(f, a, b, c);
-    wq->add(*w);
+template <class WQ, class F, class A, class B>
+bool defer(WQ wq, F f, A a, B b) {
+    return defer_helper(wq, make_work(f, a, b));
 }
+
+template <class WQ, class F, class A, class B, class C>
+bool defer(WQ wq, F f, A a, B b, C c) {
+    return defer_helper(wq, make_work(f, a, b, c));
+}
+
+template <class WQ, class F, class A, class B, class C, class D>
+bool defer(WQ wq, F f, A a, B b, C c, D d) {
+    return defer_helper(wq, make_work(f, a, b, c, d));
+}
+
+/// This version of proton::defer defers calling a free function to an arbitrary work queue
 #else
 // The C++11 version is *much* simpler and even so more general!
-// These 2 definitions encompass everything in the C++03 section
-template <class T, class... Rest>
-void defer(void(T::*f)(Rest...), T* t, Rest... r) {
-    t->add(std::bind(f, t, r...));
+// These definitions encompass everything in the C++03 section
+template <class WQ, class... Rest>
+bool defer(WQ wq, Rest&&... r) {
+    return wq->add(std::bind(std::forward<Rest>(r)...));
 }
 
-template <class U, class... Rest>
-void defer(U* wq, Rest&&... r) {
-    wq->add(std::bind(std::forward<Rest>(r)...));
+template <class... Rest>
+work make_work(Rest&&... r) {
+    return std::bind(std::forward<Rest>(r)...);
 }
 #endif
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/bf3a2b4b/proton-c/bindings/cpp/src/work_queue.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/work_queue.cpp b/proton-c/bindings/cpp/src/work_queue.cpp
index db95042..77fa3fb 100644
--- a/proton-c/bindings/cpp/src/work_queue.cpp
+++ b/proton-c/bindings/cpp/src/work_queue.cpp
@@ -36,6 +36,8 @@ work_queue::~work_queue() {}
 work_queue& work_queue::operator=(impl* i) { impl_.reset(i); return *this; }
 
 bool work_queue::add(work f) {
+    // If we have no actual work queue, then can't defer
+    if (!impl_) return false;
     return impl_->add(f);
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[13/20] qpid-proton git commit: PROTON-1481: [C++ binding] Added simpler way to get work_queue from model objects

Posted by as...@apache.org.
PROTON-1481: [C++ binding] Added simpler way to get work_queue from model objects


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d1c91a42
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d1c91a42
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d1c91a42

Branch: refs/heads/master
Commit: d1c91a42e59f618fccb6838ffd30372a179759e2
Parents: 45d5612
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 19 12:27:17 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                             |  4 ++--
 examples/cpp/scheduled_send.cpp                     | 12 ++++++++----
 examples/cpp/scheduled_send_03.cpp                  |  2 +-
 proton-c/bindings/cpp/include/proton/connection.hpp |  3 +++
 proton-c/bindings/cpp/include/proton/link.hpp       |  3 +++
 proton-c/bindings/cpp/include/proton/session.hpp    |  3 +++
 proton-c/bindings/cpp/include/proton/transfer.hpp   |  3 +++
 proton-c/bindings/cpp/src/connection.cpp            |  4 ++++
 proton-c/bindings/cpp/src/link.cpp                  |  4 ++++
 proton-c/bindings/cpp/src/session.cpp               |  4 ++++
 proton-c/bindings/cpp/src/transfer.cpp              |  2 ++
 11 files changed, 37 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 8c2d2ff..d39314c 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -182,7 +182,7 @@ class Sender : public proton::messaging_handler {
 
 public:
     Sender(proton::sender s, senders& ss) :
-        sender_(s), senders_(ss), work_queue_(make_thread_safe(s).get()->work_queue()), queue_(0), pending_credit_(0)
+        sender_(s), senders_(ss), work_queue_(s.work_queue()), queue_(0), pending_credit_(0)
     {}
 
     void add(proton::void_function0& f) {
@@ -330,7 +330,7 @@ class Receiver : public proton::messaging_handler {
 
 public:
     Receiver(proton::receiver r) :
-        receiver_(r), work_queue_(make_thread_safe(r).get()->work_queue()), queue_(0)
+        receiver_(r), work_queue_(r.work_queue()), queue_(0)
     {}
 
     void add(proton::void_function0& f) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/examples/cpp/scheduled_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send.cpp b/examples/cpp/scheduled_send.cpp
index bbef15b..2914c44 100644
--- a/examples/cpp/scheduled_send.cpp
+++ b/examples/cpp/scheduled_send.cpp
@@ -56,12 +56,16 @@ class scheduled_sender : public proton::messaging_handler {
     // The awkward looking double lambda is necessary because the scheduled lambdas run in the container context
     // and must arrange lambdas for send and close to happen in the connection context.
     void on_container_start(proton::container &c) OVERRIDE {
-        sender = c.open_sender(url);
-        work_queue = &proton::make_thread_safe(sender).get()->work_queue();
+        c.open_sender(url);
+    }
+
+    void on_sender_open(proton::sender &s) OVERRIDE {
+        sender = s;
+        work_queue = &s.work_queue();
         // Call this->cancel after timeout.
-        c.schedule(timeout, [this]() { this->work_queue->add( [this]() { this->cancel(); }); });
+        s.container().schedule(timeout, [this]() { this->work_queue->add( [this]() { this->cancel(); }); });
          // Start regular ticks every interval.
-        c.schedule(interval, [this]() { this->work_queue->add( [this]() { this->tick(); }); });
+        s.container().schedule(interval, [this]() { this->work_queue->add( [this]() { this->tick(); }); });
     }
 
     void cancel() {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/examples/cpp/scheduled_send_03.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send_03.cpp b/examples/cpp/scheduled_send_03.cpp
index 4b1b626..c3c63c8 100644
--- a/examples/cpp/scheduled_send_03.cpp
+++ b/examples/cpp/scheduled_send_03.cpp
@@ -96,7 +96,7 @@ class scheduled_sender : public proton::messaging_handler {
     }
 
     void on_sender_open(proton::sender & s) OVERRIDE {
-        work_queue = &proton::make_thread_safe(s).get()->work_queue();
+        work_queue = &s.work_queue();
 
         do_cancel = cancel_fn(*this, s);
         do_tick = tick_fn(*this, s);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/include/proton/connection.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/connection.hpp b/proton-c/bindings/cpp/include/proton/connection.hpp
index 331ba82..ef75a4e 100644
--- a/proton-c/bindings/cpp/include/proton/connection.hpp
+++ b/proton-c/bindings/cpp/include/proton/connection.hpp
@@ -59,6 +59,9 @@ PN_CPP_CLASS_EXTERN connection : public internal::object<pn_connection_t>, publi
     /// container
     PN_CPP_EXTERN class container &container() const;
 
+    /// Get the work_queue for the connection.
+    PN_CPP_EXTERN class work_queue& work_queue() const;
+
     /// Get the transport for the connection.
     PN_CPP_EXTERN class transport transport() const;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/include/proton/link.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/link.hpp b/proton-c/bindings/cpp/include/proton/link.hpp
index 8534f21..8627ec9 100644
--- a/proton-c/bindings/cpp/include/proton/link.hpp
+++ b/proton-c/bindings/cpp/include/proton/link.hpp
@@ -78,6 +78,9 @@ PN_CPP_CLASS_EXTERN link : public internal::object<pn_link_t> , public endpoint
     /// The container for this link.
     PN_CPP_EXTERN class container &container() const;
 
+    /// Get the work_queue for the link.
+    PN_CPP_EXTERN class work_queue& work_queue() const;
+
     /// The connection that owns this link.
     PN_CPP_EXTERN class connection connection() const;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/include/proton/session.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/session.hpp b/proton-c/bindings/cpp/include/proton/session.hpp
index cbdf1b9..8d4184b 100644
--- a/proton-c/bindings/cpp/include/proton/session.hpp
+++ b/proton-c/bindings/cpp/include/proton/session.hpp
@@ -66,6 +66,9 @@ PN_CPP_CLASS_EXTERN session : public internal::object<pn_session_t>, public endp
     /// Get the container for this session.
     PN_CPP_EXTERN class container &container() const;
 
+    /// Get the work_queue for the session.
+    PN_CPP_EXTERN class work_queue& work_queue() const;
+
     /// Get the connection this session belongs to.
     PN_CPP_EXTERN class connection connection() const;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/include/proton/transfer.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/transfer.hpp b/proton-c/bindings/cpp/include/proton/transfer.hpp
index ea073f6..80b0860 100644
--- a/proton-c/bindings/cpp/include/proton/transfer.hpp
+++ b/proton-c/bindings/cpp/include/proton/transfer.hpp
@@ -61,6 +61,9 @@ class transfer : public internal::object<pn_delivery_t> {
     /// Return the connection for this transfer.
     PN_CPP_EXTERN class connection connection() const;
 
+    /// Get the work_queue for the transfer.
+    PN_CPP_EXTERN class work_queue& work_queue() const;
+
     /// Return the container for this transfer.
     PN_CPP_EXTERN class container &container() const;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/src/connection.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection.cpp b/proton-c/bindings/cpp/src/connection.cpp
index 5432a42..a37d3b5 100644
--- a/proton-c/bindings/cpp/src/connection.cpp
+++ b/proton-c/bindings/cpp/src/connection.cpp
@@ -76,6 +76,10 @@ container& connection::container() const {
     return *c;
 }
 
+work_queue& connection::work_queue() const {
+    return connection_context::get(pn_object()).work_queue_;
+}
+
 session_range connection::sessions() const {
     return session_range(session_iterator(make_wrapper(pn_session_head(pn_object(), 0))));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/src/link.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/link.cpp b/proton-c/bindings/cpp/src/link.cpp
index eb4ccb1..1cb87ba 100644
--- a/proton-c/bindings/cpp/src/link.cpp
+++ b/proton-c/bindings/cpp/src/link.cpp
@@ -70,6 +70,10 @@ container& link::container() const {
     return connection().container();
 }
 
+work_queue& link::work_queue() const {
+    return connection().work_queue();
+}
+
 class connection link::connection() const {
     return make_wrapper(pn_session_connection(pn_link_session(pn_object())));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/src/session.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/session.cpp b/proton-c/bindings/cpp/src/session.cpp
index a2b318e..4c3932b 100644
--- a/proton-c/bindings/cpp/src/session.cpp
+++ b/proton-c/bindings/cpp/src/session.cpp
@@ -54,6 +54,10 @@ container& session::container() const {
     return connection().container();
 }
 
+work_queue& session::work_queue() const {
+    return connection().work_queue();
+}
+
 connection session::connection() const {
     return make_wrapper(pn_session_connection(pn_object()));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d1c91a42/proton-c/bindings/cpp/src/transfer.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/transfer.cpp b/proton-c/bindings/cpp/src/transfer.cpp
index 78b6c0e..8066dd5 100644
--- a/proton-c/bindings/cpp/src/transfer.cpp
+++ b/proton-c/bindings/cpp/src/transfer.cpp
@@ -36,6 +36,8 @@ namespace proton {
 session transfer::session() const { return make_wrapper(pn_link_session(pn_delivery_link(pn_object()))); }
 connection transfer::connection() const { return make_wrapper(pn_session_connection(pn_link_session(pn_delivery_link(pn_object())))); }
 container& transfer::container() const { return connection().container(); }
+work_queue& transfer::work_queue() const { return connection().work_queue(); }
+
 
 bool transfer::settled() const { return pn_delivery_settled(pn_object()); }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[08/20] qpid-proton git commit: NO-JIRA: Header file corrections

Posted by as...@apache.org.
NO-JIRA: Header file corrections


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d168b7be
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d168b7be
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d168b7be

Branch: refs/heads/master
Commit: d168b7be34c831494ee172dd216ec7fe438845ce
Parents: 1a513d6
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri Mar 3 15:51:58 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/cpp/src/connection.cpp           |  1 +
 proton-c/bindings/cpp/src/connection_options.cpp   |  1 +
 proton-c/bindings/cpp/src/contexts.cpp             |  3 +++
 proton-c/bindings/cpp/src/include/contexts.hpp     | 10 +++-------
 proton-c/bindings/cpp/src/io/connection_driver.cpp |  1 +
 proton-c/bindings/cpp/src/io/link_namer.cpp        |  5 ++++-
 proton-c/bindings/cpp/src/messaging_adapter.cpp    |  4 ++++
 proton-c/bindings/cpp/src/session.cpp              |  1 +
 8 files changed, 18 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/connection.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection.cpp b/proton-c/bindings/cpp/src/connection.cpp
index 113a06f..11d5624 100644
--- a/proton-c/bindings/cpp/src/connection.cpp
+++ b/proton-c/bindings/cpp/src/connection.cpp
@@ -22,6 +22,7 @@
 #include "proton_bits.hpp"
 
 #include "proton/connection.hpp"
+#include "proton/connection_options.hpp"
 #include "proton/container.hpp"
 #include "proton/error.hpp"
 #include "proton/event_loop.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/connection_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_options.cpp b/proton-c/bindings/cpp/src/connection_options.cpp
index 6321df5..0848c73 100644
--- a/proton-c/bindings/cpp/src/connection_options.cpp
+++ b/proton-c/bindings/cpp/src/connection_options.cpp
@@ -19,6 +19,7 @@
  *
  */
 #include "proton/fwd.hpp"
+#include "proton/connection.hpp"
 #include "proton/connection_options.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/reconnect_timer.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/contexts.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/contexts.cpp b/proton-c/bindings/cpp/src/contexts.cpp
index 81ef5eb..152828a 100644
--- a/proton-c/bindings/cpp/src/contexts.cpp
+++ b/proton-c/bindings/cpp/src/contexts.cpp
@@ -23,6 +23,7 @@
 #include "msg.hpp"
 #include "proton_bits.hpp"
 
+#include "proton/connection_options.hpp"
 #include "proton/error.hpp"
 
 #include <proton/connection.h>
@@ -69,6 +70,8 @@ connection_context::connection_context() :
     container(0), default_session(0), link_gen(0), handler(0), listener_context_(0)
 {}
 
+listener_context::listener_context() : listen_handler_(0) {}
+
 connection_context& connection_context::get(pn_connection_t *c) {
     return ref<connection_context>(id(pn_connection_attachments(c), CONNECTION_CONTEXT));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/include/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp
index 637cbec..ab0661a 100644
--- a/proton-c/bindings/cpp/src/include/contexts.hpp
+++ b/proton-c/bindings/cpp/src/include/contexts.hpp
@@ -22,16 +22,10 @@
  *
  */
 
-#include "proton/connection.hpp"
-#include "proton/container.hpp"
-#include "proton/io/connection_driver.hpp"
 #include "proton/event_loop.hpp"
-#include "proton/listen_handler.hpp"
 #include "proton/message.hpp"
 #include "proton/internal/pn_unique_ptr.hpp"
 
-#include "proton/io/link_namer.hpp"
-
 struct pn_record_t;
 struct pn_link_t;
 struct pn_session_t;
@@ -43,6 +37,8 @@ namespace proton {
 class proton_handler;
 class reconnect_timer;
 
+namespace io {class link_namer;}
+
 // Base class for C++ classes that are used as proton contexts.
 // Contexts are pn_objects managed by pn reference counts, the C++ value is allocated in-place.
 class context {
@@ -101,7 +97,7 @@ class connection_context : public context {
 
 class listener_context : public context {
   public:
-    listener_context() : listen_handler_(0) {}
+    listener_context();
     static listener_context& get(pn_listener_t* c);
 
     listen_handler* listen_handler_;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/io/connection_driver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp
index 0f5bc33..58af052 100644
--- a/proton-c/bindings/cpp/src/io/connection_driver.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -19,6 +19,7 @@
 
 #include "proton/io/connection_driver.hpp"
 
+#include "proton/container.hpp"
 #include "proton/event_loop.hpp"
 #include "proton/error.hpp"
 #include "proton/messaging_handler.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/io/link_namer.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/link_namer.cpp b/proton-c/bindings/cpp/src/io/link_namer.cpp
index 28c35c7..2ac5402 100644
--- a/proton-c/bindings/cpp/src/io/link_namer.cpp
+++ b/proton-c/bindings/cpp/src/io/link_namer.cpp
@@ -18,8 +18,11 @@
  */
 
 #include "proton/io/link_namer.hpp"
-#include "proton_bits.hpp"
+
+#include "proton/connection.hpp"
+
 #include "contexts.hpp"
+#include "proton_bits.hpp"
 
 namespace proton {
 namespace io {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/messaging_adapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/messaging_adapter.cpp b/proton-c/bindings/cpp/src/messaging_adapter.cpp
index 3a16930..521566c 100644
--- a/proton-c/bindings/cpp/src/messaging_adapter.cpp
+++ b/proton-c/bindings/cpp/src/messaging_adapter.cpp
@@ -21,12 +21,16 @@
 
 #include "messaging_adapter.hpp"
 
+#include "proton/connection.hpp"
+#include "proton/container.hpp"
 #include "proton/delivery.hpp"
 #include "proton/error.hpp"
 #include "proton/messaging_handler.hpp"
+#include "proton/receiver.hpp"
 #include "proton/receiver_options.hpp"
 #include "proton/sender.hpp"
 #include "proton/sender_options.hpp"
+#include "proton/session.hpp"
 #include "proton/tracker.hpp"
 #include "proton/transport.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d168b7be/proton-c/bindings/cpp/src/session.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/session.cpp b/proton-c/bindings/cpp/src/session.cpp
index 8036d2c..a2b318e 100644
--- a/proton-c/bindings/cpp/src/session.cpp
+++ b/proton-c/bindings/cpp/src/session.cpp
@@ -21,6 +21,7 @@
 #include "proton/session.hpp"
 
 #include "proton/connection.hpp"
+#include "proton/io/link_namer.hpp"
 #include "proton/receiver_options.hpp"
 #include "proton/sender_options.hpp"
 #include "proton/session_options.hpp"


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[06/20] qpid-proton git commit: PROTON-1400: [C++ binding] Remove reactor container implementation files.

Posted by as...@apache.org.
PROTON-1400: [C++ binding] Remove reactor container implementation files.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9c1797cb
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9c1797cb
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9c1797cb

Branch: refs/heads/master
Commit: 9c1797cbc8451ed65c2e153e0d247783200209ae
Parents: 9fad779
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed Feb 8 20:12:36 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/src/connection_options.cpp     |   1 -
 proton-c/bindings/cpp/src/connector.cpp         | 105 ------
 proton-c/bindings/cpp/src/container_impl.cpp    | 365 -------------------
 proton-c/bindings/cpp/src/include/acceptor.hpp  |  62 ----
 proton-c/bindings/cpp/src/include/connector.hpp |  66 ----
 .../bindings/cpp/src/include/container_impl.hpp | 119 ------
 .../cpp/src/include/event_loop_impl.hpp         |  39 --
 .../bindings/cpp/src/include/proton_bits.hpp    |   4 -
 proton-c/bindings/cpp/src/include/reactor.hpp   | 100 -----
 proton-c/bindings/cpp/src/reactor.cpp           |  95 -----
 10 files changed, 956 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/connection_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_options.cpp b/proton-c/bindings/cpp/src/connection_options.cpp
index 4644094..6321df5 100644
--- a/proton-c/bindings/cpp/src/connection_options.cpp
+++ b/proton-c/bindings/cpp/src/connection_options.cpp
@@ -26,7 +26,6 @@
 #include "proton/ssl.hpp"
 #include "proton/sasl.hpp"
 
-#include "acceptor.hpp"
 #include "contexts.hpp"
 #include "messaging_adapter.hpp"
 #include "msg.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/connector.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connector.cpp b/proton-c/bindings/cpp/src/connector.cpp
deleted file mode 100644
index 0467d60..0000000
--- a/proton-c/bindings/cpp/src/connector.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "connector.hpp"
-
-#include "proton/connection.hpp"
-#include "proton/transport.hpp"
-#include "proton/container.hpp"
-#include "proton/reconnect_timer.hpp"
-#include "proton/sasl.hpp"
-#include "proton/url.hpp"
-
-#include "container_impl.hpp"
-#include "proton_bits.hpp"
-#include "proton_event.hpp"
-
-#include <proton/connection.h>
-#include <proton/transport.h>
-
-namespace proton {
-
-container::impl::connector::connector(connection&c, const connection_options& options, const url& a) :
-    connection_(c), options_(options), address_(a), reconnect_timer_(0)
-{}
-
-container::impl::connector::~connector() { delete reconnect_timer_; }
-
-void container::impl::connector::reconnect_timer(const class reconnect_timer &rt) {
-    delete reconnect_timer_;
-    reconnect_timer_ = new class reconnect_timer(rt);
-}
-
-void container::impl::connector::connect() {
-    pn_transport_t *pnt = pn_transport();
-    transport t(make_wrapper(pnt));
-    pn_transport_bind(pnt, unwrap(connection_));
-    pn_decref(pnt);
-    // Apply options to the new transport.
-    options_.apply_bound(connection_);
-}
-
-void container::impl::connector::on_connection_local_open(proton_event &) {
-    connect();
-}
-
-void container::impl::connector::on_connection_remote_open(proton_event &) {
-    if (reconnect_timer_) {
-        reconnect_timer_->reset();
-    }
-}
-
-void container::impl::connector::on_connection_init(proton_event &) {
-}
-
-void container::impl::connector::on_transport_tail_closed(proton_event &e) {
-    on_transport_closed(e);
-}
-
-void container::impl::connector::on_transport_closed(proton_event &) {
-    if (!connection_) return;
-    if (connection_.active()) {
-        if (reconnect_timer_) {
-            pn_transport_unbind(unwrap(connection_.transport()));
-            int delay = reconnect_timer_->next_delay(timestamp::now());
-            if (delay >= 0) {
-                if (delay == 0) {
-                    // log "Disconnected, reconnecting..."
-                    connect();
-                    return;
-                }
-                else {
-                    // log "Disconnected, reconnecting in " <<  delay << " milliseconds"
-                    container::impl::schedule(connection_.container(), delay, this);
-                    return;
-                }
-            }
-        }
-    }
-    pn_connection_release(unwrap(connection_));
-    connection_  = 0;
-}
-
-void container::impl::connector::on_timer_task(proton_event &) {
-    connect();
-}
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_impl.cpp b/proton-c/bindings/cpp/src/container_impl.cpp
deleted file mode 100644
index e0851a9..0000000
--- a/proton-c/bindings/cpp/src/container_impl.cpp
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/connection_options.hpp"
-#include "proton/connection.hpp"
-#include "proton/error.hpp"
-#include "proton/event_loop.hpp"
-#include "proton/listener.hpp"
-#include "proton/receiver.hpp"
-#include "proton/sender.hpp"
-#include "proton/session.hpp"
-#include "proton/ssl.hpp"
-#include "proton/sasl.hpp"
-#include "proton/thread_safe.hpp"
-#include "proton/transport.hpp"
-#include "proton/url.hpp"
-#include "proton/uuid.hpp"
-
-#include "acceptor.hpp"
-#include "connector.hpp"
-#include "container_impl.hpp"
-#include "contexts.hpp"
-#include "event_loop_impl.hpp"
-#include "messaging_adapter.hpp"
-#include "msg.hpp"
-#include "proton_bits.hpp"
-#include "proton_event.hpp"
-
-#include <proton/connection.h>
-#include <proton/handlers.h>
-#include <proton/reactor.h>
-#include <proton/session.h>
-
-namespace proton {
-
-class container::impl::handler_context {
-  public:
-    static handler_context& get(pn_handler_t* h) {
-        return *reinterpret_cast<handler_context*>(pn_handler_mem(h));
-    }
-    static void cleanup(pn_handler_t*) {}
-
-    /*
-     * NOTE: this call, at the transition from C to C++ is possibly
-     * the biggest performance bottleneck.  "Average" clients ignore
-     * 90% of these events.  Current strategy is to create the
-     * messaging_event on the stack.  For success, the messaging_event
-     * should be small and free of indirect malloc/free/new/delete.
-     */
-
-    static void dispatch(pn_handler_t *c_handler, pn_event_t *c_event, pn_event_type_t)
-    {
-        handler_context& hc(handler_context::get(c_handler));
-        proton_event pevent(c_event, hc.container_);
-        pevent.dispatch(*hc.handler_);
-        return;
-    }
-
-    container *container_;
-    proton_handler *handler_;
-};
-
-// Used to sniff for connector events before the reactor's global handler sees them.
-class container::impl::override_handler : public proton_handler
-{
-  public:
-    internal::pn_ptr<pn_handler_t> base_handler;
-    container::impl &container_impl_;
-
-    override_handler(pn_handler_t *h, container::impl &c) : base_handler(h), container_impl_(c) {}
-
-    virtual void on_unhandled(proton_event &pe) {
-        proton_event::event_type type = pe.type();
-        if (type==proton_event::EVENT_NONE) return;  // Also not from the reactor
-
-        pn_event_t *cevent = pe.pn_event();
-        pn_connection_t *conn = pn_event_connection(cevent);
-        if (conn) {
-            proton_handler *oh = connection_context::get(conn).handler.get();
-            if (oh && type != proton_event::CONNECTION_INIT) {
-                // Send event to connector
-                pe.dispatch(*oh);
-            }
-            else if (!oh && type == proton_event::CONNECTION_INIT) {
-                // Newly accepted connection from lister socket
-                connection c(make_wrapper(conn));
-                container_impl_.configure_server_connection(c);
-            }
-        }
-        pn_handler_dispatch(base_handler.get(), cevent, pn_event_type_t(type));
-    }
-};
-
-internal::pn_ptr<pn_handler_t> container::impl::cpp_handler(proton_handler *h) {
-    pn_handler_t *handler = h ? pn_handler_new(&handler_context::dispatch,
-                                               sizeof(class handler_context),
-                                               &handler_context::cleanup) : 0;
-    if (handler) {
-        handler_context &hc = handler_context::get(handler);
-        hc.container_ = &container_;
-        hc.handler_ = h;
-    }
-    return internal::take_ownership(handler);
-}
-
-container::impl::impl(container& c, const std::string& id, messaging_handler *mh) :
-    container_(c),
-    reactor_(reactor::create()),
-    id_(id.empty() ? uuid::random().str() : id),
-    auto_stop_(true)
-{
-    container_context::set(reactor_, container_);
-
-    // Set our own global handler that "subclasses" the existing one
-    pn_handler_t *global_handler = reactor_.pn_global_handler();
-    proton_handler* oh = new override_handler(global_handler, *this);
-    handlers_.push_back(oh);
-    reactor_.pn_global_handler(cpp_handler(oh).get());
-    if (mh) {
-        proton_handler* h = new messaging_adapter(*mh);
-        handlers_.push_back(h);
-        reactor_.pn_handler(cpp_handler(h).get());
-    }
-
-    // Note: we have just set up the following handlers that see
-    // events in this order: messaging_adapter, connector override,
-    // the reactor's default globalhandler (pn_iohandler)
-}
-
-namespace {
-void close_acceptor(acceptor a) {
-    listen_handler*& lh = listener_context::get(unwrap(a)).listen_handler_;
-    if (lh) {
-        lh->on_close();
-        lh = 0;
-    }
-    a.close();
-}
-}
-
-container::impl::~impl() {
-    for (acceptors::iterator i = acceptors_.begin(); i != acceptors_.end(); ++i)
-        close_acceptor(i->second);
-}
-
-// TODO aconway 2016-06-07: this is not thread safe. It is sufficient for using
-// default_container::schedule() inside a handler but not for inject() from
-// another thread.
-bool event_loop::impl::inject(void_function0& f) {
-    try { f(); } catch(...) {}
-    return true;
-}
-
-#if PN_CPP_HAS_STD_FUNCTION
-bool event_loop::impl::inject(std::function<void()> f) {
-    try { f(); } catch(...) {}
-    return true;
-}
-#endif
-
-returned<connection> container::impl::connect(const std::string &urlstr, const connection_options &user_opts) {
-    connection_options opts = client_connection_options(); // Defaults
-    opts.update(user_opts);
-    messaging_handler* mh = opts.handler();
-    internal::pn_ptr<pn_handler_t> chandler;
-    if (mh) {
-        proton_handler* h = new messaging_adapter(*mh);
-        handlers_.push_back(h);
-        chandler = cpp_handler(h);
-    }
-
-    proton::url  url(urlstr);
-    connection conn(reactor_.connection_to_host(url.host(), url.port(), chandler.get()));
-    internal::pn_unique_ptr<connector> ctor(new connector(conn, opts, url));
-    connection_context& cc(connection_context::get(unwrap(conn)));
-    cc.handler.reset(ctor.release());
-    cc.event_loop_ = new event_loop::impl;
-
-    pn_connection_t *pnc = unwrap(conn);
-    pn_connection_set_container(pnc, id_.c_str());
-    pn_connection_set_hostname(pnc, url.host().c_str());
-    if (!url.user().empty())
-        pn_connection_set_user(pnc, url.user().c_str());
-    if (!url.password().empty())
-        pn_connection_set_password(pnc, url.password().c_str());
-
-    conn.open(opts);
-    return make_thread_safe(conn);
-}
-
-returned<sender> container::impl::open_sender(const std::string &url, const proton::sender_options &o1, const connection_options &o2) {
-    proton::sender_options lopts(sender_options_);
-    lopts.update(o1);
-    connection_options copts(client_connection_options_);
-    copts.update(o2);
-    connection conn = connect(url, copts);
-    return make_thread_safe(conn.default_session().open_sender(proton::url(url).path(), lopts));
-}
-
-returned<receiver> container::impl::open_receiver(const std::string &url, const proton::receiver_options &o1, const connection_options &o2) {
-    proton::receiver_options lopts(receiver_options_);
-    lopts.update(o1);
-    connection_options copts(client_connection_options_);
-    copts.update(o2);
-    connection conn = connect(url, copts);
-    return make_thread_safe(
-        conn.default_session().open_receiver(proton::url(url).path(), lopts));
-}
-
-listener container::impl::listen(const std::string& url, listen_handler& lh) {
-    if (acceptors_.find(url) != acceptors_.end())
-        throw error("already listening on " + url);
-    connection_options opts = server_connection_options(); // Defaults
-
-    messaging_handler* mh = opts.handler();
-    internal::pn_ptr<pn_handler_t> chandler;
-    if (mh) {
-        proton_handler* h = new messaging_adapter(*mh);
-        handlers_.push_back(h);
-        chandler = cpp_handler(h);
-    }
-
-    proton::url u(url);
-    pn_acceptor_t *acptr = pn_reactor_acceptor(
-        unwrap(reactor_), u.host().c_str(), u.port().c_str(), chandler.get());
-    if (!acptr) {
-        std::string err(pn_error_text(pn_reactor_error(unwrap(reactor_))));
-        lh.on_error(err);
-        lh.on_close();
-        throw error(err);
-    }
-    // Do not use pn_acceptor_set_ssl_domain().  Manage the incoming connections ourselves for
-    // more flexibility (i.e. ability to change the server cert for a long running listener).
-    listener_context& lc(listener_context::get(acptr));
-    lc.listen_handler_ = &lh;
-    lc.ssl = u.scheme() == url::AMQPS;
-    listener_context::get(acptr).listen_handler_ = &lh;
-    acceptors_[url] = make_wrapper(acptr);
-    return listener(container_, url);
-}
-
-void container::impl::stop_listening(const std::string& url) {
-    acceptors::iterator i = acceptors_.find(url);
-    if (i != acceptors_.end())
-        close_acceptor(i->second);
-}
-
-void container::impl::schedule(impl& ci, int delay, proton_handler *h) {
-    internal::pn_ptr<pn_handler_t> task_handler;
-    if (h)
-        task_handler = ci.cpp_handler(h);
-    ci.reactor_.schedule(delay, task_handler.get());
-}
-
-void container::impl::schedule(container& c, int delay, proton_handler *h) {
-    schedule(*c.impl_.get(), delay, h);
-}
-
-namespace {
-// Abstract base for timer_handler_std and timer_handler_03
-struct timer_handler : public proton_handler, public void_function0 {
-    void on_timer_task(proton_event& ) PN_CPP_OVERRIDE {
-        (*this)();
-        delete this;
-    }
-    void on_reactor_final(proton_event&) PN_CPP_OVERRIDE {
-        delete this;
-    }
-};
-
-struct timer_handler_03 : public timer_handler {
-    void_function0& func;
-    timer_handler_03(void_function0& f): func(f) {}
-    void operator()() PN_CPP_OVERRIDE { func(); }
-};
-}
-
-void container::impl::schedule(duration delay, void_function0& f) {
-    schedule(*this, delay.milliseconds(), new timer_handler_03(f));
-}
-
-#if PN_CPP_HAS_STD_FUNCTION
-namespace {
-struct timer_handler_std : public timer_handler {
-    std::function<void()> func;
-    timer_handler_std(std::function<void()> f): func(f) {}
-    void operator()() PN_CPP_OVERRIDE { func(); }
-};
-}
-
-void container::impl::schedule(duration delay, std::function<void()> f) {
-    schedule(*this, delay.milliseconds(), new timer_handler_std(f));
-}
-#endif
-
-void container::impl::client_connection_options(const connection_options &opts) {
-    client_connection_options_ = opts;
-}
-
-void container::impl::server_connection_options(const connection_options &opts) {
-    server_connection_options_ = opts;
-}
-
-void container::impl::sender_options(const proton::sender_options &opts) {
-    sender_options_ = opts;
-}
-
-void container::impl::receiver_options(const proton::receiver_options &opts) {
-    receiver_options_ = opts;
-}
-
-void container::impl::configure_server_connection(connection &c) {
-    pn_acceptor_t *pnp = pn_connection_acceptor(unwrap(c));
-    listener_context &lc(listener_context::get(pnp));
-    pn_connection_set_container(unwrap(c), id_.c_str());
-    connection_options opts = server_connection_options_;
-    opts.update(lc.get_options());
-    // Unbound options don't apply to server connection
-    opts.apply_bound(c);
-    // Handler applied separately
-    messaging_handler* mh = opts.handler();
-    if (mh) {
-        proton_handler* h = new messaging_adapter(*mh);
-        handlers_.push_back(h);
-        internal::pn_ptr<pn_handler_t> chandler = cpp_handler(h);
-        pn_record_t *record = pn_connection_attachments(unwrap(c));
-        pn_record_set_handler(record, chandler.get());
-    }
-    connection_context::get(unwrap(c)).event_loop_ = new event_loop::impl;
-}
-
-void container::impl::run() {
-    do {
-        reactor_.run();
-    } while (!auto_stop_);
-}
-
-void container::impl::stop(const error_condition&) {
-    reactor_.stop();
-    auto_stop_ = true;
-}
-
-void container::impl::auto_stop(bool set) {
-    auto_stop_ = set;
-}
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/include/acceptor.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/acceptor.hpp b/proton-c/bindings/cpp/src/include/acceptor.hpp
deleted file mode 100644
index 9a25592..0000000
--- a/proton-c/bindings/cpp/src/include/acceptor.hpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef PROTON_ACCEPTOR_HPP
-#define PROTON_ACCEPTOR_HPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/internal/export.hpp"
-#include "proton/internal/object.hpp"
-
-#include <proton/reactor.h>
-
-struct pn_acceptor_t;
-
-namespace proton {
-
-/// A context for accepting inbound connections.
-///
-/// @see container::listen
-class acceptor : public internal::object<pn_acceptor_t> {
-    /// @cond INTERNAL
-    acceptor(pn_acceptor_t* a) : internal::object<pn_acceptor_t>(a) {}
-    /// @endcond
-
-  public:
-    acceptor() : internal::object<pn_acceptor_t>(0) {}
-
-    /// Close the acceptor.
-    PN_CPP_EXTERN void close();
-
-    /// Return the current set of connection options applied to
-    /// inbound connectons by the acceptor.
-    ///
-    /// Note that changes made to the connection options only affect
-    /// connections accepted after this call returns.
-    PN_CPP_EXTERN class connection_options &connection_options();
-
-    /// @cond INTERNAL
-  friend class internal::factory<acceptor>;
-    /// @endcond
-};
-
-} // proton
-
-#endif // PROTON_ACCEPTOR_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/include/connector.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/connector.hpp b/proton-c/bindings/cpp/src/include/connector.hpp
deleted file mode 100644
index 6bcd0db..0000000
--- a/proton-c/bindings/cpp/src/include/connector.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef PROTON_CPP_CONNECTOR_HANDLER_H
-#define PROTON_CPP_CONNECTOR_HANDLER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/connection.hpp"
-#include "proton/connection_options.hpp"
-#include <proton/event.h>
-#include <proton/reactor.h>
-#include "proton/url.hpp"
-
-#include "container_impl.hpp"
-#include "proton_handler.hpp"
-
-#include <string>
-
-
-namespace proton {
-
-class reconnect_timer;
-
-class container::impl::connector : public proton_handler
-{
-  public:
-    connector(connection &c, const connection_options &options, const url&);
-    ~connector();
-    const url &address() const { return address_; }
-    void connect();
-    void reconnect_timer(const class reconnect_timer &);
-    virtual void on_connection_local_open(proton_event &e);
-    virtual void on_connection_remote_open(proton_event &e);
-    virtual void on_connection_init(proton_event &e);
-    virtual void on_transport_closed(proton_event &e);
-    virtual void on_transport_tail_closed(proton_event &e);
-    virtual void on_timer_task(proton_event &e);
-
-  private:
-    connection connection_;
-    const connection_options options_;
-    const url address_;
-    class reconnect_timer *reconnect_timer_;
-};
-
-
-}
-
-#endif  /*!PROTON_CPP_CONNECTOR_HANDLER_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/include/container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/container_impl.hpp b/proton-c/bindings/cpp/src/include/container_impl.hpp
deleted file mode 100644
index 7443150..0000000
--- a/proton-c/bindings/cpp/src/include/container_impl.hpp
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef PROTON_CPP_CONTAINERIMPL_H
-#define PROTON_CPP_CONTAINERIMPL_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/fwd.hpp"
-#include "proton/container.hpp"
-#include "proton/connection.hpp"
-#include "proton/connection_options.hpp"
-#include "proton/duration.hpp"
-#include "proton/sender.hpp"
-#include "proton/sender_options.hpp"
-#include "proton/receiver.hpp"
-#include "proton/receiver_options.hpp"
-
-#include "messaging_adapter.hpp"
-#include "reactor.hpp"
-#include "proton_bits.hpp"
-#include "proton_handler.hpp"
-
-#include <list>
-#include <map>
-#include <string>
-
-namespace proton {
-
-class dispatch_helper;
-class connector;
-class acceptor;
-class url;
-class listen_handler;
-
-class container::impl {
-  public:
-    impl(container& c, const std::string& id, messaging_handler* = 0);
-    ~impl();
-    std::string id() const { return id_; }
-    returned<connection> connect(const std::string&, const connection_options&);
-    returned<sender> open_sender(
-        const std::string&, const proton::sender_options &, const connection_options &);
-    returned<receiver> open_receiver(
-        const std::string&, const proton::receiver_options &, const connection_options &);
-    listener listen(const std::string&, listen_handler& lh);
-    void stop_listening(const std::string&);
-    void client_connection_options(const connection_options &);
-    connection_options client_connection_options() const { return client_connection_options_; }
-    void server_connection_options(const connection_options &);
-    connection_options server_connection_options() const { return server_connection_options_; }
-    void sender_options(const proton::sender_options&);
-    class sender_options sender_options() const { return sender_options_; }
-    void receiver_options(const proton::receiver_options&);
-    class receiver_options receiver_options() const { return receiver_options_; }
-    void run();
-    void stop(const error_condition& err);
-    void auto_stop(bool set);
-    void schedule(duration, void_function0&);
-#if PN_CPP_HAS_STD_FUNCTION
-    void schedule(duration, std::function<void()>);
-#endif
-
-    // non-interface functionality
-    class connector;
-
-    void configure_server_connection(connection &c);
-    static void schedule(impl& ci, int delay, proton_handler *h);
-    static void schedule(container& c, int delay, proton_handler *h);
-    template <class T> static void set_handler(T s, messaging_handler* h);
-
-  private:
-    class handler_context;
-    class override_handler;
-
-    internal::pn_ptr<pn_handler_t> cpp_handler(proton_handler *h);
-
-    container& container_;
-    reactor reactor_;
-    // Keep a list of all the handlers used by the container so they last as long as the container
-    std::list<internal::pn_unique_ptr<proton_handler> > handlers_;
-    std::string id_;
-    connection_options client_connection_options_;
-    connection_options server_connection_options_;
-    proton::sender_options sender_options_;
-    proton::receiver_options receiver_options_;
-    typedef std::map<std::string, acceptor> acceptors;
-    acceptors acceptors_;
-    bool auto_stop_;
-};
-
-template <class T>
-void container::impl::set_handler(T s, messaging_handler* mh) {
-    pn_record_t *record = internal::get_attachments(unwrap(s));
-    proton_handler* h = new messaging_adapter(*mh);
-    impl* ci = s.container().impl_.get();
-    ci->handlers_.push_back(h);
-    pn_record_set_handler(record, ci->cpp_handler(h).get());
-}
-
-}
-
-#endif  /*!PROTON_CPP_CONTAINERIMPL_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/include/event_loop_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/event_loop_impl.hpp b/proton-c/bindings/cpp/src/include/event_loop_impl.hpp
deleted file mode 100644
index b34a981..0000000
--- a/proton-c/bindings/cpp/src/include/event_loop_impl.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef PROTON_CPP_EVENT_LOOP_IMPL_HPP
-#define PROTON_CPP_EVENT_LOOP_IMPL_HPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/fwd.hpp"
-
-namespace proton {
-
-class event_loop::impl {
-  public:
-    bool inject(void_function0& f);
-#if PN_CPP_HAS_CPP11
-    bool inject(std::function<void()> f);
-#endif
-};
-
-}
-
-#endif // PROTON_CPP_EVENT_LOOP_IMPL_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/include/proton_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_bits.hpp b/proton-c/bindings/cpp/src/include/proton_bits.hpp
index e72f343..fdd79b5 100644
--- a/proton-c/bindings/cpp/src/include/proton_bits.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_bits.hpp
@@ -102,11 +102,9 @@ template <> struct wrapped<transfer> { typedef pn_delivery_t type; };
 template <> struct wrapped<tracker> { typedef pn_delivery_t type; };
 template <> struct wrapped<delivery> { typedef pn_delivery_t type; };
 template <> struct wrapped<error_condition> { typedef pn_condition_t type; };
-template <> struct wrapped<acceptor> { typedef pn_acceptor_t type; }; // TODO aconway 2016-05-13: reactor only
 template <> struct wrapped<terminus> { typedef pn_terminus_t type; };
 template <> struct wrapped<source> { typedef pn_terminus_t type; };
 template <> struct wrapped<target> { typedef pn_terminus_t type; };
-template <> struct wrapped<reactor> { typedef pn_reactor_t type; };
 
 template <class T> struct wrapper {};
 template <> struct wrapper<pn_data_t> { typedef internal::data type; };
@@ -118,9 +116,7 @@ template <> struct wrapper<pn_session_t> { typedef session type; };
 template <> struct wrapper<pn_link_t> { typedef link type; };
 template <> struct wrapper<pn_delivery_t> { typedef transfer type; };
 template <> struct wrapper<pn_condition_t> { typedef error_condition type; };
-template <> struct wrapper<pn_acceptor_t> { typedef acceptor type; };
 template <> struct wrapper<pn_terminus_t> { typedef terminus type; };
-template <> struct wrapper<pn_reactor_t> { typedef reactor type; };
 
 // Factory for wrapper types
 template <class T>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/include/reactor.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/reactor.hpp b/proton-c/bindings/cpp/src/include/reactor.hpp
deleted file mode 100644
index 07678e4..0000000
--- a/proton-c/bindings/cpp/src/include/reactor.hpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#ifndef REACTOR_HPP
-#define REACTOR_HPP
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/// @cond INTERNAL
-/// XXX remove
-
-#include "proton/fwd.hpp"
-#include "proton/internal/object.hpp"
-#include "proton/duration.hpp"
-#include "proton/timestamp.hpp"
-
-struct pn_reactor_t;
-struct pn_handler_t;
-struct pn_io_t;
-
-namespace proton {
-
-class acceptor;
-
-class reactor : public internal::object<pn_reactor_t> {
-  public:
-    reactor(pn_reactor_t* r = 0) : internal::object<pn_reactor_t>(r) {}
-
-    /** Create a new reactor. */
-    static reactor create();
-
-    /** Open a connection to url and create a receiver with source=url.path() */
-    acceptor listen(const proton::url &);
-
-    /** Run the event loop, return when all connections and acceptors are closed. */
-    void run();
-
-    /** Start the reactor, you must call process() to process events */
-    void start();
-
-    /** Process events, return true if there are more events to process. */
-    bool process();
-
-    /** Stop the reactor, causes run() to return and process() to return false. */
-    void stop();
-
-    /// Identifier for the container
-    std::string id() const;
-
-    /// Get timeout, process() will return if there is no activity within the timeout.
-    duration timeout();
-
-    /// Set timeout, process() will return if there is no activity within the timeout.
-    void timeout(duration timeout);
-
-    timestamp mark();
-    timestamp now();
-
-    void schedule(int, pn_handler_t*);
-
-    class connection connection(pn_handler_t*) const;
-
-    class connection connection_to_host(const std::string &host, const std::string &port, pn_handler_t*) const;
-
-    pn_handler_t* pn_handler() const;
-
-    void pn_handler(pn_handler_t* );
-
-    pn_handler_t* pn_global_handler() const;
-
-    void pn_global_handler(pn_handler_t* );
-
-    pn_io_t* pn_io() const;
-
-    void wakeup();
-    bool quiesced();
-    void yield();
-
-  friend class internal::factory<reactor>;
-};
-
-}
-
-/// @endcond
-
-#endif // REACTOR_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9c1797cb/proton-c/bindings/cpp/src/reactor.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/reactor.cpp b/proton-c/bindings/cpp/src/reactor.cpp
deleted file mode 100644
index 39f670f..0000000
--- a/proton-c/bindings/cpp/src/reactor.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "reactor.hpp"
-#include "acceptor.hpp"
-
-#include "proton/connection.hpp"
-#include "proton/url.hpp"
-
-#include "contexts.hpp"
-#include "proton_bits.hpp"
-
-#include <proton/reactor.h>
-
-namespace proton {
-
-reactor reactor::create() {
-    return internal::take_ownership(pn_reactor()).get();
-}
-
-void reactor::run() { pn_reactor_run(pn_object()); }
-void reactor::start() { pn_reactor_start(pn_object()); }
-bool reactor::process() { return pn_reactor_process(pn_object()); }
-void reactor::stop() { pn_reactor_stop(pn_object()); }
-void reactor::wakeup() { pn_reactor_wakeup(pn_object()); }
-bool reactor::quiesced() { return pn_reactor_quiesced(pn_object()); }
-void reactor::yield() { pn_reactor_yield(pn_object()); }
-timestamp reactor::mark() { return timestamp(pn_reactor_mark(pn_object())); }
-timestamp reactor::now() { return timestamp(pn_reactor_now(pn_object())); }
-
-void acceptor::close() { pn_acceptor_close(pn_object()); }
-
-acceptor reactor::listen(const url& url){
-    return make_wrapper(pn_reactor_acceptor(pn_object(), url.host().c_str(), url.port().c_str(), 0));
-}
-
-void reactor::schedule(int delay, pn_handler_t* handler) {
-    pn_reactor_schedule(pn_object(), delay, handler);
-}
-
-connection reactor::connection(pn_handler_t* h) const {
-    return make_wrapper(pn_reactor_connection(pn_object(), h));
-}
-
-connection reactor::connection_to_host(const std::string &host, const std::string &port, pn_handler_t* h) const {
-    return make_wrapper(pn_reactor_connection_to_host(pn_object(), host.c_str(), port.c_str(), h));
-}
-
-void reactor::pn_handler(pn_handler_t* h) {
-    pn_reactor_set_handler(pn_object(), h);
-}
-
-pn_handler_t* reactor::pn_handler() const {
-    return pn_reactor_get_handler(pn_object());
-}
-
-void reactor::pn_global_handler(pn_handler_t* h) {
-    pn_reactor_set_global_handler(pn_object(), h);
-}
-
-pn_handler_t* reactor::pn_global_handler() const {
-    return pn_reactor_get_global_handler(pn_object());
-}
-
-duration reactor::timeout() {
-    pn_millis_t tmo = pn_reactor_get_timeout(pn_object());
-    if (tmo == PN_MILLIS_MAX)
-        return duration::FOREVER;
-    return duration(tmo);
-}
-
-void reactor::timeout(duration timeout) {
-    if (timeout == duration::FOREVER || timeout.milliseconds() > PN_MILLIS_MAX)
-        pn_reactor_set_timeout(pn_object(), PN_MILLIS_MAX);
-    else
-        pn_reactor_set_timeout(pn_object(), timeout.milliseconds());
-}
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[16/20] qpid-proton git commit: PROTON-1482: [C++ binding] Implemented scheduling delaying work on a work_queue

Posted by as...@apache.org.
PROTON-1482: [C++ binding] Implemented scheduling delaying work on a work_queue


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/88c2d7d4
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/88c2d7d4
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/88c2d7d4

Branch: refs/heads/master
Commit: 88c2d7d481a6da96f85a6781ae27b488cfacd801
Parents: ca446ea
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 19 00:59:55 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/cpp/include/proton/fwd.hpp    |  1 +
 .../bindings/cpp/include/proton/work_queue.hpp  |  8 ++++++++
 .../src/include/proactor_work_queue_impl.hpp    |  3 +--
 .../cpp/src/proactor_container_impl.cpp         | 21 +++++++++++++-------
 proton-c/bindings/cpp/src/work_queue.cpp        |  8 ++++++++
 5 files changed, 32 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/88c2d7d4/proton-c/bindings/cpp/include/proton/fwd.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/fwd.hpp b/proton-c/bindings/cpp/include/proton/fwd.hpp
index b839f42..5ade5fd 100644
--- a/proton-c/bindings/cpp/include/proton/fwd.hpp
+++ b/proton-c/bindings/cpp/include/proton/fwd.hpp
@@ -29,6 +29,7 @@ class connection;
 class connection_options;
 class container;
 class delivery;
+class duration;
 class error_condition;
 class event;
 class message;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/88c2d7d4/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index fe739f5..bef041c 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -94,6 +94,14 @@ class PN_CPP_CLASS_EXTERN work_queue {
     /// or f() cannot be injected for any other reason.
     PN_CPP_EXTERN bool add(work f);
 
+    /// Add work to the work queue after duration: f() will be called after the duration
+    /// serialised with other work in the queue: possibly in another thread.
+    ///
+    /// The scheduled execution is "best effort" and it is possible that after the elapsed duration
+    /// the work will not be able to be injected into the serialised context - there will be no
+    /// indication of this.
+    PN_CPP_EXTERN void schedule(duration, work);
+
   private:
     PN_CPP_EXTERN static work_queue& get(pn_connection_t*);
     PN_CPP_EXTERN static work_queue& get(pn_session_t*);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/88c2d7d4/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
index ac0f803..1c94254 100644
--- a/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
@@ -23,8 +23,6 @@
  */
 
 #include "proton/fwd.hpp"
-#include "proton/internal/config.hpp"
-#include "proton/work_queue.hpp"
 
 namespace proton {
 
@@ -32,6 +30,7 @@ class work_queue::impl {
   public:
     virtual ~impl() {};
     virtual bool add(work f) = 0;
+    virtual void schedule(duration, work) = 0;
     virtual void run_all_jobs() = 0;
     virtual void finished() = 0;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/88c2d7d4/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index 0135c08..62115fd 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -45,17 +45,26 @@ namespace proton {
 
 class container::impl::common_work_queue : public work_queue::impl {
   public:
-    common_work_queue(): finished_(false) {}
+    common_work_queue(container::impl& c): container_(c), finished_(false) {}
 
     typedef std::vector<work> jobs;
 
     void run_all_jobs();
     void finished() { finished_ = true; }
+    void schedule(duration, work);
 
+    container::impl& container_;
     jobs jobs_;
     bool finished_;
 };
 
+void container::impl::common_work_queue::schedule(duration d, work f) {
+    // Note this is an unbounded work queue.
+    // A resource-safe implementation should be bounded.
+    if (finished_) return;
+    container_.schedule(d, make_work(&work_queue::impl::add, (work_queue::impl*)this, f));
+}
+
 void container::impl::common_work_queue::run_all_jobs() {
     jobs j;
     // Lock this operation for mt
@@ -69,7 +78,7 @@ void container::impl::common_work_queue::run_all_jobs() {
 
 class container::impl::connection_work_queue : public common_work_queue {
   public:
-    connection_work_queue(pn_connection_t* c): connection_(c) {}
+    connection_work_queue(container::impl& ct, pn_connection_t* c): common_work_queue(ct), connection_(c) {}
 
     bool add(work f);
 
@@ -87,12 +96,10 @@ bool container::impl::connection_work_queue::add(work f) {
 
 class container::impl::container_work_queue : public common_work_queue {
   public:
-    container_work_queue(container::impl& c): container_(c) {}
+    container_work_queue(container::impl& c): common_work_queue(c) {}
     ~container_work_queue() { container_.remove_work_queue(this); }
 
     bool add(work f);
-
-    container::impl& container_;
 };
 
 bool container::impl::container_work_queue::add(work f) {
@@ -147,7 +154,7 @@ proton::connection container::impl::connect_common(
     connection_context& cc(connection_context::get(pnc));
     cc.container = &container_;
     cc.handler = mh;
-    cc.work_queue_ = new container::impl::connection_work_queue(pnc);
+    cc.work_queue_ = new container::impl::connection_work_queue(*container_.impl_, pnc);
 
     pn_connection_set_container(pnc, id_.c_str());
     pn_connection_set_hostname(pnc, url.host().c_str());
@@ -327,7 +334,7 @@ bool container::impl::handle(pn_event_t* event) {
         cc.container = &container_;
         cc.listener_context_ = &lc;
         cc.handler = opts.handler();
-        cc.work_queue_ = new container::impl::connection_work_queue(c);
+        cc.work_queue_ = new container::impl::connection_work_queue(*container_.impl_, c);
         pn_listener_accept(l, c);
         return false;
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/88c2d7d4/proton-c/bindings/cpp/src/work_queue.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/work_queue.cpp b/proton-c/bindings/cpp/src/work_queue.cpp
index 77fa3fb..f8fc45c 100644
--- a/proton-c/bindings/cpp/src/work_queue.cpp
+++ b/proton-c/bindings/cpp/src/work_queue.cpp
@@ -19,6 +19,8 @@
 
 #include "proton/work_queue.hpp"
 
+#include "proton/duration.hpp"
+
 #include "contexts.hpp"
 #include "proactor_container_impl.hpp"
 #include "proactor_work_queue_impl.hpp"
@@ -41,6 +43,12 @@ bool work_queue::add(work f) {
     return impl_->add(f);
 }
 
+void work_queue::schedule(duration d, work f) {
+    // If we have no actual work queue, then can't defer
+    if (!impl_) return;
+    return impl_->schedule(d, f);
+}
+
 work_queue& work_queue::get(pn_connection_t* c) {
     return connection_context::get(c).work_queue_;
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[05/20] qpid-proton git commit: PROTON-1400: [C++ binding] Proactor container implementation - Remove all reactor use - Rearrange object context code - Change container includes to proactor container includes - Add sender/receiver options API to connecti

Posted by as...@apache.org.
PROTON-1400: [C++ binding] Proactor container implementation
- Remove all reactor use
- Rearrange object context code
- Change container includes to proactor container includes
- Add sender/receiver options API to connection so we never need container in handlers
- Rework connection_driver remove all use of container
- Change signature of listener_handler callbacks to supply the listener


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9fad779c
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9fad779c
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9fad779c

Branch: refs/heads/master
Commit: 9fad779c98dcc2ccc75e5055d7333e9dd862c235
Parents: 6f88f52
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed Feb 8 02:32:36 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/ssl.cpp                            |   9 +-
 proton-c/bindings/cpp/CMakeLists.txt            |   6 +-
 .../bindings/cpp/include/proton/connection.hpp  |   6 +
 .../bindings/cpp/include/proton/container.hpp   |   6 -
 .../cpp/include/proton/internal/config.hpp      |   8 +
 .../cpp/include/proton/io/connection_driver.hpp |  25 +-
 .../include/proton/io/container_impl_base.hpp   | 144 -------
 .../cpp/include/proton/listen_handler.hpp       |   6 +-
 .../bindings/cpp/include/proton/listener.hpp    |  18 +-
 proton-c/bindings/cpp/src/connection.cpp        |  27 +-
 .../bindings/cpp/src/connection_driver_test.cpp |  11 +-
 .../bindings/cpp/src/connection_options.cpp     |  30 +-
 proton-c/bindings/cpp/src/container.cpp         |  20 +-
 proton-c/bindings/cpp/src/container_test.cpp    |  11 +-
 proton-c/bindings/cpp/src/contexts.cpp          |  55 +--
 proton-c/bindings/cpp/src/event_loop.cpp        |   2 +-
 proton-c/bindings/cpp/src/include/contexts.hpp  |  56 +--
 .../cpp/src/include/messaging_adapter.hpp       |   2 -
 .../cpp/src/include/proactor_container_impl.hpp | 133 ++++++
 .../src/include/proactor_event_loop_impl.hpp    |  54 +++
 .../bindings/cpp/src/include/proton_bits.hpp    |  18 +-
 .../bindings/cpp/src/include/proton_event.hpp   |  16 +-
 .../cpp/src/include/test_dummy_container.hpp    |  82 ----
 .../bindings/cpp/src/io/connection_driver.cpp   |  31 +-
 proton-c/bindings/cpp/src/listener.cpp          |  11 +-
 proton-c/bindings/cpp/src/messaging_adapter.cpp |  21 +-
 .../cpp/src/proactor_container_impl.cpp         | 419 +++++++++++++++++++
 proton-c/bindings/cpp/src/receiver.cpp          |   1 -
 proton-c/bindings/cpp/src/receiver_options.cpp  |   2 +-
 proton-c/bindings/cpp/src/reconnect_timer.cpp   |   1 -
 proton-c/bindings/cpp/src/sender_options.cpp    |   2 +-
 proton-c/bindings/cpp/src/session_options.cpp   |   2 +-
 32 files changed, 765 insertions(+), 470 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/examples/cpp/ssl.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl.cpp b/examples/cpp/ssl.cpp
index 2e901c2..00bbccd 100644
--- a/examples/cpp/ssl.cpp
+++ b/examples/cpp/ssl.cpp
@@ -66,16 +66,16 @@ namespace {
 
 
 struct server_handler : public proton::messaging_handler {
-    std::string url;
+    proton::listener listener;
 
     void on_connection_open(proton::connection &c) OVERRIDE {
         std::cout << "Inbound server connection connected via SSL.  Protocol: " <<
             c.transport().ssl().protocol() << std::endl;
-        c.container().stop_listening(url);  // Just expecting the one connection.
+        listener.stop();  // Just expecting the one connection.
     }
 
     void on_transport_error(proton::transport &t) OVERRIDE {
-        t.connection().container().stop_listening(url);
+        listener.stop();
     }
 
     void on_message(proton::delivery &, proton::message &m) OVERRIDE {
@@ -122,8 +122,7 @@ class hello_world_direct : public proton::messaging_handler {
         } else throw std::logic_error("bad verify mode: " + verify);
 
         c.client_connection_options(client_opts);
-        s_handler.url = url;
-        c.listen(url);
+        s_handler.listener = c.listen(url);
         c.open_sender(url);
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index d1c6fd1..295a99e 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -32,9 +32,8 @@ set(qpid-proton-cpp-source
   src/map.cpp
   src/connection.cpp
   src/connection_options.cpp
-  src/connector.cpp
   src/container.cpp
-  src/container_impl.cpp
+  src/proactor_container_impl.cpp
   src/contexts.cpp
   src/data.cpp
   src/decimal.cpp
@@ -58,7 +57,6 @@ set(qpid-proton-cpp-source
   src/proton_bits.cpp
   src/proton_event.cpp
   src/proton_handler.cpp
-  src/reactor.cpp
   src/receiver.cpp
   src/receiver_options.cpp
   src/reconnect_timer.cpp
@@ -91,7 +89,7 @@ set_source_files_properties (
 
 add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source})
 
-target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton)
+target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton-core qpid-proton-proactor)
 
 set_target_properties (
   qpid-proton-cpp

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/connection.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/connection.hpp b/proton-c/bindings/cpp/include/proton/connection.hpp
index a4046be..331ba82 100644
--- a/proton-c/bindings/cpp/include/proton/connection.hpp
+++ b/proton-c/bindings/cpp/include/proton/connection.hpp
@@ -106,6 +106,12 @@ PN_CPP_CLASS_EXTERN connection : public internal::object<pn_connection_t>, publi
     PN_CPP_EXTERN receiver open_receiver(const std::string &addr,
                                          const receiver_options &);
 
+    /// @copydoc container::sender_options
+    PN_CPP_EXTERN class sender_options sender_options() const;
+
+    /// @copydoc container::receiver_options
+    PN_CPP_EXTERN class receiver_options receiver_options() const;
+
     /// Return all sessions on this connection.
     PN_CPP_EXTERN session_range sessions() const;
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index 6f10c3c..be83e5e 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -73,12 +73,6 @@ class PN_CPP_CLASS_EXTERN container {
     /// Connect to `url` and send an open request to the remote peer.
     PN_CPP_EXTERN returned<connection> connect(const std::string& url);
 
-    /// @cond INTERNAL
-    /// Stop listening on url, must match the url string given to listen().
-    /// You can also use the proton::listener object returned by listen()
-    PN_CPP_EXTERN void stop_listening(const std::string& url);
-    /// @endcond
-
     /// Start listening on url.
     ///
     /// Calls to the @ref listen_handler are serialized for this listener,

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/internal/config.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/internal/config.hpp b/proton-c/bindings/cpp/include/proton/internal/config.hpp
index da7f480..79d201c 100644
--- a/proton-c/bindings/cpp/include/proton/internal/config.hpp
+++ b/proton-c/bindings/cpp/include/proton/internal/config.hpp
@@ -95,6 +95,14 @@
 #define PN_CPP_HAS_CHRONO PN_CPP_HAS_CPP11
 #endif
 
+#ifndef PN_CPP_HAS_STD_MUTEX
+#define PN_CPP_HAS_STD_MUTEX PN_CPP_HAS_CPP11
+#endif
+
+#ifndef PN_CPP_HAS_STD_ATOMIC
+#define PN_CPP_HAS_STD_ATOMIC PN_CPP_HAS_CPP11
+#endif
+
 #endif // PROTON_INTERNAL_CONFIG_HPP
 
 /// @endcond

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
index 56deb00..8d0be85 100644
--- a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
+++ b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
@@ -94,28 +94,11 @@ struct const_buffer {
 class
 PN_CPP_CLASS_EXTERN connection_driver {
   public:
-    /// An engine that is not associated with a proton::container or
-    /// proton::event_loop.
-    ///
-    /// Accessing the container or event_loop for this connection in
-    /// a proton::messaging_handler will throw a proton::error exception.
-    ///
+    /// An engine without a container id.
     PN_CPP_EXTERN connection_driver();
 
-    /// Create a connection driver associated with a proton::container and
-    /// optional event_loop. If the event_loop is not provided attempts to use
-    /// it will throw proton::error.
-    ///
-    /// Takes ownership of the event_loop. Note the proton::connection created
-    /// by this connection_driver can outlive the connection_driver itself if
-    /// the user pins it in memory using the proton::thread_safe<> template.
-    /// The event_loop is deleted when, and only when, the proton::connection is.
-    ///
-    PN_CPP_EXTERN connection_driver(proton::container&);
-#if PN_CPP_HAS_RVALUE_REFERENCES
-    /// @copydoc connection_driver()
-    PN_CPP_EXTERN connection_driver(proton::container&, event_loop&& loop);
-#endif
+    /// Create a connection driver associated with a container id.
+    PN_CPP_EXTERN connection_driver(const std::string&);
 
     PN_CPP_EXTERN ~connection_driver();
 
@@ -207,8 +190,8 @@ PN_CPP_CLASS_EXTERN connection_driver {
     connection_driver(const connection_driver&);
     connection_driver& operator=(const connection_driver&);
 
+    std::string container_id_;
     messaging_handler* handler_;
-    proton::container* container_;
     pn_connection_driver_t driver_;
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/io/container_impl_base.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/container_impl_base.hpp b/proton-c/bindings/cpp/include/proton/io/container_impl_base.hpp
deleted file mode 100644
index a04b4ff..0000000
--- a/proton-c/bindings/cpp/include/proton/io/container_impl_base.hpp
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef PROTON_IO_CONTAINER_IMPL_BASE_HPP
-#define PROTON_IO_CONTAINER_IMPL_BASE_HPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "../container.hpp"
-
-#include <future>
-#include <mutex>
-#include <sstream>
-
-namespace proton {
-namespace io {
-
-/// **Experimental** - A base container implementation.
-///
-/// This is a thread-safe partial implementation of the
-/// proton::container interface to reduce boilerplate code in
-/// container implementations. Requires C++11.
-///
-/// You can ignore this class if you want to implement the functions
-/// in a different way.
-class container_impl_base : public standard_container {
-  public:
-    // Pull in base class functions here so that name search finds all the overloads
-    using standard_container::open_receiver;
-    using standard_container::open_sender;
-
-    /// @see proton::container::client_connection_options
-    void client_connection_options(const connection_options & opts) {
-        store(client_copts_, opts);
-    }
-    
-    /// @see proton::container::client_connection_options
-    connection_options client_connection_options() const {
-        return load(client_copts_);
-    }
-    
-    /// @see proton::container::server_connection_options
-    void server_connection_options(const connection_options & opts) {
-        store(server_copts_, opts);
-    }
-    
-    /// @see proton::container::server_connection_options
-    connection_options server_connection_options() const {
-        return load(server_copts_);
-    }
-    
-    /// @see proton::container::sender_options
-    void sender_options(const class sender_options & opts) {
-        store(sender_opts_, opts);
-    }
-    
-    /// @see proton::container::sender_options
-    class sender_options sender_options() const {
-        return load(sender_opts_);
-    }
-    
-    /// @see proton::container::receiver_options
-    void receiver_options(const class receiver_options & opts) {
-        store(receiver_opts_, opts);
-    }
-    
-    /// @see proton::container::receiver_options
-    class receiver_options receiver_options() const {
-        return load(receiver_opts_);
-    }
-
-    /// @see proton::container::open_sender
-    returned<sender> open_sender(
-        const std::string &url, const class sender_options &opts, const connection_options &copts)
-    {
-        return open_link<sender, class sender_options>(url, opts, copts, &connection::open_sender);
-    }
-
-    /// @see proton::container::open_receiver
-    returned<receiver> open_receiver(
-        const std::string &url, const class receiver_options &opts, const connection_options &copts)
-    {
-        return open_link<receiver>(url, opts, copts, &connection::open_receiver);
-    }
-
-  private:
-    template<class T, class Opts>
-    returned<T> open_link(
-        const std::string &url_str, const Opts& opts, const connection_options& copts,
-        T (connection::*open_fn)(const std::string&, const Opts&))
-    {
-        std::string addr = url(url_str).path();
-        std::shared_ptr<thread_safe<connection> > ts_connection = connect(url_str, copts);
-        std::promise<returned<T> > result_promise;
-        auto do_open = [ts_connection, addr, opts, open_fn, &result_promise]() {
-            try {
-                connection c = ts_connection->unsafe();
-                returned<T> s = make_thread_safe((c.*open_fn)(addr, opts));
-                result_promise.set_value(s);
-            } catch (...) {
-                result_promise.set_exception(std::current_exception());
-            }
-        };
-        ts_connection->event_loop()->inject(do_open);
-        std::future<returned<T> > result_future = result_promise.get_future();
-        if (!result_future.valid())
-            throw error(url_str+": connection closed");
-        return result_future.get();
-    }
-
-    mutable std::mutex lock_;
-    template <class T> T load(const T& v) const {
-        std::lock_guard<std::mutex> g(lock_);
-        return v;
-    }
-    template <class T> void store(T& v, const T& x) const {
-        std::lock_guard<std::mutex> g(lock_);
-        v = x;
-    }
-    connection_options client_copts_, server_copts_;
-    class receiver_options receiver_opts_;
-    class sender_options sender_opts_;
-};
-
-} // io
-} // proton
-
-#endif // PROTON_IO_CONTAINER_IMPL_BASE_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/listen_handler.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/listen_handler.hpp b/proton-c/bindings/cpp/include/proton/listen_handler.hpp
index 99f7558..08d5e76 100644
--- a/proton-c/bindings/cpp/include/proton/listen_handler.hpp
+++ b/proton-c/bindings/cpp/include/proton/listen_handler.hpp
@@ -41,14 +41,14 @@ class listen_handler {
     /// the connection.  messaging_handler::on_connection_open() will be called with
     /// the proton::connection, it can call connection::open() to accept or
     /// connection::close() to reject the connection.
-    virtual connection_options on_accept()= 0;
+    virtual connection_options on_accept(listener&)= 0;
 
     /// Called if there is a listening error, with an error message.
     /// close() will also be called.
-    virtual void on_error(const std::string&) {}
+    virtual void on_error(listener&, const std::string&) {}
 
     /// Called when this listen_handler is no longer needed, and can be deleted.
-    virtual void on_close() {}
+    virtual void on_close(listener&) {}
 };
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/include/proton/listener.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/listener.hpp b/proton-c/bindings/cpp/include/proton/listener.hpp
index 4b4ca24..c7f95a7 100644
--- a/proton-c/bindings/cpp/include/proton/listener.hpp
+++ b/proton-c/bindings/cpp/include/proton/listener.hpp
@@ -20,30 +20,30 @@
  * under the License.
  */
 
-#include "./fwd.hpp"
 #include "./internal/export.hpp"
 
-#include <string>
+struct pn_listener_t;
 
 namespace proton {
 
 /// A listener for incoming connections.
 class PN_CPP_CLASS_EXTERN listener {
+    /// @cond INTERNAL
+    listener(pn_listener_t*);
+    /// @endcond
+
   public:
     /// Create an empty listener.
     PN_CPP_EXTERN listener();
 
-    /// @cond INTERNAL
-    PN_CPP_EXTERN listener(container&, const std::string&);
-    /// @endcond
-
     /// Stop listening on the address provided to the call to
     /// container::listen that returned this listener.
     PN_CPP_EXTERN void stop();
 
- private:
-    std::string url_;
-    container* container_;
+  private:
+    pn_listener_t* listener_;
+
+  friend class container;
 };
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/connection.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection.cpp b/proton-c/bindings/cpp/src/connection.cpp
index f706df4..113a06f 100644
--- a/proton-c/bindings/cpp/src/connection.cpp
+++ b/proton-c/bindings/cpp/src/connection.cpp
@@ -38,7 +38,6 @@
 #include <proton/connection.h>
 #include <proton/session.h>
 #include <proton/transport.h>
-#include <proton/reactor.h>
 #include <proton/object.h>
 
 namespace proton {
@@ -72,13 +71,7 @@ std::string connection::user() const {
 
 container& connection::container() const {
     class container* c = connection_context::get(pn_object()).container;
-    if (!c) {
-        pn_reactor_t *r = pn_object_reactor(pn_object());
-        if (r)
-            c = &container_context::get(r);
-    }
-    if (!c)
-        throw proton::error("connection does not have a container");
+    if (!c) throw proton::error("No container");
     return *c;
 }
 
@@ -133,7 +126,7 @@ sender connection::open_sender(const std::string &addr) {
     return open_sender(addr, sender_options());
 }
 
-sender connection::open_sender(const std::string &addr, const sender_options &opts) {
+sender connection::open_sender(const std::string &addr, const class sender_options &opts) {
     return default_session().open_sender(addr, opts);
 }
 
@@ -141,11 +134,25 @@ receiver connection::open_receiver(const std::string &addr) {
     return open_receiver(addr, receiver_options());
 }
 
-receiver connection::open_receiver(const std::string &addr, const receiver_options &opts)
+receiver connection::open_receiver(const std::string &addr, const class receiver_options &opts)
 {
     return default_session().open_receiver(addr, opts);
 }
 
+class sender_options connection::sender_options() const {
+    connection_context& ctx = connection_context::get(pn_object());
+    return ctx.container ?
+        ctx.container->sender_options() :
+        proton::sender_options();
+}
+
+class receiver_options connection::receiver_options() const {
+    connection_context& ctx = connection_context::get(pn_object());
+    return ctx.container ?
+        ctx.container->receiver_options() :
+        proton::receiver_options();
+}
+
 error_condition connection::error() const {
     return make_wrapper(pn_connection_remote_condition(pn_object()));
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
index a5771f9..ae18ebe 100644
--- a/proton-c/bindings/cpp/src/connection_driver_test.cpp
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -31,6 +31,7 @@
 #include "proton/sender.hpp"
 #include "proton/sender_options.hpp"
 #include "proton/source_options.hpp"
+#include "proton/thread_safe.hpp"
 #include "proton/types_fwd.hpp"
 #include "proton/uuid.hpp"
 
@@ -57,8 +58,8 @@ struct in_memory_driver : public connection_driver {
     byte_stream& writes;
     int spinning;
 
-    in_memory_driver(byte_stream& rd, byte_stream& wr) :
-        reads(rd), writes(wr), spinning(0) {}
+    in_memory_driver(byte_stream& rd, byte_stream& wr, const std::string& name) :
+        connection_driver(name), reads(rd), writes(wr), spinning(0)  {}
 
     void do_read() {
         mutable_buffer rbuf = read_buffer();
@@ -102,8 +103,10 @@ struct driver_pair {
     byte_stream ab, ba;
     in_memory_driver a, b;
 
-    driver_pair(const connection_options& oa, const connection_options& ob)
-        : a(ba, ab), b(ab, ba)
+    driver_pair(const connection_options& oa, const connection_options& ob,
+                const std::string& name=""
+    ) :
+        a(ba, ab, name+"a"), b(ab, ba, name+"b")
     {
         a.connect(oa);
         b.accept(ob);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/connection_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_options.cpp b/proton-c/bindings/cpp/src/connection_options.cpp
index 506e84e..4644094 100644
--- a/proton-c/bindings/cpp/src/connection_options.cpp
+++ b/proton-c/bindings/cpp/src/connection_options.cpp
@@ -18,6 +18,7 @@
  * under the License.
  *
  */
+#include "proton/fwd.hpp"
 #include "proton/connection_options.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/reconnect_timer.hpp"
@@ -27,12 +28,12 @@
 
 #include "acceptor.hpp"
 #include "contexts.hpp"
-#include "connector.hpp"
 #include "messaging_adapter.hpp"
 #include "msg.hpp"
 #include "proton_bits.hpp"
 
 #include <proton/connection.h>
+#include <proton/proactor.h>
 #include <proton/transport.h>
 
 namespace proton {
@@ -74,15 +75,14 @@ class connection_options::impl {
      */
     void apply_unbound(connection& c) {
         pn_connection_t *pnc = unwrap(c);
-        container::impl::connector *outbound = dynamic_cast<container::impl::connector*>(
-            connection_context::get(unwrap(c)).handler.get());
 
         // Only apply connection options if uninit.
         bool uninit = c.uninitialized();
         if (!uninit) return;
 
+        bool outbound = !connection_context::get(pnc).listener_context_;
         if (reconnect.set && outbound)
-            outbound->reconnect_timer(reconnect.value);
+            connection_context::get(pnc).reconnect.reset(new reconnect_timer(reconnect.value));
         if (container_id.set)
             pn_connection_set_container(pnc, container_id.value.c_str());
         if (virtual_host.set)
@@ -97,31 +97,23 @@ class connection_options::impl {
         // Transport options.  pnt is NULL between reconnect attempts
         // and if there is a pipelined open frame.
         pn_connection_t *pnc = unwrap(c);
-        container::impl::connector *outbound = dynamic_cast<container::impl::connector*>(
-            connection_context::get(unwrap(c)).handler.get());
-
         pn_transport_t *pnt = pn_connection_transport(pnc);
         if (!pnt) return;
 
         // SSL
-        if (outbound && outbound->address().scheme() == url::AMQPS) {
+        connection_context& cc = connection_context::get(pnc);
+        bool outbound = !cc.listener_context_;
+        if (outbound && ssl_client_options.set) {
             // A side effect of pn_ssl() is to set the ssl peer
             // hostname to the connection hostname, which has
             // already been adjusted for the virtual_host option.
             pn_ssl_t *ssl = pn_ssl(pnt);
             if (pn_ssl_init(ssl, ssl_client_options.value.pn_domain(), NULL))
                 throw error(MSG("client SSL/TLS initialization error"));
-        } else if (!outbound) {
-            // TODO aconway 2016-05-13: reactor only
-            pn_acceptor_t *pnp = pn_connection_acceptor(pnc);
-            if (pnp) {
-                listener_context &lc(listener_context::get(pnp));
-                if (lc.ssl) {
-                    pn_ssl_t *ssl = pn_ssl(pnt);
-                    if (pn_ssl_init(ssl, ssl_server_options.value.pn_domain(), NULL))
-                        throw error(MSG("server SSL/TLS initialization error"));
-                }
-            }
+        } else if (!outbound && ssl_server_options.set) {
+                pn_ssl_t *ssl = pn_ssl(pnt);
+                if (pn_ssl_init(ssl, ssl_server_options.value.pn_domain(), NULL))
+                    throw error(MSG("server SSL/TLS initialization error"));
         }
 
         // SASL

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/container.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container.cpp b/proton-c/bindings/cpp/src/container.cpp
index 3daa925..b98da78 100644
--- a/proton-c/bindings/cpp/src/container.cpp
+++ b/proton-c/bindings/cpp/src/container.cpp
@@ -27,7 +27,7 @@
 #include "proton/listener.hpp"
 #include "proton/thread_safe.hpp"
 
-#include "container_impl.hpp"
+#include "proactor_container_impl.hpp"
 
 namespace proton {
 
@@ -65,24 +65,12 @@ returned<receiver> container::open_receiver(const std::string &url, const proton
     return open_receiver(url, receiver_options(), co);
 }
 
-namespace{
-    struct listen_opts : public listen_handler {
-        connection_options  opts;
-        listen_opts(const connection_options& o) : opts(o) {}
-        connection_options on_accept() { return opts; }
-        void on_close() { delete this; }
-    };
-}
-
 listener container::listen(const std::string& url, const connection_options& opts) {
-    // Note: listen_opts::on_close() calls delete(this) so this is not a leak.
-    // The container will always call on_closed() even if there are errors or exceptions.
-    listen_opts* lh = new listen_opts(opts);
-    return listen(url, *lh);
+    return impl_->listen(url, opts);
 }
 
 listener container::listen(const std::string &url) {
-    return listen(url, connection_options());
+    return impl_->listen(url);
 }
 
 void container::stop() { stop(error_condition()); }
@@ -93,8 +81,6 @@ returned<connection> container::connect(const std::string& url, const connection
 
 listener container::listen(const std::string& url, listen_handler& l) { return impl_->listen(url, l); }
 
-void container::stop_listening(const std::string& url) { impl_->stop_listening(url); }
-
 void container::run() { impl_->run(); }
 
 void container::auto_stop(bool set) { impl_->auto_stop(set); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/container_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container_test.cpp b/proton-c/bindings/cpp/src/container_test.cpp
index e02aff5..d210268 100644
--- a/proton-c/bindings/cpp/src/container_test.cpp
+++ b/proton-c/bindings/cpp/src/container_test.cpp
@@ -124,12 +124,12 @@ struct test_listener : public proton::listen_handler {
     bool on_accept_, on_close_;
     std::string on_error_;
     test_listener() : on_accept_(false), on_close_(false) {}
-    proton::connection_options on_accept() PN_CPP_OVERRIDE {
+    proton::connection_options on_accept(proton::listener&) PN_CPP_OVERRIDE {
         on_accept_ = true;
         return proton::connection_options();
     }
-    void on_close() PN_CPP_OVERRIDE { on_close_ = true; }
-    void on_error(const std::string& e) PN_CPP_OVERRIDE { on_error_ = e; }
+    void on_close(proton::listener&) PN_CPP_OVERRIDE { on_close_ = true; }
+    void on_error(proton::listener&, const std::string& e) PN_CPP_OVERRIDE { on_error_ = e; }
 };
 
 int test_container_bad_address() {
@@ -179,6 +179,11 @@ class stop_tester : public proton::messaging_handler {
         state = 5;
     }
 
+    void on_transport_error(proton::transport & t) PN_CPP_OVERRIDE {
+        // Do nothing - ignore transport errors - we're going to get one when
+        // the container stops.
+    }
+
 public:
     stop_tester(): state(0) {}
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/contexts.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/contexts.cpp b/proton-c/bindings/cpp/src/contexts.cpp
index b1a234f..81ef5eb 100644
--- a/proton-c/bindings/cpp/src/contexts.cpp
+++ b/proton-c/bindings/cpp/src/contexts.cpp
@@ -21,7 +21,6 @@
 
 #include "contexts.hpp"
 #include "msg.hpp"
-#include "reactor.hpp"
 #include "proton_bits.hpp"
 
 #include "proton/error.hpp"
@@ -29,8 +28,9 @@
 #include <proton/connection.h>
 #include <proton/object.h>
 #include <proton/link.h>
+#include <proton/listener.h>
 #include <proton/message.h>
-#include <proton/reactor.h>
+#include "proton/reconnect_timer.hpp"
 #include <proton/session.h>
 
 #include <typeinfo>
@@ -48,16 +48,10 @@ pn_class_t cpp_context_class = PN_CLASS(cpp_context);
 
 // Handles
 PN_HANDLE(CONNECTION_CONTEXT)
-PN_HANDLE(CONTAINER_CONTEXT)
 PN_HANDLE(LISTENER_CONTEXT)
+PN_HANDLE(SESSION_CONTEXT)
 PN_HANDLE(LINK_CONTEXT)
 
-void set_context(pn_record_t* record, pn_handle_t handle, const pn_class_t *clazz, void* value)
-{
-    pn_record_def(record, handle, clazz);
-    pn_record_set(record, handle, value);
-}
-
 template <class T>
 T* get_context(pn_record_t* record, pn_handle_t handle) {
     return reinterpret_cast<T*>(pn_record_get(record, handle));
@@ -71,45 +65,24 @@ void *context::alloc(size_t n) { return pn_object_new(&cpp_context_class, n); }
 
 pn_class_t* context::pn_class() { return &cpp_context_class; }
 
+connection_context::connection_context() :
+    container(0), default_session(0), link_gen(0), handler(0), listener_context_(0)
+{}
 
-context::id connection_context::id(pn_connection_t* c) {
-    return context::id(pn_connection_attachments(c), CONNECTION_CONTEXT);
-}
-
-void container_context::set(const reactor& r, container& c) {
-    set_context(pn_reactor_attachments(unwrap(r)), CONTAINER_CONTEXT, PN_VOID, &c);
+connection_context& connection_context::get(pn_connection_t *c) {
+    return ref<connection_context>(id(pn_connection_attachments(c), CONNECTION_CONTEXT));
 }
 
-container &container_context::get(pn_reactor_t *pn_reactor) {
-    container *ctx = get_context<container>(pn_reactor_attachments(pn_reactor), CONTAINER_CONTEXT);
-    if (!ctx) throw error(MSG("Reactor has no C++ container context"));
-    return *ctx;
+listener_context& listener_context::get(pn_listener_t* l) {
+    return ref<listener_context>(id(pn_listener_attachments(l), LISTENER_CONTEXT));
 }
 
-listener_context& listener_context::get(pn_acceptor_t* a) {
-    // TODO aconway 2016-05-13: reactor only
-    // A Proton C pn_acceptor_t is really just a selectable
-    pn_selectable_t *sel = reinterpret_cast<pn_selectable_t*>(a);
-
-    listener_context* ctx =
-        get_context<listener_context>(pn_selectable_attachments(sel), LISTENER_CONTEXT);
-    if (!ctx) {
-        ctx =  context::create<listener_context>();
-        set_context(pn_selectable_attachments(sel), LISTENER_CONTEXT, context::pn_class(), ctx);
-        pn_decref(ctx);
-    }
-    return *ctx;
+link_context& link_context::get(pn_link_t* l) {
+    return ref<link_context>(id(pn_link_attachments(l), LINK_CONTEXT));
 }
 
-link_context& link_context::get(pn_link_t* l) {
-    link_context* ctx =
-        get_context<link_context>(pn_link_attachments(l), LINK_CONTEXT);
-    if (!ctx) {
-        ctx =  context::create<link_context>();
-        set_context(pn_link_attachments(l), LINK_CONTEXT, context::pn_class(), ctx);
-        pn_decref(ctx);
-    }
-    return *ctx;
+session_context& session_context::get(pn_session_t* s) {
+    return ref<session_context>(id(pn_session_attachments(s), SESSION_CONTEXT));
 }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/event_loop.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/event_loop.cpp b/proton-c/bindings/cpp/src/event_loop.cpp
index ea4ee71..ab39aa7 100644
--- a/proton-c/bindings/cpp/src/event_loop.cpp
+++ b/proton-c/bindings/cpp/src/event_loop.cpp
@@ -20,7 +20,7 @@
 #include "proton/event_loop.hpp"
 
 #include "contexts.hpp"
-#include "event_loop_impl.hpp"
+#include "proactor_event_loop_impl.hpp"
 
 #include <proton/session.h>
 #include <proton/link.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp
index 742b346..c096a6e 100644
--- a/proton-c/bindings/cpp/src/include/contexts.hpp
+++ b/proton-c/bindings/cpp/src/include/contexts.hpp
@@ -34,16 +34,16 @@
 
 #include "proton_handler.hpp"
 
-struct pn_session_t;
-struct pn_event_t;
-struct pn_reactor_t;
 struct pn_record_t;
-struct pn_acceptor_t;
+struct pn_link_t;
+struct pn_session_t;
+struct pn_connection_t;
+struct pn_listener_t;
 
 namespace proton {
 
 class proton_handler;
-class reactor;
+class reconnect_timer;
 
 // Base class for C++ classes that are used as proton contexts.
 // Contexts are pn_objects managed by pn reference counts, the C++ value is allocated in-place.
@@ -82,51 +82,53 @@ class context {
     static void *alloc(size_t n);
 };
 
+class listener_context;
+
 // Connection context used by all connections.
 class connection_context : public context {
   public:
-    connection_context() : container(0), default_session(0), link_gen(0) {}
+    connection_context();
+    static connection_context& get(pn_connection_t *c);
 
     class container* container;
     pn_session_t *default_session; // Owned by connection.
     message event_message;      // re-used by messaging_adapter for performance.
     io::link_namer* link_gen;      // Link name generator.
 
-    internal::pn_unique_ptr<proton_handler> handler;
+    messaging_handler* handler;
+    internal::pn_unique_ptr<reconnect_timer> reconnect;
+    listener_context* listener_context_;
     event_loop event_loop_;
-
-    static connection_context& get(pn_connection_t *c) { return ref<connection_context>(id(c)); }
-
-  protected:
-    static context::id id(pn_connection_t*);
-};
-
-void container_context(const reactor&, container&);
-
-class container_context {
-  public:
-    static void set(const reactor& r, container& c);
-    static container& get(pn_reactor_t*);
 };
 
 class listener_context : public context {
   public:
-    static listener_context& get(pn_acceptor_t* c);
-    listener_context() : listen_handler_(0), ssl(false) {}
-    connection_options  get_options() { return listen_handler_->on_accept(); }
-    class listen_handler* listen_handler_;
-    bool ssl;
+    listener_context() : listen_handler_(0) {}
+    static listener_context& get(pn_listener_t* c);
+
+    listen_handler* listen_handler_;
+    internal::pn_unique_ptr<const connection_options> connection_options_;
 };
 
 class link_context : public context {
   public:
+    link_context() : handler(0), credit_window(10), pending_credit(0), auto_accept(true), auto_settle(true), draining(false) {}
     static link_context& get(pn_link_t* l);
-    link_context() : credit_window(10), auto_accept(true), auto_settle(true), draining(false), pending_credit(0) {}
+
+    messaging_handler* handler;
     int credit_window;
+    uint32_t pending_credit;
     bool auto_accept;
     bool auto_settle;
     bool draining;
-    uint32_t pending_credit;
+};
+
+class session_context : public context {
+  public:
+    session_context() : handler(0) {}
+    static session_context& get(pn_session_t* s);
+
+    messaging_handler* handler;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/messaging_adapter.hpp b/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
index 5371eec..d7eb6a0 100644
--- a/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
+++ b/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
@@ -39,8 +39,6 @@ class messaging_adapter : public proton_handler
   public:
     messaging_adapter(messaging_handler &delegate) : delegate_(delegate) {}
 
-    void on_reactor_init(proton_event &e);
-    void on_reactor_final(proton_event & e);
     void on_link_flow(proton_event &e);
     void on_delivery(proton_event &e);
     void on_connection_remote_open(proton_event &e);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
new file mode 100644
index 0000000..8c12c02
--- /dev/null
+++ b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
@@ -0,0 +1,133 @@
+#ifndef PROTON_CPP_PROACTOR_CONTAINERIMPL_H
+#define PROTON_CPP_PROACTOR_CONTAINERIMPL_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/fwd.hpp"
+#include "proton/container.hpp"
+#include "proton/connection.hpp"
+#include "proton/connection_options.hpp"
+#include "proton/duration.hpp"
+#include "proton/error_condition.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/receiver.hpp"
+#include "proton/receiver_options.hpp"
+#include "proton/sender.hpp"
+#include "proton/sender_options.hpp"
+
+#include "proton_bits.hpp"
+#include "proton_handler.hpp"
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+struct pn_proactor_t;
+struct pn_listener_t;
+struct pn_event_t;
+
+namespace proton {
+
+class container::impl {
+  public:
+    impl(container& c, const std::string& id, messaging_handler* = 0);
+    ~impl();
+    std::string id() const { return id_; }
+    returned<connection> connect(const std::string&, const connection_options&);
+    returned<sender> open_sender(
+        const std::string&, const proton::sender_options &, const connection_options &);
+    returned<receiver> open_receiver(
+        const std::string&, const proton::receiver_options &, const connection_options &);
+    listener listen(const std::string&);
+    listener listen(const std::string&, const connection_options& lh);
+    listener listen(const std::string&, listen_handler& lh);
+    void client_connection_options(const connection_options &);
+    connection_options client_connection_options() const { return client_connection_options_; }
+    void server_connection_options(const connection_options &);
+    connection_options server_connection_options() const { return server_connection_options_; }
+    void sender_options(const proton::sender_options&);
+    class sender_options sender_options() const { return sender_options_; }
+    void receiver_options(const proton::receiver_options&);
+    class receiver_options receiver_options() const { return receiver_options_; }
+    void run();
+    void stop(const error_condition& err);
+    void auto_stop(bool set);
+    void schedule(duration, void_function0&);
+#if PN_CPP_HAS_STD_FUNCTION
+    void schedule(duration, std::function<void()>);
+#endif
+    template <class T> static void set_handler(T s, messaging_handler* h);
+    template <class T> static messaging_handler* get_handler(T s);
+
+  private:
+    pn_listener_t* listen_common_lh(const std::string&);
+    connection connect_common(const std::string&, const connection_options&);
+
+    // Event loop to run in each container thread
+    static void thread(impl&);
+    bool handle(pn_event_t*);
+    void run_timer_jobs();
+
+    container& container_;
+
+    struct scheduled {
+        timestamp time; // duration from epoch for task
+#if PN_CPP_HAS_STD_FUNCTION
+        std::function<void()>  task;
+#else
+        void_function0* task_;
+        void task();
+#endif
+
+        // We want to get to get the *earliest* first so test is "reversed"
+        bool operator < (const scheduled& r) const { return  r.time < time; }
+    };
+    std::vector<scheduled> deferred_; // This vector is kept as a heap
+
+    pn_proactor_t* proactor_;
+    messaging_handler* handler_;
+    std::string id_;
+    connection_options client_connection_options_;
+    connection_options server_connection_options_;
+    proton::sender_options sender_options_;
+    proton::receiver_options receiver_options_;
+
+    proton::error_condition stop_err_;
+    bool auto_stop_;
+    bool stopping_;
+};
+
+template <class T>
+void container::impl::set_handler(T s, messaging_handler* mh) {
+    internal::set_messaging_handler(s, mh);
+}
+
+template <class T>
+messaging_handler* container::impl::get_handler(T s) {
+    return internal::get_messaging_handler(s);
+}
+
+
+}
+
+#endif  /*!PROTON_CPP_PROACTOR_CONTAINERIMPL_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
new file mode 100644
index 0000000..8fa7acf
--- /dev/null
+++ b/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
@@ -0,0 +1,54 @@
+#ifndef PROTON_CPP_EVENT_LOOP_IMPL_HPP
+#define PROTON_CPP_EVENT_LOOP_IMPL_HPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/fwd.hpp"
+
+struct pn_connection_t;
+
+namespace proton {
+
+class event_loop::impl {
+  public:
+    impl(pn_connection_t*);
+
+    bool inject(void_function0& f);
+#if PN_CPP_HAS_STD_FUNCTION
+    bool inject(std::function<void()> f);
+    typedef std::vector<std::function<void()> > jobs;
+#else
+    typedef std::vector<void_function0*> jobs;
+#endif
+
+
+    void run_all_jobs();
+    void finished();
+
+    jobs jobs_;
+    pn_connection_t* connection_;
+    bool finished_;
+};
+
+}
+
+#endif // PROTON_CPP_EVENT_LOOP_IMPL_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/proton_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_bits.hpp b/proton-c/bindings/cpp/src/include/proton_bits.hpp
index 53f2230..e72f343 100644
--- a/proton-c/bindings/cpp/src/include/proton_bits.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_bits.hpp
@@ -24,6 +24,8 @@
 #include <string>
 #include <iosfwd>
 
+#include "contexts.hpp"
+
 /**@file
  *
  * Assorted internal proton utilities.
@@ -65,6 +67,7 @@ class terminus;
 class source;
 class target;
 class reactor;
+class messaging_handler;
 
 std::string error_str(long code);
 
@@ -127,12 +130,19 @@ public:
     static typename wrapped<T>::type* unwrap(const T& t) { return t.pn_object(); }
 };
 
-// Get attachments for various proton-c types
+template <class T> struct context {};
+template <> struct context<link> {typedef link_context type; };
+template <> struct context<receiver> {typedef link_context type; };
+template <> struct context<sender> {typedef link_context type; };
+template <> struct context<session> {typedef session_context type; };
+template <> struct context<connection> {typedef connection_context type; };
+
+template <class T>
+inline void set_messaging_handler(T t, messaging_handler* mh) { context<T>::type::get(factory<T>::unwrap(t)).handler = mh; }
+
 template <class T>
-inline pn_record_t* get_attachments(T*);
+inline messaging_handler* get_messaging_handler(T* t) { return context<typename internal::wrapper<T>::type>::type::get(t).handler; }
 
-template <> inline pn_record_t* get_attachments(pn_session_t* s) { return pn_session_attachments(s); }
-template <> inline pn_record_t* get_attachments(pn_link_t* l) { return pn_link_attachments(l); }
 }
 
 template <class T>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/proton_event.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_event.hpp b/proton-c/bindings/cpp/src/include/proton_event.hpp
index 374da85..be324e7 100644
--- a/proton-c/bindings/cpp/src/include/proton_event.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_event.hpp
@@ -266,23 +266,12 @@ class proton_event
     };
     ///@}
 
-    proton_event(pn_event_t *ce, class container* cont) :
-      pn_event_(ce),
-      container_(cont)
+    proton_event(pn_event_t *ce) :
+      pn_event_(ce)
     {}
 
     pn_event_t* pn_event() const { return pn_event_; }
 
-    /** Return a reference to the container, throws proton::error if there is none. */
-    class container& container() const {
-        if (!container_)
-            throw proton::error("event does not have a container");
-        return *container_;
-    }
-
-    /** Return a pointer to the container if there is one, NULL otherwise. */
-    class container* container_ptr() const { return container_; }
-
     /// Get type of event
     event_type type() const { return event_type(pn_event_type(pn_event_)); }
 
@@ -290,7 +279,6 @@ class proton_event
 
   private:
     pn_event_t *pn_event_;
-    class container* container_;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/test_dummy_container.hpp b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
deleted file mode 100644
index daed435..0000000
--- a/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef TEST_DUMMY_CONTAINER_HPP
-#define TEST_DUMMY_CONTAINER_HPP
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "proton/container.hpp"
-#include "proton/event_loop.hpp"
-#include "proton/thread_safe.hpp"
-
-namespace test {
-
-using namespace proton;
-
-class dummy_container : public standard_container {
-  public:
-    dummy_container(const std::string cid="") :
-        id_(cid), fail("not implemented for dummy_container") {}
-
-    // Pull in base class functions here so that name search finds all the overloads
-    using standard_container::stop;
-    using standard_container::connect;
-    using standard_container::listen;
-    using standard_container::open_receiver;
-    using standard_container::open_sender;
-
-    returned<connection> connect(const std::string&, const connection_options&) { throw fail; }
-    listener listen(const std::string& , listen_handler& ) { throw fail; }
-    void stop_listening(const std::string&) { throw fail; }
-    void run() { throw fail; }
-    void auto_stop(bool) { throw fail; }
-    void stop(const proton::error_condition& ) { throw fail; }
-    returned<sender> open_sender(const std::string &, const proton::sender_options &, const connection_options&) { throw fail; }
-    returned<receiver> open_receiver( const std::string &, const proton::receiver_options &, const connection_options &) { throw fail; }
-    std::string id() const { return id_; }
-    void client_connection_options(const connection_options &o) { ccopts_ = o; }
-    connection_options client_connection_options() const { return ccopts_; }
-    void server_connection_options(const connection_options &o) { scopts_ = o; }
-    connection_options server_connection_options() const { return scopts_; }
-    void sender_options(const class sender_options &o) { sopts_ = o; }
-    class sender_options sender_options() const { return sopts_; }
-    void receiver_options(const class receiver_options &o) { ropts_ = o; }
-    class receiver_options receiver_options() const { return ropts_; }
-#if PN_CPP_HAS_STD_FUNCTION
-    void schedule(duration, std::function<void()>) { throw fail; }
-#endif
-    void schedule(duration, void_function0&) { throw fail; }
-
-  private:
-    std::string id_;
-    connection_options ccopts_, scopts_;
-    class sender_options sopts_;
-    class receiver_options ropts_;
-    std::runtime_error fail;
-};
-
-class dummy_event_loop : public event_loop {
-#if PN_CPP_HAS_CPP11
-    bool inject(std::function<void()> f) PN_CPP_OVERRIDE { f(); return true; }
-#endif
-    bool inject(proton::void_function0& h) PN_CPP_OVERRIDE { h(); return true; }
-};
-
-}
-
-#endif // TEST_DUMMY_CONTAINER_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/io/connection_driver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp
index da8c2a4..d7c5e5c 100644
--- a/proton-c/bindings/cpp/src/io/connection_driver.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -47,23 +47,12 @@ void connection_driver::init() {
     }
 }
 
-connection_driver::connection_driver() : handler_(0), container_(0) { init(); }
+connection_driver::connection_driver() : handler_(0) { init(); }
 
-connection_driver::connection_driver(class container& cont) : handler_(0), container_(&cont) {
+connection_driver::connection_driver(const std::string& id) : container_id_(id), handler_(0) {
     init();
-    connection_context& ctx = connection_context::get(unwrap(connection()));
-    ctx.container = container_;
 }
 
-#if PN_CPP_HAS_RVALUE_REFERENCES
-connection_driver::connection_driver(class container& cont, event_loop&& loop) : handler_(0), container_(&cont) {
-    init();
-    connection_context& ctx = connection_context::get(unwrap(connection()));
-    ctx.container = container_;
-    ctx.event_loop_ = loop.impl_.get();
-}
-#endif
-
 connection_driver::~connection_driver() {
     pn_connection_driver_destroy(&driver_);
 }
@@ -79,10 +68,7 @@ void connection_driver::configure(const connection_options& opts, bool server) {
 
 void connection_driver::connect(const connection_options& opts) {
     connection_options all;
-    if (container_) {
-        all.container_id(container_->id());
-        all.update(container_->client_connection_options());
-    }
+    all.container_id(container_id_);
     all.update(opts);
     configure(all, false);
     connection().open();
@@ -90,10 +76,7 @@ void connection_driver::connect(const connection_options& opts) {
 
 void connection_driver::accept(const connection_options& opts) {
     connection_options all;
-    if (container_) {
-        all.container_id(container_->id());
-        all.update(container_->server_connection_options());
-    }
+    all.container_id(container_id_);
     all.update(opts);
     configure(all, true);
 }
@@ -105,7 +88,7 @@ bool connection_driver::has_events() const {
 bool connection_driver::dispatch() {
     pn_event_t* c_event;
     while ((c_event = pn_connection_driver_next_event(&driver_)) != NULL) {
-        proton_event cpp_event(c_event, container_);
+        proton_event cpp_event(c_event);
         try {
             if (handler_ != 0) {
                 messaging_adapter adapter(*handler_);
@@ -163,8 +146,4 @@ proton::transport connection_driver::transport() const {
     return make_wrapper(driver_.transport);
 }
 
-proton::container* connection_driver::container() const {
-    return container_;
-}
-
 }}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/listener.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/listener.cpp b/proton-c/bindings/cpp/src/listener.cpp
index 2639f5e..a9ca53d 100644
--- a/proton-c/bindings/cpp/src/listener.cpp
+++ b/proton-c/bindings/cpp/src/listener.cpp
@@ -18,12 +18,15 @@
  */
 
 #include "proton/listener.hpp"
-#include "proton/container.hpp"
+
+#include <proton/listener.h>
+
+#include "contexts.hpp"
 
 namespace proton {
 
-listener::listener() : container_(0) {}
-listener::listener(container& c, const std::string& u) : url_(u), container_(&c) {}
-void listener::stop() { if (container_) container_->stop_listening(url_); }
+listener::listener(): listener_(0) {}
+listener::listener(pn_listener_t* l) : listener_(l) {}
+void listener::stop() { if (listener_) pn_listener_close(listener_); }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/messaging_adapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/messaging_adapter.cpp b/proton-c/bindings/cpp/src/messaging_adapter.cpp
index a70703e..613808b 100644
--- a/proton-c/bindings/cpp/src/messaging_adapter.cpp
+++ b/proton-c/bindings/cpp/src/messaging_adapter.cpp
@@ -58,16 +58,6 @@ void credit_topup(pn_link_t *link) {
 }
 }
 
-void messaging_adapter::on_reactor_init(proton_event &pe) {
-    container* c = pe.container_ptr();
-    if (c) delegate_.on_container_start(*c);
-}
-
-void messaging_adapter::on_reactor_final(proton_event &pe) {
-    container* c = pe.container_ptr();
-    if (c) delegate_.on_container_stop(*c);
-}
-
 void messaging_adapter::on_link_flow(proton_event &pe) {
     pn_event_t *pne = pe.pn_event();
     pn_link_t *lnk = pn_event_link(pne);
@@ -281,24 +271,17 @@ void messaging_adapter::on_link_local_open(proton_event &pe) {
 
 void messaging_adapter::on_link_remote_open(proton_event &pe) {
     pn_link_t *lnk = pn_event_link(pe.pn_event());
-    container* c = pe.container_ptr();
     if (pn_link_is_receiver(lnk)) {
       receiver r(make_wrapper<receiver>(lnk));
       delegate_.on_receiver_open(r);
       if (is_local_unititialised(pn_link_state(lnk))) {
-          if (c)
-              r.open(c->receiver_options());
-          else
-              r.open();
+          r.open(r.connection().receiver_options());
       }
     } else {
       sender s(make_wrapper<sender>(lnk));
       delegate_.on_sender_open(s);
       if (is_local_unititialised(pn_link_state(lnk))) {
-          if (c)
-              s.open(c->sender_options());
-          else
-              s.open();
+          s.open(s.connection().sender_options());
       }
     }
     credit_topup(lnk);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
new file mode 100644
index 0000000..2b6b1de
--- /dev/null
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -0,0 +1,419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proactor_container_impl.hpp"
+#include "proactor_event_loop_impl.hpp"
+
+#include "proton/error_condition.hpp"
+#include "proton/function.hpp"
+#include "proton/listener.hpp"
+#include "proton/listen_handler.hpp"
+#include "proton/thread_safe.hpp"
+#include "proton/url.hpp"
+
+#include "proton/connection.h"
+#include "proton/listener.h"
+#include "proton/proactor.h"
+#include "proton/transport.h"
+
+#include "contexts.hpp"
+#include "messaging_adapter.hpp"
+#include "proton_bits.hpp"
+#include "proton_event.hpp"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <vector>
+
+namespace proton {
+
+event_loop::impl::impl(pn_connection_t* c)
+    : connection_(c), finished_(false)
+{}
+
+void event_loop::impl::finished() {
+    finished_ = true;
+}
+
+#if PN_CPP_HAS_STD_FUNCTION
+bool event_loop::impl::inject(std::function<void()> f) {
+    // Note this is an unbounded work queue.
+    // A resource-safe implementation should be bounded.
+    if (finished_)
+         return false;
+    jobs_.push_back(f);
+    pn_connection_wake(connection_);
+    return true;
+}
+
+bool event_loop::impl::inject(proton::void_function0& f) {
+    return inject([&f]() { f(); });
+}
+
+void event_loop::impl::run_all_jobs() {
+    decltype(jobs_) j;
+    {
+        std::swap(j, jobs_);
+    }
+    // Run queued work, but ignore any exceptions
+    for (auto& f : j) try {
+        f();
+    } catch (...) {};
+}
+#else
+bool event_loop::impl::inject(proton::void_function0& f) {
+    // Note this is an unbounded work queue.
+    // A resource-safe implementation should be bounded.
+    if (finished_)
+         return false;
+    jobs_.push_back(&f);
+    pn_connection_wake(connection_);
+    return true;
+}
+
+void event_loop::impl::run_all_jobs() {
+    // Run queued work, but ignore any exceptions
+    for (event_loop::impl::jobs::iterator f = jobs_.begin(); f != jobs_.end(); ++f) try {
+        (**f)();
+    } catch (...) {};
+    jobs_.clear();
+    return;
+}
+#endif
+container::impl::impl(container& c, const std::string& id, messaging_handler* mh)
+    : container_(c), proactor_(pn_proactor()), handler_(mh), id_(id),
+      auto_stop_(true), stopping_(false)
+{}
+
+container::impl::~impl() {
+    try {
+        stop(error_condition("exception", "container shut-down"));
+        //wait();
+    } catch (...) {}
+    pn_proactor_free(proactor_);
+}
+
+proton::connection container::impl::connect_common(
+    const std::string& addr,
+    const proton::connection_options& user_opts)
+{
+    if (stopping_)
+        throw proton::error("container is stopping");
+
+    connection_options opts = client_connection_options_; // Defaults
+    opts.update(user_opts);
+    messaging_handler* mh = opts.handler();
+
+    proton::url url(addr);
+    pn_connection_t *pnc = pn_connection();
+    connection_context& cc(connection_context::get(pnc));
+    cc.container = &container_;
+    cc.handler = mh;
+    cc.event_loop_ = new event_loop::impl(pnc);
+
+    pn_connection_set_container(pnc, id_.c_str());
+    pn_connection_set_hostname(pnc, url.host().c_str());
+    if (!url.user().empty())
+        pn_connection_set_user(pnc, url.user().c_str());
+    if (!url.password().empty())
+        pn_connection_set_password(pnc, url.password().c_str());
+
+    connection conn = make_wrapper(pnc);
+    conn.open(opts);
+    // Figure out correct string len then create connection address
+    int len = pn_proactor_addr(0, 0, url.host().c_str(), url.port().c_str());
+    std::vector<char> caddr(len+1);
+    pn_proactor_addr(&caddr[0], len+1, url.host().c_str(), url.port().c_str());
+    pn_proactor_connect(proactor_, pnc, &caddr[0]);
+    return conn;
+}
+
+proton::returned<proton::connection> container::impl::connect(
+    const std::string& addr,
+    const proton::connection_options& user_opts)
+{
+    connection conn = connect_common(addr, user_opts);
+    return make_thread_safe(conn);
+}
+
+returned<sender> container::impl::open_sender(const std::string &url, const proton::sender_options &o1, const connection_options &o2) {
+    proton::sender_options lopts(sender_options_);
+    lopts.update(o1);
+    connection conn = connect_common(url, o2);
+
+    return make_thread_safe(conn.default_session().open_sender(proton::url(url).path(), lopts));
+}
+
+returned<receiver> container::impl::open_receiver(const std::string &url, const proton::receiver_options &o1, const connection_options &o2) {
+    proton::receiver_options lopts(receiver_options_);
+    lopts.update(o1);
+    connection conn = connect_common(url, o2);
+
+    return make_thread_safe(
+        conn.default_session().open_receiver(proton::url(url).path(), lopts));
+}
+
+pn_listener_t* container::impl::listen_common_lh(const std::string& addr) {
+    if (stopping_)
+        throw proton::error("container is stopping");
+
+    proton::url url(addr);
+
+    // Figure out correct string len then create connection address
+    int len = pn_proactor_addr(0, 0, url.host().c_str(), url.port().c_str());
+    std::vector<char> caddr(len+1);
+    pn_proactor_addr(&caddr[0], len+1, url.host().c_str(), url.port().c_str());
+
+    pn_listener_t* listener = pn_listener();
+    pn_proactor_listen(proactor_, listener, &caddr[0], 16);
+    return listener;
+}
+
+proton::listener container::impl::listen(const std::string& addr) {
+    pn_listener_t* listener = listen_common_lh(addr);
+    return proton::listener(listener);
+}
+
+proton::listener container::impl::listen(const std::string& addr, const proton::connection_options& opts) {
+    pn_listener_t* listener = listen_common_lh(addr);
+    listener_context& lc=listener_context::get(listener);
+    lc.connection_options_.reset(new connection_options(opts));
+    return proton::listener(listener);
+}
+
+proton::listener container::impl::listen(const std::string& addr, proton::listen_handler& lh) {
+    pn_listener_t* listener = listen_common_lh(addr);
+    listener_context& lc=listener_context::get(listener);
+    lc.listen_handler_ = &lh;
+    return proton::listener(listener);
+}
+
+#if PN_CPP_HAS_STD_FUNCTION
+void container::impl::schedule(duration delay, void_function0& f) {
+    schedule(delay, [&f](){ f(); } );
+}
+
+void container::impl::schedule(duration delay, std::function<void()> f) {
+    // Set timeout
+    pn_proactor_set_timeout(proactor_, delay.milliseconds());
+
+    // Record timeout; Add callback to timeout sorted list
+    deferred_.emplace_back(scheduled{timestamp::now()+delay, f});
+    std::push_heap(deferred_.begin(), deferred_.end());
+}
+#else
+void container::impl::scheduled::task() {(*task_)();}
+
+void container::impl::schedule(duration delay, void_function0& f) {
+    // Set timeout
+    pn_proactor_set_timeout(proactor_, delay.milliseconds());
+
+    // Record timeout; Add callback to timeout sorted list
+    scheduled s={timestamp::now()+delay, &f};
+    deferred_.push_back(s);
+    std::push_heap(deferred_.begin(), deferred_.end());
+}
+#endif
+
+void container::impl::client_connection_options(const connection_options &opts) {
+    client_connection_options_ = opts;
+}
+
+void container::impl::server_connection_options(const connection_options &opts) {
+    server_connection_options_ = opts;
+}
+
+void container::impl::sender_options(const proton::sender_options &opts) {
+    sender_options_ = opts;
+}
+
+void container::impl::receiver_options(const proton::receiver_options &opts) {
+    receiver_options_ = opts;
+}
+
+void container::impl::run_timer_jobs() {
+    // Check head of timer queue
+    timestamp now = timestamp::now();
+    scheduled* next = &deferred_.front();
+
+    // So every scheduled element that has past run and remove head
+    while ( next->time<=now ) {
+        next->task();
+        std::pop_heap(deferred_.begin(), deferred_.end());
+        deferred_.pop_back();
+        // If there are no more scheduled items finish now
+        if  ( deferred_.size()==0 ) return;
+        next = &deferred_.front();
+    };
+
+    // To get here we know we must have at least one more thing scheduled
+    pn_proactor_set_timeout(proactor_, (next->time-now).milliseconds());
+}
+
+bool container::impl::handle(pn_event_t* event) {
+
+    // If we have any pending connection work, do it now
+    pn_connection_t* c = pn_event_connection(event);
+    if (c) {
+        event_loop::impl* loop = connection_context::get(c).event_loop_.impl_.get();
+        loop->run_all_jobs();
+    }
+
+    // Process events that shouldn't be sent to messaging_handler
+    switch (pn_event_type(event)) {
+
+    case PN_PROACTOR_INACTIVE: /* listener and all connections closed */
+        return auto_stop_;
+
+    // We never interrupt the proactor so ignore
+    case PN_PROACTOR_INTERRUPT:
+        return false;
+
+    case PN_PROACTOR_TIMEOUT:
+        // Maybe we got a timeout and have nothing scheduled (not sure if this is possible)
+        if  ( deferred_.size()==0 ) return false;
+
+        run_timer_jobs();
+        return false;
+
+    case PN_LISTENER_OPEN:
+        return false;
+
+    case PN_LISTENER_ACCEPT: {
+        pn_listener_t* l = pn_event_listener(event);
+        pn_connection_t* c = pn_connection();
+        listener_context &lc(listener_context::get(l));
+        pn_connection_set_container(c, id_.c_str());
+        connection_options opts = server_connection_options_;
+        if (lc.listen_handler_) {
+            listener lstr(l);
+            opts.update(lc.listen_handler_->on_accept(lstr));
+        }
+        else if (!!lc.connection_options_) opts.update(*lc.connection_options_);
+        lc.connection_options_.reset(new connection_options(opts));
+        // Handler applied separately
+        connection_context& cc = connection_context::get(c);
+        cc.container = &container_;
+        cc.listener_context_ = &lc;
+        cc.handler = opts.handler();
+        cc.event_loop_ = new event_loop::impl(c);
+        pn_listener_accept(l, c);
+        return false;
+    }
+    case PN_LISTENER_CLOSE: {
+        pn_listener_t* l = pn_event_listener(event);
+        listener_context &lc(listener_context::get(l));
+        listener lstnr(l);
+        if (lc.listen_handler_) {
+            pn_condition_t* c = pn_listener_condition(l);
+            if (pn_condition_is_set(c)) {
+                lc.listen_handler_->on_error(lstnr, make_wrapper(c).what());
+            }
+            lc.listen_handler_->on_close(lstnr);
+        }
+        return false;
+    }
+    // If the event was just connection wake then there isn't anything more to do
+    case PN_CONNECTION_WAKE:
+        return false;
+
+    // Connection driver will bind a new transport to the connection at this point
+    case PN_CONNECTION_INIT:
+        return false;
+
+    case PN_CONNECTION_BOUND: {
+        // Need to apply post bind connection options
+        pn_connection_t* c = pn_event_connection(event);
+        connection conn = make_wrapper(c);
+        connection_context& cc = connection_context::get(c);
+        if (cc.listener_context_) {
+            cc.listener_context_->connection_options_->apply_bound(conn);
+        } else {
+            client_connection_options_.apply_bound(conn);
+        }
+
+        return false;
+    }
+    default:
+        break;
+    }
+
+    // Figure out the handler for the primary object for event
+    messaging_handler* mh = 0;
+
+    // First try for a link (send/receiver) handler
+    pn_link_t *link = pn_event_link(event);
+    if (link) mh = get_handler(link);
+
+    // Try for session handler if no link handler
+    pn_session_t *session = pn_event_session(event);
+    if (session && !mh) mh = get_handler(session);
+
+    // Try for connection handler if none of the above
+    pn_connection_t *connection = pn_event_connection(event);
+    if (connection && !mh) mh = get_handler(connection);
+
+    // Use container handler if nothing more specific (must be a container handler)
+    if (!mh) mh = handler_;
+
+    // If we still have no handler don't do anything!
+    // This is pretty unusual, but possible if we use the default constructor for container
+    if (!mh) return false;
+
+    // TODO: Currently create a throwaway messaging_adapter and proton_event so we can call dispatch, a bit inefficient
+    messaging_adapter ma(*mh);
+    proton_event pe(event);
+    pe.dispatch(ma);
+    return false;
+}
+
+void container::impl::thread(container::impl& ci) {
+  bool finished = false;
+  do {
+    pn_event_batch_t *events = pn_proactor_wait(ci.proactor_);
+    pn_event_t *e;
+    while ((e = pn_event_batch_next(events))) {
+      finished = ci.handle(e) || finished;
+    }
+    pn_proactor_done(ci.proactor_, events);
+  } while(!finished);
+}
+
+void container::impl::run() {
+    // Have to "manually" generate container events
+    if (handler_) handler_->on_container_start(container_);
+    thread(*this);
+    if (handler_) handler_->on_container_stop(container_);
+}
+
+void container::impl::auto_stop(bool set) {
+    auto_stop_ = set;
+}
+
+void container::impl::stop(const proton::error_condition& err) {
+    auto_stop_ = true;
+    stopping_ = true;
+    pn_condition_t* error_condition = pn_condition();
+    set_error_condition(err, error_condition);
+    pn_proactor_disconnect(proactor_, error_condition);
+    pn_condition_free(error_condition);
+}
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/receiver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/receiver.cpp b/proton-c/bindings/cpp/src/receiver.cpp
index 68d55d0..b7239a5 100644
--- a/proton-c/bindings/cpp/src/receiver.cpp
+++ b/proton-c/bindings/cpp/src/receiver.cpp
@@ -34,7 +34,6 @@
 #include <proton/session.h>
 #include <proton/link.h>
 #include <proton/event.h>
-#include <proton/reactor.h>
 
 namespace proton {
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/receiver_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/receiver_options.cpp b/proton-c/bindings/cpp/src/receiver_options.cpp
index 4a4d80f..2b134bc 100644
--- a/proton-c/bindings/cpp/src/receiver_options.cpp
+++ b/proton-c/bindings/cpp/src/receiver_options.cpp
@@ -27,7 +27,7 @@
 #include <proton/link.h>
 
 #include "contexts.hpp"
-#include "container_impl.hpp"
+#include "proactor_container_impl.hpp"
 #include "messaging_adapter.hpp"
 #include "proton_bits.hpp"
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/reconnect_timer.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/reconnect_timer.cpp b/proton-c/bindings/cpp/src/reconnect_timer.cpp
index c63f8a1..a299b0e 100644
--- a/proton-c/bindings/cpp/src/reconnect_timer.cpp
+++ b/proton-c/bindings/cpp/src/reconnect_timer.cpp
@@ -23,7 +23,6 @@
 #include "proton/error.hpp"
 #include "msg.hpp"
 #include <proton/types.h>
-#include <proton/reactor.h>
 
 namespace proton {
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/sender_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/sender_options.cpp b/proton-c/bindings/cpp/src/sender_options.cpp
index 4f501e6..9305666 100644
--- a/proton-c/bindings/cpp/src/sender_options.cpp
+++ b/proton-c/bindings/cpp/src/sender_options.cpp
@@ -24,7 +24,7 @@
 #include "proton/source_options.hpp"
 #include "proton/target_options.hpp"
 
-#include "container_impl.hpp"
+#include "proactor_container_impl.hpp"
 #include "contexts.hpp"
 #include "messaging_adapter.hpp"
 #include "proton_bits.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9fad779c/proton-c/bindings/cpp/src/session_options.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/session_options.cpp b/proton-c/bindings/cpp/src/session_options.cpp
index 2147fd4..fc03ebb 100644
--- a/proton-c/bindings/cpp/src/session_options.cpp
+++ b/proton-c/bindings/cpp/src/session_options.cpp
@@ -27,7 +27,7 @@
 #include <proton/session.h>
 
 #include "messaging_adapter.hpp"
-#include "container_impl.hpp"
+#include "proactor_container_impl.hpp"
 #include "proton_bits.hpp"
 
 namespace proton {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[10/20] qpid-proton git commit: PROTON-1400: WIP Use the mt broker example as the example instead of the previous st broker - The st broker didn't correctly respect the object access constraints from within handlers

Posted by as...@apache.org.
PROTON-1400: WIP Use the mt broker example as the example instead of the previous st broker
- The st broker didn't correctly respect the object access constraints from within handlers


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/4eba80ee
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/4eba80ee
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/4eba80ee

Branch: refs/heads/master
Commit: 4eba80ee8527ab3145427803ad3bfdf801d79229
Parents: d168b7b
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Jan 24 23:36:03 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp             | 352 +++++++++++---------
 examples/cpp/broker.hpp             | 236 --------------
 examples/cpp/mt/broker.cpp          | 318 ------------------
 examples/cpp/mt/epoll_container.cpp | 541 -------------------------------
 examples/cpp/mt/mt_container.hpp    |  29 --
 5 files changed, 190 insertions(+), 1286 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4eba80ee/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 97ef206..e47a2a6 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,271 +15,300 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
 
 #include "options.hpp"
 
 #include <proton/connection.hpp>
+#include <proton/connection_options.hpp>
 #include <proton/container.hpp>
 #include <proton/default_container.hpp>
 #include <proton/delivery.hpp>
 #include <proton/error_condition.hpp>
+#include <proton/listen_handler.hpp>
 #include <proton/listener.hpp>
-#include <proton/messaging_handler.hpp>
 #include <proton/message.hpp>
-#include <proton/receiver_options.hpp>
-#include <proton/sender.hpp>
+#include <proton/messaging_handler.hpp>
 #include <proton/sender_options.hpp>
 #include <proton/source_options.hpp>
-#include <proton/target_options.hpp>
+#include <proton/target.hpp>
+#include <proton/thread_safe.hpp>
 #include <proton/tracker.hpp>
-#include <proton/transport.hpp>
-#include <proton/url.hpp>
 
+#include <atomic>
 #include <deque>
+#include <functional>
 #include <iostream>
-#include <list>
 #include <map>
+#include <mutex>
 #include <string>
 
 #include "fake_cpp11.hpp"
 
-/// A simple implementation of a queue.
+// Thread safe queue.
+// Stores messages, notifies subscribed connections when there is data.
 class queue {
   public:
-    queue(const std::string &name, bool dynamic = false) : name_(name), dynamic_(dynamic) {}
+    queue(const std::string& name) : name_(name) {}
 
     std::string name() const { return name_; }
 
-    void subscribe(proton::sender s) {
-        consumers_.push_back(s);
-    }
-
-    // Return true if queue can be deleted.
-    bool unsubscribe(proton::sender s) {
-        consumers_.remove(s);
-        return (consumers_.size() == 0 && (dynamic_ || messages_.size() == 0));
-    }
-
-    void publish(const proton::message &m) {
+    // Push a message onto the queue.
+    // If the queue was previously empty, notify subscribers it has messages.
+    // Called from receiver's connection.
+    void push(const proton::message &m) {
+        std::lock_guard<std::mutex> g(lock_);
         messages_.push_back(m);
-        dispatch(0);
-    }
-
-    void dispatch(proton::sender *s) {
-        while (deliver_to(s)) {}
-    }
-
-    bool deliver_to(proton::sender *s) {
-        // Deliver to single sender if supplied, else all consumers
-        int count = s ? 1 : consumers_.size();
-
-        if (!count) return false;
-
-        bool result = false;
-        sender_list::iterator it = consumers_.begin();
-
-        if (!s && count) {
-            s = &*it;
+        if (messages_.size() == 1) { // Non-empty, notify subscribers
+            for (auto cb : callbacks_)
+                cb(this);
+            callbacks_.clear();
         }
+    }
 
-        while (messages_.size()) {
-            if (s->credit()) {
-                const proton::message& m = messages_.front();
-
-                s->send(m);
-                messages_.pop_front();
-                result = true;
-            }
-
-            if (--count) {
-                it++;
-            } else {
-                return result;
-            }
+    // If the queue is not empty, pop a message into m and return true.
+    // Otherwise save callback to be called when there are messages and return false.
+    // Called from sender's connection.
+    bool pop(proton::message& m, std::function<void(queue*)> callback) {
+        std::lock_guard<std::mutex> g(lock_);
+        if (messages_.empty()) {
+            callbacks_.push_back(callback);
+            return false;
+        } else {
+            m = std::move(messages_.front());
+            messages_.pop_front();
+            return true;
         }
-
-        return false;
     }
 
   private:
-    typedef std::deque<proton::message> message_queue;
-    typedef std::list<proton::sender> sender_list;
-
-    std::string name_;
-    bool dynamic_;
-    message_queue messages_;
-    sender_list consumers_;
+    const std::string name_;
+    std::mutex lock_;
+    std::deque<proton::message> messages_;
+    std::vector<std::function<void(queue*)> > callbacks_;
 };
 
-/// A collection of queues and queue factory, used by a broker.
+/// Thread safe map of queues.
 class queues {
   public:
     queues() : next_id_(0) {}
-    virtual ~queues() {}
 
-    // Get or create a queue.
-    virtual queue &get(const std::string &address) {
-        if (address.empty()) {
-            throw std::runtime_error("empty queue name");
-        }
-
-        queue*& q = queues_[address];
-
-        if (!q) q = new queue(address);
-
-        return *q;
+    // Get or create the named queue.
+    queue* get(const std::string& name) {
+        std::lock_guard<std::mutex> g(lock_);
+        auto i = queues_.insert(queue_map::value_type(name, nullptr)).first;
+        if (!i->second)
+            i->second.reset(new queue(name));
+        return i->second.get();
     }
 
     // Create a dynamic queue with a unique name.
-    virtual queue &dynamic() {
+    queue* dynamic() {
         std::ostringstream os;
-        os << "q" << next_id_++;
-        queue *q = queues_[os.str()] = new queue(os.str(), true);
-
-        return *q;
+        os << "_dynamic_" << next_id_++;
+        return get(os.str());
     }
 
-    // Delete the named queue
-    virtual void erase(std::string &name) {
-        delete queues_[name];
-        queues_.erase(name);
-    }
+  private:
+    typedef std::map<std::string, std::unique_ptr<queue> > queue_map;
 
-  protected:
-    typedef std::map<std::string, queue *> queue_map;
+    std::mutex lock_;
     queue_map queues_;
-    int next_id_; // Use to generate unique queue IDs.
+    std::atomic<int> next_id_; // Use to generate unique queue IDs.
 };
 
-// A handler to implement broker logic
-class broker_handler : public proton::messaging_handler {
+/// Broker connection handler. Things to note:
+///
+/// 1. Each handler manages a single connection.
+///
+/// 2. For a *single connection* calls to proton::handler functions and calls to
+/// function objects passed to proton::event_loop::inject() are serialized,
+/// i.e. never called concurrently. Handlers can have per-connection state
+/// without needing locks.
+///
+/// 3. Handler/injected functions for *different connections* can be called
+/// concurrently. Resources used by multiple connections (e.g. the queues in
+/// this example) must be thread-safe.
+///
+/// 4. You can 'inject' work to be done sequentially using a connection's
+/// proton::event_loop. In this example, we create a std::function callback
+/// that we pass to queues, so they can notify us when they have messages.
+///
+class broker_connection_handler : public proton::messaging_handler {
   public:
-    broker_handler(queues& qs) : queues_(qs) {}
+    broker_connection_handler(queues& qs) : queues_(qs) {}
+
+    void on_connection_open(proton::connection& c) OVERRIDE {
+        // Create the has_messages callback for queue subscriptions.
+        //
+        // Make a std::shared_ptr to a thread_safe handle for our proton::connection.
+        // The connection's proton::event_loop will remain valid as a shared_ptr exists.
+        std::shared_ptr<proton::thread_safe<proton::connection> > ts_c = make_shared_thread_safe(c);
+
+        // Make a lambda function to inject a call to this->has_messages() via the proton::event_loop.
+        // The function is bound to a shared_ptr so this is safe. If the connection has already closed
+        // proton::event_loop::inject() will drop the callback.
+        has_messages_callback_ = [this, ts_c](queue* q) mutable {
+            ts_c->event_loop().inject(
+                std::bind(&broker_connection_handler::has_messages, this, q));
+        };
+
+        c.open();            // Accept the connection
+    }
 
+    // A sender sends messages from a queue to a subscriber.
     void on_sender_open(proton::sender &sender) OVERRIDE {
-        proton::source src(sender.source());
-        queue *q;
-        if (src.dynamic()) {
-            q = &queues_.dynamic();
-        } else if (!src.address().empty()) {
-            q = &queues_.get(src.address());
-        } else {
-            sender.close(proton::error_condition("No queue address supplied"));
-            return;
-        }
-        sender.open(proton::sender_options().source(proton::source_options().address(q->name())));
-        q->subscribe(sender);
-        std::cout << "broker outgoing link from " << q->name() << std::endl;
+        queue *q = sender.source().dynamic() ?
+            queues_.dynamic() : queues_.get(sender.source().address());
+        sender.open(proton::sender_options().source((proton::source_options().address(q->name()))));
+        std::cout << "sending from " << q->name() << std::endl;
+    }
+
+    // We have credit to send a message.
+    void on_sendable(proton::sender &s) OVERRIDE {
+        queue* q = sender_queue(s);
+        if (!do_send(q, s))     // Queue is empty, save ourselves in the blocked set.
+            blocked_.insert(std::make_pair(q, s));
     }
 
-    void on_receiver_open(proton::receiver &receiver) OVERRIDE {
-        std::string address = receiver.target().address();
-        if (!address.empty()) {
-            receiver.open(proton::receiver_options().target(proton::target_options().address(address)));
-            std::cout << "broker incoming link to " << address << std::endl;
+    // A receiver receives messages from a publisher to a queue.
+    void on_receiver_open(proton::receiver &r) OVERRIDE {
+        std::string qname = r.target().address();
+        if (qname == "shutdown") {
+            std::cout << "broker shutting down" << std::endl;
+            // Sending to the special "shutdown" queue stops the broker.
+            r.connection().container().stop(
+                proton::error_condition("shutdown", "stop broker"));
         } else {
-            receiver.close(proton::error_condition("No queue address supplied"));
+            std::cout << "receiving to " << qname << std::endl;
         }
     }
 
-    void unsubscribe(proton::sender lnk) {
-        std::string address = lnk.source().address();
+    // A message is received.
+    void on_message(proton::delivery &d, proton::message &m) OVERRIDE {
+        std::string qname = d.receiver().target().address();
+        queues_.get(qname)->push(m);
+    }
 
-        if (queues_.get(address).unsubscribe(lnk)) {
-            queues_.erase(address);
-        }
+    void on_session_close(proton::session &session) OVERRIDE {
+        // Erase all blocked senders that belong to session.
+        auto predicate = [session](const proton::sender& s) {
+            return s.session() == session;
+        };
+        erase_sender_if(blocked_.begin(), blocked_.end(), predicate);
     }
 
     void on_sender_close(proton::sender &sender) OVERRIDE {
-        unsubscribe(sender);
+        // Erase sender from the blocked set.
+        auto range = blocked_.equal_range(sender_queue(sender));
+        auto predicate = [sender](const proton::sender& s) { return s == sender; };
+        erase_sender_if(range.first, range.second, predicate);
     }
 
-    void on_connection_close(proton::connection &c) OVERRIDE {
-        remove_stale_consumers(c);
+    void on_error(const proton::error_condition& e) OVERRIDE {
+        std::cerr << "error: " << e.what() << std::endl;
     }
-
-    void on_transport_close(proton::transport &t) OVERRIDE {
-        remove_stale_consumers(t.connection());
+    // The container calls on_transport_close() last.
+    void on_transport_close(proton::transport&) OVERRIDE {
+        delete this;            // All done.
     }
 
-    void on_transport_error(proton::transport &t) OVERRIDE {
-        std::cout << "broker client disconnect: " << t.error().what() << std::endl;
-    }
+  private:
+    typedef std::multimap<queue*, proton::sender> blocked_map;
 
-    void on_error(const proton::error_condition &c) OVERRIDE {
-        std::cerr << "broker error: " << c.what() << std::endl;
+    // Get the queue associated with a sender.
+    queue* sender_queue(const proton::sender& s) {
+        return queues_.get(s.source().address()); // Thread safe.
     }
 
-    void remove_stale_consumers(proton::connection connection) {
-        proton::sender_range r = connection.senders();
-        for (proton::sender_iterator i = r.begin(); i != r.end(); ++i) {
-            if (i->active())
-                unsubscribe(*i);
-        }
+    // Only called if we have credit. Return true if we sent a message.
+    bool do_send(queue* q, proton::sender &s) {
+        proton::message m;
+        bool popped =  q->pop(m, has_messages_callback_);
+        if (popped)
+            s.send(m);
+        /// if !popped the queue has saved the callback for later.
+        return popped;
     }
 
-    void on_sendable(proton::sender &s) OVERRIDE {
-        std::string address = s.source().address();
-
-        queues_.get(address).dispatch(&s);
+    // Called via the connection's proton::event_loop when q has messages.
+    // Try all the blocked senders.
+    void has_messages(queue* q) {
+        auto range = blocked_.equal_range(q);
+        for (auto i = range.first; i != range.second;) {
+            if (i->second.credit() <= 0 || do_send(q, i->second))
+                i = blocked_.erase(i); // No credit or send was successful, stop blocked.
+            else
+                ++i;            // have credit, didn't send, keep blocked
+        }
     }
 
-    void on_message(proton::delivery &d, proton::message &m) OVERRIDE {
-        std::string address = d.receiver().target().address();
-        queues_.get(address).publish(m);
+    // Use to erase closed senders from blocked_ set.
+    template <class Predicate>
+    void erase_sender_if(blocked_map::iterator begin, blocked_map::iterator end, Predicate p) {
+        for (auto i = begin; i != end; ) {
+            if (p(i->second))
+                i = blocked_.erase(i);
+            else
+                ++i;
+        }
     }
 
-  protected:
     queues& queues_;
+    blocked_map blocked_;
+    std::function<void(queue*)> has_messages_callback_;
+    proton::connection connection_;
 };
 
 
-// The broker
 class broker {
   public:
-    broker(const std::string& url) : handler_(url, queues_) {}
+    broker(const std::string addr) :
+        container_("mt_broker"), listener_(queues_)
+    {
+        container_.listen(addr, listener_);
+        std::cout << "broker listening on " << addr << std::endl;
+    }
 
-    proton::messaging_handler& handler() { return handler_; }
+    void run() {
+        container_.run(/* std::thread::hardware_concurrency() */);
+    }
 
   private:
-    class my_handler : public broker_handler {
-      public:
-        my_handler(const std::string& u, queues& qs) : broker_handler(qs), url_(u) {}
+    struct listener : public proton::listen_handler {
+        listener(queues& qs) : queues_(qs) {}
 
-        void on_container_start(proton::container &c) OVERRIDE {
-            c.listen(url_);
-            std::cout << "broker listening on " << url_ << std::endl;
+        proton::connection_options on_accept(proton::listener&) OVERRIDE{
+            return proton::connection_options().handler(*(new broker_connection_handler(queues_)));
         }
 
-      private:
-        const std::string& url_;
+        void on_error(proton::listener&, const std::string& s) OVERRIDE {
+            std::cerr << "listen error: " << s << std::endl;
+            throw std::runtime_error(s);
+        }
+        queues& queues_;
     };
 
-  private:
     queues queues_;
-    my_handler handler_;
+    proton::container container_;
+    listener listener_;
 };
 
 int main(int argc, char **argv) {
-    std::string url("0.0.0.0");
+    // Command line options
+    std::string address("0.0.0.0");
     example::options opts(argc, argv);
 
-    opts.add_value(url, 'a', "address", "listen on URL", "URL");
+    opts.add_value(address, 'a', "address", "listen on URL", "URL");
 
     try {
         opts.parse();
-
-        broker b(url);
-        proton::default_container(b.handler()).run();
-
+        broker(address).run();
         return 0;
     } catch (const example::bad_option& e) {
         std::cout << opts << std::endl << e.what() << std::endl;
     } catch (const std::exception& e) {
-        std::cerr << e.what() << std::endl;
+        std::cerr << "broker shutdown: " << e.what() << std::endl;
     }
-
     return 1;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4eba80ee/examples/cpp/broker.hpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.hpp b/examples/cpp/broker.hpp
deleted file mode 100644
index 953713f..0000000
--- a/examples/cpp/broker.hpp
+++ /dev/null
@@ -1,236 +0,0 @@
-#ifndef BROKER_HPP
-#define BROKER_HPP
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/// @file
-///
-/// Common code used by different broker examples.
-///
-/// The examples add functionality as needed, this helps to make it
-/// easier to see the important differences between the examples.
-
-#include <proton/connection.hpp>
-#include <proton/delivery.hpp>
-#include <proton/messaging_handler.hpp>
-#include <proton/message.hpp>
-#include <proton/sasl.hpp>
-#include <proton/sender.hpp>
-#include <proton/tracker.hpp>
-#include <proton/transport.hpp>
-#include <proton/sender_options.hpp>
-#include <proton/receiver_options.hpp>
-#include <proton/source_options.hpp>
-#include <proton/target_options.hpp>
-
-#include <iostream>
-#include <deque>
-#include <map>
-#include <list>
-#include <sstream>
-
-/// A simple implementation of a queue.
-class queue {
-  public:
-    queue(const std::string &name, bool dynamic = false) : name_(name), dynamic_(dynamic) {}
-
-    std::string name() const { return name_; }
-
-    void subscribe(proton::sender s) {
-        consumers_.push_back(s);
-    }
-
-    // Return true if queue can be deleted.
-    bool unsubscribe(proton::sender s) {
-        consumers_.remove(s);
-        return (consumers_.size() == 0 && (dynamic_ || messages_.size() == 0));
-    }
-
-    void publish(const proton::message &m) {
-        messages_.push_back(m);
-        dispatch(0);
-    }
-
-    void dispatch(proton::sender *s) {
-        while (deliver_to(s)) {}
-    }
-
-    bool deliver_to(proton::sender *s) {
-        // Deliver to single sender if supplied, else all consumers
-        int count = s ? 1 : consumers_.size();
-
-        if (!count) return false;
-
-        bool result = false;
-        sender_list::iterator it = consumers_.begin();
-
-        if (!s && count) {
-            s = &*it;
-        }
-
-        while (messages_.size()) {
-            if (s->credit()) {
-                const proton::message& m = messages_.front();
-
-                s->send(m);
-                messages_.pop_front();
-                result = true;
-            }
-
-            if (--count) {
-                it++;
-            } else {
-                return result;
-            }
-        }
-
-        return false;
-    }
-
-  private:
-    typedef std::deque<proton::message> message_queue;
-    typedef std::list<proton::sender> sender_list;
-
-    std::string name_;
-    bool dynamic_;
-    message_queue messages_;
-    sender_list consumers_;
-};
-
-/// A collection of queues and queue factory, used by a broker.
-class queues {
-  public:
-    queues() : next_id_(0) {}
-    virtual ~queues() {}
-
-    // Get or create a queue.
-    virtual queue &get(const std::string &address = std::string()) {
-        if (address.empty()) {
-            throw std::runtime_error("empty queue name");
-        }
-
-        queue*& q = queues_[address];
-
-        if (!q) q = new queue(address);
-
-        return *q;
-    }
-
-    // Create a dynamic queue with a unique name.
-    virtual queue &dynamic() {
-        std::ostringstream os;
-        os << "q" << next_id_++;
-        queue *q = queues_[os.str()] = new queue(os.str(), true);
-
-        return *q;
-    }
-
-    // Delete the named queue
-    virtual void erase(std::string &name) {
-        delete queues_[name];
-        queues_.erase(name);
-    }
-
-  protected:
-    typedef std::map<std::string, queue *> queue_map;
-    queue_map queues_;
-    int next_id_; // Use to generate unique queue IDs.
-};
-
-#include <proton/config.hpp>
-
-/** Common handler logic for brokers. */
-class broker_handler : public proton::messaging_handler {
-  public:
-    broker_handler(queues& qs) : queues_(qs) {}
-
-    void on_transport_open(proton::transport &t) OVERRIDE {
-        std::cout << "Connection from user: " << t.sasl().user() << " (mechanism: " << t.sasl().mech() << ")" << std::endl;
-    }
-
-    void on_sender_open(proton::sender &sender) OVERRIDE {
-        proton::source src(sender.source());
-        queue &q = src.dynamic() ?
-            queues_.dynamic() : queues_.get(src.address());
-        sender.open(proton::sender_options().source(proton::source_options().address(q.name())));
-        q.subscribe(sender);
-        std::cout << "broker outgoing link from " << q.name() << std::endl;
-    }
-
-    void on_receiver_open(proton::receiver &receiver) OVERRIDE {
-        std::string address = receiver.target().address();
-        if (!address.empty()) {
-            receiver.open(proton::receiver_options().target(proton::target_options().address(address)));
-            std::cout << "broker incoming link to " << address << std::endl;
-        }
-    }
-
-    void unsubscribe(proton::sender lnk) {
-        std::string address = lnk.source().address();
-
-        if (queues_.get(address).unsubscribe(lnk)) {
-            queues_.erase(address);
-        }
-    }
-
-    void on_sender_close(proton::sender &sender) OVERRIDE {
-        unsubscribe(sender);
-    }
-
-    void on_connection_close(proton::connection &c) OVERRIDE {
-        remove_stale_consumers(c);
-    }
-
-    void on_transport_close(proton::transport &t) OVERRIDE {
-        remove_stale_consumers(t.connection());
-    }
-
-    void on_transport_error(proton::transport &t) OVERRIDE {
-        std::cout << "broker client disconnect: " << t.error().what() << std::endl;
-    }
-
-    void on_error(const proton::error_condition &c) OVERRIDE {
-        std::cerr << "broker error: " << c.what() << std::endl;
-    }
-
-    void remove_stale_consumers(proton::connection connection) {
-        proton::sender_range sr = connection.senders();
-        for (proton::sender_iterator i = sr.begin(); i != sr.end(); ++i) {
-            if (i->active())
-                unsubscribe(*i);
-        }
-    }
-
-    void on_sendable(proton::sender &s) OVERRIDE {
-        std::string address = s.source().address();
-
-        queues_.get(address).dispatch(&s);
-    }
-
-    void on_message(proton::delivery &d, proton::message &m) OVERRIDE {
-        std::string address = d.receiver().target().address();
-        queues_.get(address).publish(m);
-    }
-
-  protected:
-    queues& queues_;
-};
-
-#endif // BROKER_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4eba80ee/examples/cpp/mt/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/mt/broker.cpp b/examples/cpp/mt/broker.cpp
deleted file mode 100644
index 83b7005..0000000
--- a/examples/cpp/mt/broker.cpp
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "../options.hpp"
-#include "mt_container.hpp"
-
-#include <proton/connection.hpp>
-#include <proton/connection_options.hpp>
-#include <proton/container.hpp>
-#include <proton/default_container.hpp>
-#include <proton/delivery.hpp>
-#include <proton/error_condition.hpp>
-#include <proton/listen_handler.hpp>
-#include <proton/listener.hpp>
-#include <proton/message.hpp>
-#include <proton/messaging_handler.hpp>
-#include <proton/sender_options.hpp>
-#include <proton/source_options.hpp>
-#include <proton/target.hpp>
-#include <proton/thread_safe.hpp>
-#include <proton/tracker.hpp>
-
-#include <atomic>
-#include <deque>
-#include <functional>
-#include <iostream>
-#include <map>
-#include <mutex>
-#include <thread>
-
-#include "../fake_cpp11.hpp"
-
-// Thread safe queue.
-// Stores messages, notifies subscribed connections when there is data.
-class queue {
-  public:
-    queue(const std::string& name) : name_(name) {}
-
-    std::string name() const { return name_; }
-
-    // Push a message onto the queue.
-    // If the queue was previously empty, notify subscribers it has messages.
-    // Called from receiver's connection.
-    void push(const proton::message &m) {
-        std::lock_guard<std::mutex> g(lock_);
-        messages_.push_back(m);
-        if (messages_.size() == 1) { // Non-empty, notify subscribers
-            for (auto cb : callbacks_)
-                cb(this);
-            callbacks_.clear();
-        }
-    }
-
-    // If the queue is not empty, pop a message into m and return true.
-    // Otherwise save callback to be called when there are messages and return false.
-    // Called from sender's connection.
-    bool pop(proton::message& m, std::function<void(queue*)> callback) {
-        std::lock_guard<std::mutex> g(lock_);
-        if (messages_.empty()) {
-            callbacks_.push_back(callback);
-            return false;
-        } else {
-            m = std::move(messages_.front());
-            messages_.pop_front();
-            return true;
-        }
-    }
-
-  private:
-    const std::string name_;
-    std::mutex lock_;
-    std::deque<proton::message> messages_;
-    std::vector<std::function<void(queue*)> > callbacks_;
-};
-
-/// Thread safe map of queues.
-class queues {
-  public:
-    queues() : next_id_(0) {}
-
-    // Get or create the named queue.
-    queue* get(const std::string& name) {
-        std::lock_guard<std::mutex> g(lock_);
-        auto i = queues_.insert(queue_map::value_type(name, nullptr)).first;
-        if (!i->second)
-            i->second.reset(new queue(name));
-        return i->second.get();
-    }
-
-    // Create a dynamic queue with a unique name.
-    queue* dynamic() {
-        std::ostringstream os;
-        os << "_dynamic_" << next_id_++;
-        return get(os.str());
-    }
-
-  private:
-    typedef std::map<std::string, std::unique_ptr<queue> > queue_map;
-
-    std::mutex lock_;
-    queue_map queues_;
-    std::atomic<int> next_id_; // Use to generate unique queue IDs.
-};
-
-/// Broker connection handler. Things to note:
-///
-/// 1. Each handler manages a single connection.
-///
-/// 2. For a *single connection* calls to proton::handler functions and calls to
-/// function objects passed to proton::event_loop::inject() are serialized,
-/// i.e. never called concurrently. Handlers can have per-connection state
-/// without needing locks.
-///
-/// 3. Handler/injected functions for *different connections* can be called
-/// concurrently. Resources used by multiple connections (e.g. the queues in
-/// this example) must be thread-safe.
-///
-/// 4. You can 'inject' work to be done sequentially using a connection's
-/// proton::event_loop. In this example, we create a std::function callback
-/// that we pass to queues, so they can notify us when they have messages.
-///
-class broker_connection_handler : public proton::messaging_handler {
-  public:
-    broker_connection_handler(queues& qs) : queues_(qs) {}
-
-    void on_connection_open(proton::connection& c) OVERRIDE {
-        // Create the has_messages callback for queue subscriptions.
-        //
-        // Make a std::shared_ptr to a thread_safe handle for our proton::connection.
-        // The connection's proton::event_loop will remain valid as a shared_ptr exists.
-        std::shared_ptr<proton::thread_safe<proton::connection> > ts_c = make_shared_thread_safe(c);
-
-        // Make a lambda function to inject a call to this->has_messages() via the proton::event_loop.
-        // The function is bound to a shared_ptr so this is safe. If the connection has already closed
-        // proton::event_loop::inject() will drop the callback.
-        has_messages_callback_ = [this, ts_c](queue* q) mutable {
-            ts_c->event_loop()->inject(
-                std::bind(&broker_connection_handler::has_messages, this, q));
-        };
-
-        c.open();            // Accept the connection
-    }
-
-    // A sender sends messages from a queue to a subscriber.
-    void on_sender_open(proton::sender &sender) OVERRIDE {
-        queue *q = sender.source().dynamic() ?
-            queues_.dynamic() : queues_.get(sender.source().address());
-        sender.open(proton::sender_options().source((proton::source_options().address(q->name()))));
-        std::cout << "sending from " << q->name() << std::endl;
-    }
-
-    // We have credit to send a message.
-    void on_sendable(proton::sender &s) OVERRIDE {
-        queue* q = sender_queue(s);
-        if (!do_send(q, s))     // Queue is empty, save ourselves in the blocked set.
-            blocked_.insert(std::make_pair(q, s));
-    }
-
-    // A receiver receives messages from a publisher to a queue.
-    void on_receiver_open(proton::receiver &r) OVERRIDE {
-        std::string qname = r.target().address();
-        if (qname == "shutdown") {
-            std::cout << "broker shutting down" << std::endl;
-            // Sending to the special "shutdown" queue stops the broker.
-            r.connection().container().stop(
-                proton::error_condition("shutdown", "stop broker"));
-        } else {
-            std::cout << "receiving to " << qname << std::endl;
-        }
-    }
-
-    // A message is received.
-    void on_message(proton::delivery &d, proton::message &m) OVERRIDE {
-        std::string qname = d.receiver().target().address();
-        queues_.get(qname)->push(m);
-    }
-
-    void on_session_close(proton::session &session) OVERRIDE {
-        // Erase all blocked senders that belong to session.
-        auto predicate = [session](const proton::sender& s) {
-            return s.session() == session;
-        };
-        erase_sender_if(blocked_.begin(), blocked_.end(), predicate);
-    }
-
-    void on_sender_close(proton::sender &sender) OVERRIDE {
-        // Erase sender from the blocked set.
-        auto range = blocked_.equal_range(sender_queue(sender));
-        auto predicate = [sender](const proton::sender& s) { return s == sender; };
-        erase_sender_if(range.first, range.second, predicate);
-    }
-
-    void on_error(const proton::error_condition& e) OVERRIDE {
-        std::cerr << "error: " << e.what() << std::endl;
-    }
-    // The container calls on_transport_close() last.
-    void on_transport_close(proton::transport&) OVERRIDE {
-        delete this;            // All done.
-    }
-
-  private:
-    typedef std::multimap<queue*, proton::sender> blocked_map;
-
-    // Get the queue associated with a sender.
-    queue* sender_queue(const proton::sender& s) {
-        return queues_.get(s.source().address()); // Thread safe.
-    }
-
-    // Only called if we have credit. Return true if we sent a message.
-    bool do_send(queue* q, proton::sender &s) {
-        proton::message m;
-        bool popped =  q->pop(m, has_messages_callback_);
-        if (popped)
-            s.send(m);
-        /// if !popped the queue has saved the callback for later.
-        return popped;
-    }
-
-    // Called via the connection's proton::event_loop when q has messages.
-    // Try all the blocked senders.
-    void has_messages(queue* q) {
-        auto range = blocked_.equal_range(q);
-        for (auto i = range.first; i != range.second;) {
-            if (i->second.credit() <= 0 || do_send(q, i->second))
-                i = blocked_.erase(i); // No credit or send was successful, stop blocked.
-            else
-                ++i;            // have credit, didn't send, keep blocked
-        }
-    }
-
-    // Use to erase closed senders from blocked_ set.
-    template <class Predicate>
-    void erase_sender_if(blocked_map::iterator begin, blocked_map::iterator end, Predicate p) {
-        for (auto i = begin; i != end; ) {
-            if (p(i->second))
-                i = blocked_.erase(i);
-            else
-                ++i;
-        }
-    }
-
-    queues& queues_;
-    blocked_map blocked_;
-    std::function<void(queue*)> has_messages_callback_;
-    proton::connection connection_;
-};
-
-
-class broker {
-  public:
-    broker(const std::string addr) :
-        container_(make_mt_container("mt_broker")), listener_(queues_)
-    {
-        container_->listen(addr, listener_);
-        std::cout << "broker listening on " << addr << std::endl;
-    }
-
-    void run() {
-        std::vector<std::thread> threads(std::thread::hardware_concurrency()-1);
-        for (auto& t : threads)
-            t = std::thread(&proton::container::run, container_.get());
-        container_->run();      // Use this thread too.
-        for (auto& t : threads)
-            t.join();
-    }
-
-  private:
-    struct listener : public proton::listen_handler {
-        listener(queues& qs) : queues_(qs) {}
-
-        proton::connection_options on_accept() OVERRIDE{
-            return proton::connection_options().handler(*(new broker_connection_handler(queues_)));
-        }
-
-        void on_error(const std::string& s) OVERRIDE {
-            std::cerr << "listen error: " << s << std::endl;
-            throw std::runtime_error(s);
-        }
-        queues& queues_;
-    };
-
-    queues queues_;
-    std::unique_ptr<proton::container> container_;
-    listener listener_;
-};
-
-int main(int argc, char **argv) {
-    // Command line options
-    std::string address("0.0.0.0");
-    example::options opts(argc, argv);
-    opts.add_value(address, 'a', "address", "listen on URL", "URL");
-    try {
-        opts.parse();
-        broker(address).run();
-        return 0;
-    } catch (const example::bad_option& e) {
-        std::cout << opts << std::endl << e.what() << std::endl;
-    } catch (const std::exception& e) {
-        std::cerr << "broker shutdown: " << e.what() << std::endl;
-    }
-    return 1;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4eba80ee/examples/cpp/mt/epoll_container.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/mt/epoll_container.cpp b/examples/cpp/mt/epoll_container.cpp
deleted file mode 100644
index 5643fcc..0000000
--- a/examples/cpp/mt/epoll_container.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "mt_container.hpp"
-
-#include <proton/default_container.hpp>
-#include <proton/event_loop.hpp>
-#include <proton/listen_handler.hpp>
-#include <proton/url.hpp>
-
-#include <proton/io/container_impl_base.hpp>
-#include <proton/io/connection_driver.hpp>
-#include <proton/io/link_namer.hpp>
-
-#include <atomic>
-#include <memory>
-#include <mutex>
-#include <condition_variable>
-#include <thread>
-#include <set>
-#include <sstream>
-#include <system_error>
-
-// Linux native IO
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-#include <unistd.h>
-
-#include "../fake_cpp11.hpp"
-
-// Private implementation
-namespace  {
-
-
-using lock_guard = std::lock_guard<std::mutex>;
-
-// Get string from errno
-std::string errno_str(const std::string& msg) {
-    return std::system_error(errno, std::system_category(), msg).what();
-}
-
-// Throw proton::error(errno_str(msg)) if result < 0
-int check(int result, const std::string& msg) {
-    if (result < 0)
-        throw proton::error(errno_str(msg));
-    return result;
-}
-
-// Wrapper for getaddrinfo() that cleans up in destructor.
-class unique_addrinfo {
-  public:
-    unique_addrinfo(const std::string& addr) : addrinfo_(0) {
-        proton::url u(addr);
-        int result = ::getaddrinfo(char_p(u.host()), char_p(u.port()), 0, &addrinfo_);
-        if (result)
-            throw proton::error(std::string("bad address: ") + gai_strerror(result));
-    }
-    ~unique_addrinfo() { if (addrinfo_) ::freeaddrinfo(addrinfo_); }
-
-    ::addrinfo* operator->() const { return addrinfo_; }
-
-  private:
-    static const char* char_p(const std::string& s) { return s.empty() ? 0 : s.c_str(); }
-    ::addrinfo *addrinfo_;
-};
-
-// File descriptor wrapper that calls ::close in destructor.
-class unique_fd {
-  public:
-    unique_fd(int fd) : fd_(fd) {}
-    ~unique_fd() { if (fd_ >= 0) ::close(fd_); }
-    operator int() const { return fd_; }
-    int release() { int ret = fd_; fd_ = -1; return ret; }
-
-  protected:
-    int fd_;
-};
-
-class pollable;
-class pollable_driver;
-class pollable_listener;
-
-class epoll_container : public proton::io::container_impl_base {
-  public:
-    epoll_container(const std::string& id);
-    ~epoll_container();
-
-    // Pull in base class functions here so that name search finds all the overloads
-    using standard_container::stop;
-    using standard_container::connect;
-    using standard_container::listen;
-
-    proton::returned<proton::connection> connect(
-        const std::string& addr, const proton::connection_options& opts) OVERRIDE;
-
-    proton::listener listen(const std::string& addr, proton::listen_handler&) OVERRIDE;
-
-    void stop_listening(const std::string& addr) OVERRIDE;
-
-    void run() OVERRIDE;
-    void auto_stop(bool) OVERRIDE;
-    void stop(const proton::error_condition& err) OVERRIDE;
-
-    std::string id() const OVERRIDE { return id_; }
-
-    // Functions used internally.
-    proton::connection add_driver(proton::connection_options opts, int fd, bool server);
-    void erase(pollable*);
-
-    // Link names must be unique per container.
-    // Generate unique names with a simple atomic counter.
-    class atomic_link_namer : public proton::io::link_namer {
-      public:
-        std::string link_name() {
-            std::ostringstream o;
-            o << std::hex << ++count_;
-            return o.str();
-        }
-      private:
-        std::atomic<int> count_;
-    };
-
-     // TODO aconway 2016-06-07: Unfinished
-    void schedule(proton::duration, std::function<void()>) OVERRIDE { throw std::logic_error("not implemented"); }
-    void schedule(proton::duration, proton::void_function0&) OVERRIDE { throw std::logic_error("not implemented"); }
-    atomic_link_namer link_namer;
-
-  private:
-    template <class T> void store(T& v, const T& x) const { lock_guard g(lock_); v = x; }
-
-    void idle_check(const lock_guard&);
-    void interrupt();
-    void wait();
-
-    const std::string id_;
-    const unique_fd epoll_fd_;
-    const unique_fd interrupt_fd_;
-
-    mutable std::mutex lock_;
-
-    proton::connection_options options_;
-    std::map<std::string, std::unique_ptr<pollable_listener> > listeners_;
-    std::map<pollable*, std::unique_ptr<pollable_driver> > drivers_;
-
-    std::condition_variable stopped_;
-    bool stopping_;
-    proton::error_condition stop_err_;
-    std::atomic<size_t> threads_;
-};
-
-// Base class for pollable file-descriptors. Manages epoll interaction,
-// subclasses implement virtual work() to do their serialized work.
-class pollable {
-  public:
-    pollable(int fd, int epoll_fd) : fd_(fd), epoll_fd_(epoll_fd), notified_(false), working_(false)
-    {
-        int flags = check(::fcntl(fd, F_GETFL, 0), "non-blocking");
-        check(::fcntl(fd, F_SETFL,  flags | O_NONBLOCK), "non-blocking");
-        ::epoll_event ev = {};
-        ev.data.ptr = this;
-        ::epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd_, &ev);
-    }
-
-    virtual ~pollable() {
-        ::epoll_event ev = {};
-        ::epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd_, &ev); // Ignore errors.
-    }
-
-    bool do_work(uint32_t events) {
-        {
-            lock_guard g(lock_);
-            if (working_)
-                return true;         // Another thread is already working.
-            working_ = true;
-            notified_ = false;
-        }
-        uint32_t new_events = work(events);  // Serialized, outside the lock.
-        if (new_events) {
-            lock_guard g(lock_);
-            rearm(notified_ ?  EPOLLIN|EPOLLOUT : new_events);
-        }
-        return new_events;
-    }
-
-    // Called from any thread to wake up the connection handler.
-    void notify() {
-        lock_guard g(lock_);
-        if (!notified_) {
-            notified_ = true;
-            if (!working_) // No worker thread, rearm now.
-                rearm(EPOLLIN|EPOLLOUT);
-        }
-    }
-
-  protected:
-
-    // Subclass implements  work.
-    // Returns epoll events to re-enable or 0 if finished.
-    virtual uint32_t work(uint32_t events) = 0;
-
-    const unique_fd fd_;
-    const int epoll_fd_;
-
-  private:
-
-    void rearm(uint32_t events) {
-        epoll_event ev;
-        ev.data.ptr = this;
-        ev.events = EPOLLONESHOT | events;
-        check(::epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd_, &ev), "re-arm epoll");
-        working_ = false;
-    }
-
-    std::mutex lock_;
-    bool notified_;
-    bool working_;
-};
-
-class epoll_event_loop : public proton::event_loop {
-  public:
-    typedef std::vector<std::function<void()> > jobs;
-
-    epoll_event_loop(pollable& p) : pollable_(p), closed_(false) {}
-
-    bool inject(std::function<void()> f) OVERRIDE {
-        // Note this is an unbounded work queue.
-        // A resource-safe implementation should be bounded.
-        lock_guard g(lock_);
-        if (closed_)
-            return false;
-        jobs_.push_back(f);
-        pollable_.notify();
-        return true;
-    }
-
-    bool inject(proton::void_function0& f) OVERRIDE {
-        return inject([&f]() { f(); });
-    }
-
-    jobs pop_all() {
-        lock_guard g(lock_);
-        return std::move(jobs_);
-    }
-
-    void close() {
-        lock_guard g(lock_);
-        closed_ = true;
-    }
-
-  private:
-    std::mutex lock_;
-    pollable& pollable_;
-    jobs jobs_;
-    bool closed_;
-};
-
-// Handle epoll wakeups for a connection_driver.
-class pollable_driver : public pollable {
-  public:
-    pollable_driver(epoll_container& c, int fd, int epoll_fd) :
-        pollable(fd, epoll_fd),
-        loop_(new epoll_event_loop(*this)),
-        driver_(c, loop_)
-    {
-        proton::connection conn = driver_.connection();
-        proton::io::set_link_namer(conn, c.link_namer);
-    }
-
-    ~pollable_driver() {
-        loop_->close();                // No calls to notify() after this.
-        driver_.dispatch();            // Run any final events.
-        try { write(); } catch(...) {} // Write connection close if we can.
-        for (auto f : loop_->pop_all()) {// Run final queued work for side-effects.
-            try { f(); } catch(...) {}
-        }
-    }
-
-    uint32_t work(uint32_t events) {
-        try {
-            bool can_read = events & EPOLLIN, can_write = events & EPOLLOUT;
-            do {
-                can_write = can_write && write();
-                can_read = can_read && read();
-                for (auto f : loop_->pop_all()) // Run queued work
-                    f();
-                driver_.dispatch();
-            } while (can_read || can_write);
-            return (driver_.read_buffer().size ? EPOLLIN:0) |
-                (driver_.write_buffer().size ? EPOLLOUT:0);
-        } catch (const std::exception& e) {
-            driver_.disconnected(proton::error_condition("exception", e.what()));
-        }
-        return 0;               // Ending
-    }
-
-    proton::io::connection_driver& driver() { return driver_; }
-
-  private:
-    static bool try_again(int e) {
-        // These errno values from read or write mean "try again"
-        return (e == EAGAIN || e == EWOULDBLOCK || e == EINTR);
-    }
-
-    bool write() {
-        proton::io::const_buffer wbuf(driver_.write_buffer());
-        if (wbuf.size) {
-            ssize_t n = ::write(fd_, wbuf.data, wbuf.size);
-            if (n > 0) {
-                driver_.write_done(n);
-                return true;
-            } else if (n < 0 && !try_again(errno)) {
-                check(n, "write");
-            }
-        }
-        return false;
-    }
-
-    bool read() {
-        proton::io::mutable_buffer rbuf(driver_.read_buffer());
-        if (rbuf.size) {
-            ssize_t n = ::read(fd_, rbuf.data, rbuf.size);
-            if (n > 0) {
-                driver_.read_done(n);
-                return true;
-            }
-            else if (n == 0)
-                driver_.read_close();
-            else if (!try_again(errno))
-                check(n, "read");
-        }
-        return false;
-    }
-
-    // Lifecycle note: loop_ belongs to the proton::connection, which can live
-    // longer than the driver if the application holds a reference to it, we
-    // disconnect ourselves with loop_->close() in ~connection_driver()
-    epoll_event_loop* loop_;
-    proton::io::connection_driver driver_;
-};
-
-// A pollable listener fd that creates pollable_driver for incoming connections.
-class pollable_listener : public pollable {
-  public:
-    pollable_listener(
-        const std::string& addr,
-        proton::listen_handler& l,
-        int epoll_fd,
-        epoll_container& c
-    ) :
-        pollable(socket_listen(addr), epoll_fd),
-        addr_(addr),
-        container_(c),
-        listener_(l)
-    {}
-
-    uint32_t work(uint32_t events) {
-        if (events & EPOLLRDHUP) {
-            try { listener_.on_close(); } catch (...) {}
-            return 0;
-        }
-        try {
-            int accepted = check(::accept(fd_, NULL, 0), "accept");
-            container_.add_driver(listener_.on_accept(), accepted, true);
-            return EPOLLIN;
-        } catch (const std::exception& e) {
-            listener_.on_error(e.what());
-            return 0;
-        }
-    }
-
-    std::string addr() { return addr_; }
-
-  private:
-
-    static int socket_listen(const std::string& addr) {
-        std::string msg = "listen on "+addr;
-        unique_addrinfo ainfo(addr);
-        unique_fd fd(check(::socket(ainfo->ai_family, SOCK_STREAM, 0), msg));
-        int yes = 1;
-        check(::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)), msg);
-        check(::bind(fd, ainfo->ai_addr, ainfo->ai_addrlen), msg);
-        check(::listen(fd, 32), msg);
-        return fd.release();
-    }
-
-    std::string addr_;
-    std::function<proton::connection_options(const std::string&)> factory_;
-    epoll_container& container_;
-    proton::connection_options opts_;
-    proton::listen_handler& listener_;
-};
-
-
-epoll_container::epoll_container(const std::string& id)
-    : id_(id),                       epoll_fd_(check(epoll_create(1), "epoll_create")),
-      interrupt_fd_(check(eventfd(1, 0), "eventfd")),
-      stopping_(false), threads_(0)
-{}
-
-epoll_container::~epoll_container() {
-    try {
-        stop(proton::error_condition("exception", "container shut-down"));
-        wait();
-    } catch (...) {}
-}
-
-proton::connection epoll_container::add_driver(proton::connection_options opts, int fd, bool server)
-{
-    lock_guard g(lock_);
-    if (stopping_)
-        throw proton::error("container is stopping");
-    std::unique_ptr<pollable_driver> eng(new pollable_driver(*this, fd, epoll_fd_));
-    if (server)
-        eng->driver().accept(opts);
-    else
-        eng->driver().connect(opts);
-    proton::connection c = eng->driver().connection();
-    eng->notify();
-    drivers_[eng.get()] = std::move(eng);
-    return c;
-}
-
-void epoll_container::erase(pollable* e) {
-    lock_guard g(lock_);
-    if (!drivers_.erase(e)) {
-        pollable_listener* l = dynamic_cast<pollable_listener*>(e);
-        if (l)
-            listeners_.erase(l->addr());
-    }
-    idle_check(g);
-}
-
-void epoll_container::idle_check(const lock_guard&) {
-    if (stopping_  && drivers_.empty() && listeners_.empty())
-        interrupt();
-}
-
-proton::returned<proton::connection> epoll_container::connect(
-    const std::string& addr, const proton::connection_options& opts)
-{
-    std::string msg = "connect to "+addr;
-    unique_addrinfo ainfo(addr);
-    unique_fd fd(check(::socket(ainfo->ai_family, SOCK_STREAM, 0), msg));
-    check(::connect(fd, ainfo->ai_addr, ainfo->ai_addrlen), msg);
-    return make_thread_safe(add_driver(opts, fd.release(), false));
-}
-
-proton::listener epoll_container::listen(const std::string& addr, proton::listen_handler& lh) {
-    lock_guard g(lock_);
-    if (stopping_)
-        throw proton::error("container is stopping");
-    auto& l = listeners_[addr];
-    try {
-        l.reset(new pollable_listener(addr, lh, epoll_fd_, *this));
-        l->notify();
-        return proton::listener(*this, addr);
-    } catch (const std::exception& e) {
-        lh.on_error(e.what());
-        lh.on_close();
-        throw;
-    }
-}
-
-void epoll_container::stop_listening(const std::string& addr) {
-    lock_guard g(lock_);
-    listeners_.erase(addr);
-    idle_check(g);
-}
-
-void epoll_container::run() {
-    ++threads_;
-    try {
-        epoll_event e;
-        while(true) {
-            check(::epoll_wait(epoll_fd_, &e, 1, -1), "epoll_wait");
-            pollable* p = reinterpret_cast<pollable*>(e.data.ptr);
-            if (!p)
-                break;          // Interrupted
-            if (!p->do_work(e.events))
-                erase(p);
-        }
-    } catch (const std::exception& e) {
-        stop(proton::error_condition("exception", e.what()));
-    }
-    if (--threads_ == 0)
-        stopped_.notify_all();
-}
-
-void epoll_container::auto_stop(bool set) {
-    lock_guard g(lock_);
-    stopping_ = set;
-}
-
-void epoll_container::stop(const proton::error_condition& err) {
-    lock_guard g(lock_);
-    stop_err_ = err;
-    interrupt();
-}
-
-void epoll_container::wait() {
-    std::unique_lock<std::mutex> l(lock_);
-    stopped_.wait(l, [this]() { return this->threads_ == 0; } );
-    for (auto& eng : drivers_)
-        eng.second->driver().disconnected(stop_err_);
-    listeners_.clear();
-    drivers_.clear();
-}
-
-void epoll_container::interrupt() {
-    // Add an always-readable fd with 0 data and no ONESHOT to interrupt all threads.
-    epoll_event ev = {};
-    ev.events = EPOLLIN;
-    check(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupt_fd_, &ev), "interrupt");
-}
-
-}
-
-// This is the only public function.
-std::unique_ptr<proton::container> make_mt_container(const std::string& id) {
-    return std::unique_ptr<proton::container>(new epoll_container(id));
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4eba80ee/examples/cpp/mt/mt_container.hpp
----------------------------------------------------------------------
diff --git a/examples/cpp/mt/mt_container.hpp b/examples/cpp/mt/mt_container.hpp
deleted file mode 100644
index 164fe72..0000000
--- a/examples/cpp/mt/mt_container.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef MT_MT_CONTROLLER_HPP
-#define MT_MT_CONTROLLER_HPP
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <proton/default_container.hpp>
-#include <memory>
-
-// Defined in whichever MT container implementation we are linked with.
-std::unique_ptr<proton::container> make_mt_container(const std::string& id);
-
-#endif // MT_MT_DEFAULT_CONTAINER.HPP


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[20/20] qpid-proton git commit: PROTON-1481: [C++ binding] Rename proton::defer -> proton::schedule_work

Posted by as...@apache.org.
PROTON-1481: [C++ binding] Rename proton::defer -> proton::schedule_work


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/8aee73b6
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/8aee73b6
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/8aee73b6

Branch: refs/heads/master
Commit: 8aee73b611bd0faff3d065e1ed16f89d5c222b73
Parents: 1e2efdb
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 19 17:02:05 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         | 24 ++++++------
 examples/cpp/scheduled_send_03.cpp              |  6 +--
 .../bindings/cpp/include/proton/thread_safe.hpp |  2 +-
 .../bindings/cpp/include/proton/work_queue.hpp  | 40 ++++++++++----------
 4 files changed, 36 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8aee73b6/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 09a771c..2cb2b36 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -139,7 +139,7 @@ class Queue {
             DOUT(std::cerr << "(" << current_->second << ") ";);
             if (current_->second>0) {
                 DOUT(std::cerr << current_->first << " ";);
-                proton::defer(current_->first, &Sender::sendMsg, current_->first, messages_.front());
+                proton::schedule_work(current_->first, &Sender::sendMsg, current_->first, messages_.front());
                 messages_.pop_front();
                 --current_->second;
                 ++current_;
@@ -178,14 +178,14 @@ public:
         // If we're about to erase the current subscription move on
         if (current_ != subscriptions_.end() && current_->first==s) ++current_;
         subscriptions_.erase(s);
-        proton::defer(s, &Sender::unsubscribed, s);
+        proton::schedule_work(s, &Sender::unsubscribed, s);
     }
 };
 
 // We have credit to send a message.
 void Sender::on_sendable(proton::sender &sender) {
     if (queue_) {
-        proton::defer(queue_, &Queue::flow, queue_, this, sender.credit());
+        proton::schedule_work(queue_, &Queue::flow, queue_, this, sender.credit());
     } else {
         pending_credit_ = sender.credit();
     }
@@ -193,7 +193,7 @@ void Sender::on_sendable(proton::sender &sender) {
 
 void Sender::on_sender_close(proton::sender &sender) {
     if (queue_) {
-        proton::defer(queue_, &Queue::unsubscribe, queue_, this);
+        proton::schedule_work(queue_, &Queue::unsubscribe, queue_, this);
     } else {
         // TODO: Is it possible to be closed before we get the queue allocated?
         // If so, we should have a way to mark the sender deleted, so we can delete
@@ -207,12 +207,12 @@ void Sender::boundQueue(Queue* q, std::string qn) {
     queue_ = q;
     queue_name_ = qn;
 
-    proton::defer(q, &Queue::subscribe, q, this);
+    proton::schedule_work(q, &Queue::subscribe, q, this);
     sender_.open(proton::sender_options()
         .source((proton::source_options().address(queue_name_)))
         .handler(*this));
     if (pending_credit_>0) {
-        proton::defer(queue_, &Queue::flow, queue_, this, pending_credit_);
+        proton::schedule_work(queue_, &Queue::flow, queue_, this, pending_credit_);
     }
     std::cout << "sending from " << queue_name_ << std::endl;
 }
@@ -237,7 +237,7 @@ class Receiver : public proton::messaging_handler {
     void queueMsgs() {
         DOUT(std::cerr << "Receiver: " << this << " queueing " << messages_.size() << " msgs to: " << queue_ << "\n";);
         while (!messages_.empty()) {
-            proton::defer(queue_, &Queue::queueMsg, queue_, messages_.front());
+            proton::schedule_work(queue_, &Queue::queueMsg, queue_, messages_.front());
             messages_.pop_front();
         }
     }
@@ -295,7 +295,7 @@ public:
         } else {
             q = i->second;
         }
-        proton::defer(&connection, &T::boundQueue, &connection, q, qn);
+        proton::schedule_work(&connection, &T::boundQueue, &connection, q, qn);
     }
 
     void findQueueSender(Sender* s, std::string qn) {
@@ -325,7 +325,7 @@ public:
         std::string qn = sender.source().dynamic() ? "" : sender.source().address();
         Sender* s = new Sender(sender, senders_);
         senders_[sender] = s;
-        proton::defer(&queue_manager_, &QueueManager::findQueueSender, &queue_manager_, s, qn);
+        proton::schedule_work(&queue_manager_, &QueueManager::findQueueSender, &queue_manager_, s, qn);
     }
 
     // A receiver receives messages from a publisher to a queue.
@@ -341,7 +341,7 @@ public:
                 DOUT(std::cerr << "ODD - trying to attach to a empty address\n";);
             }
             Receiver* r = new Receiver(receiver);
-            proton::defer(&queue_manager_, &QueueManager::findQueueReceiver, &queue_manager_, r, qname);
+            proton::schedule_work(&queue_manager_, &QueueManager::findQueueReceiver, &queue_manager_, r, qname);
         }
     }
 
@@ -352,7 +352,7 @@ public:
             if (j == senders_.end()) continue;
             Sender* s = j->second;
             if (s->queue_) {
-                proton::defer(s->queue_, &Queue::unsubscribe, s->queue_, s);
+                proton::schedule_work(s->queue_, &Queue::unsubscribe, s->queue_, s);
             }
             senders_.erase(j);
         }
@@ -370,7 +370,7 @@ public:
             if (j == senders_.end()) continue;
             Sender* s = j->second;
             if (s->queue_) {
-                proton::defer(s->queue_, &Queue::unsubscribe, s->queue_, s);
+                proton::schedule_work(s->queue_, &Queue::unsubscribe, s->queue_, s);
             }
         }
         delete this;            // All done.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8aee73b6/examples/cpp/scheduled_send_03.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send_03.cpp b/examples/cpp/scheduled_send_03.cpp
index 8ac46a1..008853c 100644
--- a/examples/cpp/scheduled_send_03.cpp
+++ b/examples/cpp/scheduled_send_03.cpp
@@ -62,8 +62,8 @@ class scheduled_sender : public proton::messaging_handler {
     void on_sender_open(proton::sender & s) OVERRIDE {
         work_queue = &s.work_queue();
 
-        proton::defer(work_queue, timeout, &scheduled_sender::cancel, this, s);
-        proton::defer(work_queue, interval, &scheduled_sender::tick, this, s);
+        proton::schedule_work(work_queue, timeout, &scheduled_sender::cancel, this, s);
+        proton::schedule_work(work_queue, interval, &scheduled_sender::tick, this, s);
     }
 
     void cancel(proton::sender sender) {
@@ -73,7 +73,7 @@ class scheduled_sender : public proton::messaging_handler {
 
     void tick(proton::sender sender) {
         if (!canceled) {
-            proton::defer(work_queue, interval, &scheduled_sender::tick, this, sender); // Next tick
+            proton::schedule_work(work_queue, interval, &scheduled_sender::tick, this, sender); // Next tick
             if (sender.credit() > 0) // Only send if we have credit
                 send(sender);
             else

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8aee73b6/proton-c/bindings/cpp/include/proton/thread_safe.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/thread_safe.hpp b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
index 04e39df..0b38883 100644
--- a/proton-c/bindings/cpp/include/proton/thread_safe.hpp
+++ b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
@@ -70,7 +70,7 @@ class thread_safe : private internal::pn_ptr_base, private internal::endpoint_tr
 
     ~thread_safe() {
         if (ptr()) {
-            if (!!work_queue().impl_) defer(&work_queue(), &decref, (void*)ptr());
+            if (!!work_queue().impl_) schedule_work(&work_queue(), &decref, (void*)ptr());
             else decref(ptr());
         }
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/8aee73b6/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index 61567b8..844680b 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -284,76 +284,76 @@ void_function0& make_work(R (*f)(A, B, C), A a, B b, C c) {
 
 namespace {
 template <class T>
-bool defer_helper(T t, void_function0& w) {
+bool schedule_work_helper(T t, void_function0& w) {
     bool r = t->add(w);
     if (!r) delete &w;
     return r;
 }
 }
 
-/// defer is a convenience that is used for C++03 code to defer function calls
+/// schedule_work is a convenience that is used for C++03 code to defer function calls
 /// to a work_queue
 template <class WQ, class F>
-bool defer(WQ wq, F f) {
-    return defer_helper(wq, make_work(f));
+bool schedule_work(WQ wq, F f) {
+    return schedule_work_helper(wq, make_work(f));
 }
 
 template <class WQ, class F, class A>
-bool defer(WQ wq, F f, A a) {
-    return defer_helper(wq, make_work(f, a));
+bool schedule_work(WQ wq, F f, A a) {
+    return schedule_work_helper(wq, make_work(f, a));
 }
 
 template <class WQ, class F, class A, class B>
-bool defer(WQ wq, F f, A a, B b) {
-    return defer_helper(wq, make_work(f, a, b));
+bool schedule_work(WQ wq, F f, A a, B b) {
+    return schedule_work_helper(wq, make_work(f, a, b));
 }
 
 template <class WQ, class F, class A, class B, class C>
-bool defer(WQ wq, F f, A a, B b, C c) {
-    return defer_helper(wq, make_work(f, a, b, c));
+bool schedule_work(WQ wq, F f, A a, B b, C c) {
+    return schedule_work_helper(wq, make_work(f, a, b, c));
 }
 
 template <class WQ, class F, class A, class B, class C, class D>
-bool defer(WQ wq, F f, A a, B b, C c, D d) {
-    return defer_helper(wq, make_work(f, a, b, c, d));
+bool schedule_work(WQ wq, F f, A a, B b, C c, D d) {
+    return schedule_work_helper(wq, make_work(f, a, b, c, d));
 }
 
 template <class WQ, class F>
-void defer(WQ wq, duration dn, F f) {
+void schedule_work(WQ wq, duration dn, F f) {
     wq->schedule(dn, make_work(f));
 }
 
 template <class WQ, class F, class A>
-void defer(WQ wq, duration dn, F f, A a) {
+void schedule_work(WQ wq, duration dn, F f, A a) {
     wq->schedule(dn, make_work(f, a));
 }
 
 template <class WQ, class F, class A, class B>
-void defer(WQ wq, duration dn, F f, A a, B b) {
+void schedule_work(WQ wq, duration dn, F f, A a, B b) {
     wq->schedule(dn, make_work(f, a, b));
 }
 
 template <class WQ, class F, class A, class B, class C>
-void defer(WQ wq, duration dn, F f, A a, B b, C c) {
+void schedule_work(WQ wq, duration dn, F f, A a, B b, C c) {
     wq->schedule(dn, make_work(f, a, b, c));
 }
 
 template <class WQ, class F, class A, class B, class C, class D>
-void defer(WQ wq, duration dn, F f, A a, B b, C c, D d) {
+void schedule_work(WQ wq, duration dn, F f, A a, B b, C c, D d) {
     wq->schedule(dn, make_work(f, a, b, c, d));
 }
 
-/// This version of proton::defer defers calling a free function to an arbitrary work queue
+/// This version of proton::schedule_work schedule_works calling a free function to an arbitrary work queue
 #else
 // The C++11 version is *much* simpler and even so more general!
 // These definitions encompass everything in the C++03 section
 template <class WQ, class... Rest>
-bool defer(WQ wq, Rest&&... r) {
+bool schedule_work(WQ wq, Rest&&... r) {
     return wq->add(std::bind(std::forward<Rest>(r)...));
 }
 
 template <class WQ, class... Rest>
-void defer(WQ wq, duration d, Rest&&... r) {
+void schedule_work(WQ wq, duration d, Rest&&... r) {
     wq->schedule(d, std::bind(std::forward<Rest>(r)...));
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[18/20] qpid-proton git commit: PROTON-1482: [C++ binding] Added convenience overload to proton::defer for scheduled deferred work - Used new conveniences in scheduled_send_03 example

Posted by as...@apache.org.
PROTON-1482: [C++ binding] Added convenience overload to proton::defer
for scheduled deferred work
- Used new conveniences in scheduled_send_03 example


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1e2efdb0
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1e2efdb0
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1e2efdb0

Branch: refs/heads/master
Commit: 1e2efdb01c8ebf863626150c9c14eae600c4739c
Parents: 88c2d7d
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri May 19 01:38:18 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/scheduled_send_03.cpp              | 50 +++-----------------
 .../bindings/cpp/include/proton/work_queue.hpp  | 31 ++++++++++++
 2 files changed, 37 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1e2efdb0/examples/cpp/scheduled_send_03.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send_03.cpp b/examples/cpp/scheduled_send_03.cpp
index c3c63c8..8ac46a1 100644
--- a/examples/cpp/scheduled_send_03.cpp
+++ b/examples/cpp/scheduled_send_03.cpp
@@ -46,49 +46,13 @@ class scheduled_sender : public proton::messaging_handler {
     proton::work_queue *work_queue;
     bool ready, canceled;
 
-    struct cancel_fn : public proton::void_function0 {
-        scheduled_sender* parent;
-        proton::sender sender;
-        cancel_fn(): parent(0) {}
-        cancel_fn(scheduled_sender& ss, proton::sender& s) : parent(&ss), sender(s) {}
-        void operator()() { if (parent) parent->cancel(sender); }
-    };
-
-    struct tick_fn : public proton::void_function0 {
-        scheduled_sender* parent;
-        proton::sender sender;
-        tick_fn(): parent(0) {}
-        tick_fn(scheduled_sender& ss, proton::sender& s) : parent(&ss), sender(s) {}
-        void operator()() { if (parent) parent->tick(sender); }
-    };
-
-    struct defer_cancel_fn : public proton::void_function0 {
-        scheduled_sender& parent;
-        defer_cancel_fn(scheduled_sender& ss) : parent(ss) {}
-        void operator()() { parent.work_queue->add(parent.do_cancel); }
-    };
-
-    struct defer_tick_fn : public proton::void_function0 {
-        scheduled_sender& parent;
-        defer_tick_fn(scheduled_sender& ss) : parent(ss) {}
-        void operator()() { parent.work_queue->add(parent.do_tick); }
-    };
-
-    tick_fn do_tick;
-    cancel_fn do_cancel;
-    defer_tick_fn defer_tick;
-    defer_cancel_fn defer_cancel;
-
   public:
-
     scheduled_sender(const std::string &s, double d, double t) :
         url(s),
         interval(int(d*proton::duration::SECOND.milliseconds())), // Send interval.
         timeout(int(t*proton::duration::SECOND.milliseconds())), // Cancel after timeout.
         ready(true),            // Ready to send.
-        canceled(false),         // Canceled.
-        defer_tick(*this),
-        defer_cancel(*this)
+        canceled(false)         // Canceled.
     {}
 
     void on_container_start(proton::container &c) OVERRIDE {
@@ -98,20 +62,18 @@ class scheduled_sender : public proton::messaging_handler {
     void on_sender_open(proton::sender & s) OVERRIDE {
         work_queue = &s.work_queue();
 
-        do_cancel = cancel_fn(*this, s);
-        do_tick = tick_fn(*this, s);
-        s.container().schedule(timeout, defer_cancel); // Call this->cancel after timeout.
-        s.container().schedule(interval, defer_tick); // Start regular ticks every interval.
+        proton::defer(work_queue, timeout, &scheduled_sender::cancel, this, s);
+        proton::defer(work_queue, interval, &scheduled_sender::tick, this, s);
     }
 
-    void cancel(proton::sender& sender) {
+    void cancel(proton::sender sender) {
         canceled = true;
         sender.connection().close();
     }
 
-    void tick(proton::sender& sender) {
+    void tick(proton::sender sender) {
         if (!canceled) {
-            sender.container().schedule(interval, defer_tick); // Next tick
+            proton::defer(work_queue, interval, &scheduled_sender::tick, this, sender); // Next tick
             if (sender.credit() > 0) // Only send if we have credit
                 send(sender);
             else

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1e2efdb0/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index bef041c..61567b8 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -22,6 +22,7 @@
  *
  */
 
+#include "./duration.hpp"
 #include "./fwd.hpp"
 #include "./function.hpp"
 #include "./internal/config.hpp"
@@ -317,6 +318,31 @@ bool defer(WQ wq, F f, A a, B b, C c, D d) {
     return defer_helper(wq, make_work(f, a, b, c, d));
 }
 
+template <class WQ, class F>
+void defer(WQ wq, duration dn, F f) {
+    wq->schedule(dn, make_work(f));
+}
+
+template <class WQ, class F, class A>
+void defer(WQ wq, duration dn, F f, A a) {
+    wq->schedule(dn, make_work(f, a));
+}
+
+template <class WQ, class F, class A, class B>
+void defer(WQ wq, duration dn, F f, A a, B b) {
+    wq->schedule(dn, make_work(f, a, b));
+}
+
+template <class WQ, class F, class A, class B, class C>
+void defer(WQ wq, duration dn, F f, A a, B b, C c) {
+    wq->schedule(dn, make_work(f, a, b, c));
+}
+
+template <class WQ, class F, class A, class B, class C, class D>
+void defer(WQ wq, duration dn, F f, A a, B b, C c, D d) {
+    wq->schedule(dn, make_work(f, a, b, c, d));
+}
+
 /// This version of proton::defer defers calling a free function to an arbitrary work queue
 #else
 // The C++11 version is *much* simpler and even so more general!
@@ -326,6 +352,11 @@ bool defer(WQ wq, Rest&&... r) {
     return wq->add(std::bind(std::forward<Rest>(r)...));
 }
 
+template <class WQ, class... Rest>
+void defer(WQ wq, duration d, Rest&&... r) {
+    wq->schedule(d, std::bind(std::forward<Rest>(r)...));
+}
+
 template <class... Rest>
 work make_work(Rest&&... r) {
     return std::bind(std::forward<Rest>(r)...);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[14/20] qpid-proton git commit: PROTON-1481: [C++ binding] simplify work_queue code by introducing work type - The work type can be created from std::function or void_function0 - and so pushes those c++11/C++03 differences into a single place

Posted by as...@apache.org.
PROTON-1481: [C++ binding] simplify work_queue code by introducing work type
- The work type can be created from std::function<void()> or void_function0
- and so pushes those c++11/C++03 differences into a single place


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/5dd3f464
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/5dd3f464
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/5dd3f464

Branch: refs/heads/master
Commit: 5dd3f464fbe472de49c0341a853098eba8059a14
Parents: d1c91a4
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon May 15 01:36:52 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         |   8 +-
 .../bindings/cpp/include/proton/container.hpp   |  14 +--
 proton-c/bindings/cpp/include/proton/fwd.hpp    |   4 +-
 .../bindings/cpp/include/proton/work_queue.hpp  |  52 +++++++---
 proton-c/bindings/cpp/src/container.cpp         |   6 +-
 .../cpp/src/include/proactor_container_impl.hpp |  12 +--
 .../src/include/proactor_work_queue_impl.hpp    |   6 +-
 .../cpp/src/proactor_container_impl.cpp         | 103 ++++---------------
 proton-c/bindings/cpp/src/work_queue.cpp        |  10 +-
 9 files changed, 77 insertions(+), 138 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index d39314c..9af60ba 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -185,7 +185,7 @@ public:
         sender_(s), senders_(ss), work_queue_(s.work_queue()), queue_(0), pending_credit_(0)
     {}
 
-    void add(proton::void_function0& f) {
+    void add(proton::work f) {
         work_queue_.add(f);
     }
 
@@ -241,7 +241,7 @@ public:
         work_queue_(c), name_(n), current_(subscriptions_.end())
     {}
 
-    void add(proton::void_function0& f) {
+    void add(proton::work f) {
         work_queue_.add(f);
     }
 
@@ -333,7 +333,7 @@ public:
         receiver_(r), work_queue_(r.work_queue()), queue_(0)
     {}
 
-    void add(proton::void_function0& f) {
+    void add(proton::work f) {
         work_queue_.add(f);
     }
 
@@ -361,7 +361,7 @@ public:
         container_(c), work_queue_(c), next_id_(0)
     {}
 
-    void add(proton::void_function0& f) {
+    void add(proton::work f) {
         work_queue_.add(f);
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index 383aa3c..0739517 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -206,15 +206,11 @@ class PN_CPP_CLASS_EXTERN container {
     /// @copydoc receiver_options
     PN_CPP_EXTERN class receiver_options receiver_options() const;
 
-    /// Schedule a function to be called after the duration.  C++03
-    /// compatible, for C++11 use schedule(duration,
-    /// std::function<void()>)
-    PN_CPP_EXTERN void schedule(duration, void_function0&);
-
-#if PN_CPP_HAS_STD_FUNCTION
-    /// Schedule a function to be called after the duration
-    PN_CPP_EXTERN void schedule(duration, std::function<void()>);
-#endif
+    /// Schedule a piece of work to happen after the duration:
+    /// The piece of work can be created from a function object.
+    /// for C++11 and on use a std::function<void()> type; for
+    /// C++03 compatibility you can use void_function0&
+    PN_CPP_EXTERN void schedule(duration, work);
 
   private:
     class impl;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/include/proton/fwd.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/fwd.hpp b/proton-c/bindings/cpp/include/proton/fwd.hpp
index 6ad216e..b839f42 100644
--- a/proton-c/bindings/cpp/include/proton/fwd.hpp
+++ b/proton-c/bindings/cpp/include/proton/fwd.hpp
@@ -31,7 +31,6 @@ class container;
 class delivery;
 class error_condition;
 class event;
-class work_queue;
 class message;
 class message_id;
 class messaging_handler;
@@ -54,7 +53,8 @@ class tracker;
 class transport;
 class url;
 class void_function0;
-
+class work;
+class work_queue;
 
 namespace io {
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index 7acd507..7c21710 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -23,6 +23,7 @@
  */
 
 #include "./fwd.hpp"
+#include "./function.hpp"
 #include "./internal/config.hpp"
 #include "./internal/export.hpp"
 #include "./internal/pn_unique_ptr.hpp"
@@ -35,12 +36,44 @@ struct pn_link_t;
 
 namespace proton {
 
-/// **Experimental** - A serial execution context.
+/// **Experimental** - A work queue for serial execution.
 ///
 /// Event handler functions associated with a single proton::connection are called in sequence.
-/// The connection's @ref event_loop allows you to "inject" extra work from any thread,
+/// The connection's @ref work_queue allows you to "inject" extra @ref work from any thread,
 /// and have it executed in the same sequence.
 ///
+/// You may also create arbitrary @ref work_queue objects backed by a @ref container that allow
+/// other objects to have their own serialised work queues that can have work injected safely
+/// from other threads. The @ref container ensures that the work is correctly serialised.
+///
+/// The @ref work class represents the work to be queued and can be created from a function
+/// that takes no parameters and returns no value.
+///
+
+class work {
+  public:
+#if PN_CPP_HAS_STD_FUNCTION
+    work(void_function0& f): item_( [&f]() { f(); }) {}
+    template <class T>
+    work(T f): item_(f) {}
+
+    void operator()() { item_(); }
+#else
+    work(void_function0& f): item_(&f) {}
+
+    void operator()() { (*item_)(); }
+#endif
+    ~work() {}
+
+
+  private:
+#if PN_CPP_HAS_STD_FUNCTION
+    std::function<void()> item_;
+#else
+    void_function0* item_;
+#endif
+};
+
 class PN_CPP_CLASS_EXTERN work_queue {
     /// @cond internal
     class impl;
@@ -48,14 +81,14 @@ class PN_CPP_CLASS_EXTERN work_queue {
     /// @endcond
 
   public:
-    /// Create event_loop
+    /// Create work_queue
     PN_CPP_EXTERN work_queue();
     PN_CPP_EXTERN work_queue(container&);
 
     PN_CPP_EXTERN ~work_queue();
 
 #if PN_CPP_HAS_EXPLICIT_CONVERSIONS
-    /// When using C++11 (or later) you can use event_loop in a bool context
+    /// When using C++11 (or later) you can use work_queue in a bool context
     /// to indicate if there is an event loop set.
     PN_CPP_EXTERN explicit operator bool() const { return bool(impl_); }
 #endif
@@ -63,17 +96,12 @@ class PN_CPP_CLASS_EXTERN work_queue {
     /// No event loop set.
     PN_CPP_EXTERN bool operator !() const { return !impl_; }
 
-    /// Arrange to have f() called in the event_loop's sequence: possibly
-    /// deferred, possibly in another thread.
+    /// Add work to the work queue: f() will be called serialised with other work in the queue:
+    /// deferred and possibly in another thread.
     ///
     /// @return true if f() has or will be called, false if the event_loop is ended
     /// and f() cannot be injected.
-    PN_CPP_EXTERN bool add(void_function0& f);
-
-#if PN_CPP_HAS_STD_FUNCTION
-    /// @copydoc inject(void_function0&)
-    PN_CPP_EXTERN bool add(std::function<void()> f);
-#endif
+    PN_CPP_EXTERN bool add(work f);
 
   private:
     PN_CPP_EXTERN static work_queue& get(pn_connection_t*);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/src/container.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/container.cpp b/proton-c/bindings/cpp/src/container.cpp
index b98da78..c2af659 100644
--- a/proton-c/bindings/cpp/src/container.cpp
+++ b/proton-c/bindings/cpp/src/container.cpp
@@ -103,11 +103,7 @@ returned<receiver> container::open_receiver(
 
 std::string container::id() const { return impl_->id(); }
 
-void container::schedule(duration d, void_function0& f) { return impl_->schedule(d, f); }
-
-#if PN_CPP_HAS_STD_FUNCTION
-void container::schedule(duration d, std::function<void()> f) { return impl_->schedule(d, f); }
-#endif
+void container::schedule(duration d, work f) { return impl_->schedule(d, f); }
 
 void container::client_connection_options(const connection_options& c) { impl_->client_connection_options(c); }
 connection_options container::client_connection_options() const { return impl_->client_connection_options(); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
index 9b4be11..fc963f7 100644
--- a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
@@ -73,10 +73,7 @@ class container::impl {
     void run();
     void stop(const error_condition& err);
     void auto_stop(bool set);
-    void schedule(duration, void_function0&);
-#if PN_CPP_HAS_STD_FUNCTION
-    void schedule(duration, std::function<void()>);
-#endif
+    void schedule(duration, work);
     template <class T> static void set_handler(T s, messaging_handler* h);
     template <class T> static messaging_handler* get_handler(T s);
     static work_queue::impl* make_work_queue(container&);
@@ -101,12 +98,7 @@ class container::impl {
     void remove_work_queue(container_work_queue*);
     struct scheduled {
         timestamp time; // duration from epoch for task
-#if PN_CPP_HAS_STD_FUNCTION
-        std::function<void()>  task;
-#else
-        void_function0* task_;
-        void task();
-#endif
+        work task;
 
         // We want to get to get the *earliest* first so test is "reversed"
         bool operator < (const scheduled& r) const { return  r.time < time; }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
index 57fc4c0..ac0f803 100644
--- a/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
@@ -24,16 +24,14 @@
 
 #include "proton/fwd.hpp"
 #include "proton/internal/config.hpp"
+#include "proton/work_queue.hpp"
 
 namespace proton {
 
 class work_queue::impl {
   public:
     virtual ~impl() {};
-    virtual bool inject(void_function0& f) = 0;
-#if PN_CPP_HAS_STD_FUNCTION
-    virtual bool inject(std::function<void()> f) = 0;
-#endif
+    virtual bool add(work f) = 0;
     virtual void run_all_jobs() = 0;
     virtual void finished() = 0;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index 78ccabf..0135c08 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -47,11 +47,7 @@ class container::impl::common_work_queue : public work_queue::impl {
   public:
     common_work_queue(): finished_(false) {}
 
-#if PN_CPP_HAS_STD_FUNCTION
-    typedef std::vector<std::function<void()> > jobs;
-#else
-    typedef std::vector<void_function0*> jobs;
-#endif
+    typedef std::vector<work> jobs;
 
     void run_all_jobs();
     void finished() { finished_ = true; }
@@ -60,100 +56,53 @@ class container::impl::common_work_queue : public work_queue::impl {
     bool finished_;
 };
 
-#if PN_CPP_HAS_STD_FUNCTION
-void container::impl::common_work_queue::run_all_jobs() {
-    decltype(jobs_) j;
-    {
-        std::swap(j, jobs_);
-    }
-    // Run queued work, but ignore any exceptions
-    for (auto& f : j) try {
-        f();
-    } catch (...) {};
-}
-#else
 void container::impl::common_work_queue::run_all_jobs() {
+    jobs j;
+    // Lock this operation for mt
+    std::swap(j, jobs_);
     // Run queued work, but ignore any exceptions
-    for (jobs::iterator f = jobs_.begin(); f != jobs_.end(); ++f) try {
-        (**f)();
+    for (jobs::iterator f = j.begin(); f != j.end(); ++f) try {
+        (*f)();
     } catch (...) {};
-    jobs_.clear();
     return;
 }
-#endif
 
 class container::impl::connection_work_queue : public common_work_queue {
   public:
     connection_work_queue(pn_connection_t* c): connection_(c) {}
 
-    bool inject(void_function0& f);
-#if PN_CPP_HAS_STD_FUNCTION
-    bool inject(std::function<void()> f);
-#endif
+    bool add(work f);
 
     pn_connection_t* connection_;
 };
 
-#if PN_CPP_HAS_STD_FUNCTION
-bool container::impl::connection_work_queue::inject(std::function<void()> f) {
-    // Note this is an unbounded work queue.
-    // A resource-safe implementation should be bounded.
-    if (finished_) return false;
-    jobs_.emplace_back(std::move(f));
-    pn_connection_wake(connection_);
-    return true;
-}
-
-bool container::impl::connection_work_queue::inject(proton::void_function0& f) {
-    return inject([&f]() { f(); });
-}
-#else
-bool container::impl::connection_work_queue::inject(proton::void_function0& f) {
+bool container::impl::connection_work_queue::add(work f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
     if (finished_) return false;
-    jobs_.push_back(&f);
+    jobs_.push_back(f);
     pn_connection_wake(connection_);
     return true;
 }
-#endif
 
 class container::impl::container_work_queue : public common_work_queue {
   public:
     container_work_queue(container::impl& c): container_(c) {}
     ~container_work_queue() { container_.remove_work_queue(this); }
 
-    bool inject(void_function0& f);
-#if PN_CPP_HAS_STD_FUNCTION
-    bool inject(std::function<void()> f);
-#endif
+    bool add(work f);
 
     container::impl& container_;
 };
 
-#if PN_CPP_HAS_STD_FUNCTION
-bool container::impl::container_work_queue::inject(std::function<void()> f) {
-    // Note this is an unbounded work queue.
-    // A resource-safe implementation should be bounded.
-    if (finished_) return false;
-    jobs_.emplace_back(std::move(f));
-    pn_proactor_set_timeout(container_.proactor_, 0);
-    return true;
-}
-
-bool container::impl::container_work_queue::inject(proton::void_function0& f) {
-    return inject([&f]() { f(); });
-}
-#else
-bool container::impl::container_work_queue::inject(proton::void_function0& f) {
+bool container::impl::container_work_queue::add(work f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
     if (finished_) return false;
-    jobs_.push_back(&f);
+    jobs_.push_back(f);
     pn_proactor_set_timeout(container_.proactor_, 0);
     return true;
 }
-#endif
 
 class work_queue::impl* container::impl::make_work_queue(container& c) {
     return c.impl_->add_work_queue();
@@ -277,32 +226,18 @@ proton::listener container::impl::listen(const std::string& addr, proton::listen
     return proton::listener(listener);
 }
 
-#if PN_CPP_HAS_STD_FUNCTION
-void container::impl::schedule(duration delay, void_function0& f) {
-    schedule(delay, [&f](){ f(); } );
-}
-
-void container::impl::schedule(duration delay, std::function<void()> f) {
-    // Set timeout
-    pn_proactor_set_timeout(proactor_, delay.milliseconds());
-
-    // Record timeout; Add callback to timeout sorted list
-    deferred_.emplace_back(scheduled{timestamp::now()+delay, f});
-    std::push_heap(deferred_.begin(), deferred_.end());
-}
-#else
-void container::impl::scheduled::task() {(*task_)();}
-
-void container::impl::schedule(duration delay, void_function0& f) {
-    // Set timeout
-    pn_proactor_set_timeout(proactor_, delay.milliseconds());
+void container::impl::schedule(duration delay, work f) {
+    timestamp now = timestamp::now();
 
     // Record timeout; Add callback to timeout sorted list
-    scheduled s = {timestamp::now()+delay, &f};
+    scheduled s = {now+delay, f};
     deferred_.push_back(s);
     std::push_heap(deferred_.begin(), deferred_.end());
+
+    // Set timeout for current head of timeout queue
+    scheduled* next = &deferred_.front();
+    pn_proactor_set_timeout(proactor_, (next->time-now).milliseconds());
 }
-#endif
 
 void container::impl::client_connection_options(const connection_options &opts) {
     client_connection_options_ = opts;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/5dd3f464/proton-c/bindings/cpp/src/work_queue.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/work_queue.cpp b/proton-c/bindings/cpp/src/work_queue.cpp
index 961e5f0..db95042 100644
--- a/proton-c/bindings/cpp/src/work_queue.cpp
+++ b/proton-c/bindings/cpp/src/work_queue.cpp
@@ -35,16 +35,10 @@ work_queue::~work_queue() {}
 
 work_queue& work_queue::operator=(impl* i) { impl_.reset(i); return *this; }
 
-bool work_queue::add(void_function0& f) {
-    return impl_->inject(f);
+bool work_queue::add(work f) {
+    return impl_->add(f);
 }
 
-#if PN_CPP_HAS_STD_FUNCTION
-bool work_queue::add(std::function<void()> f) {
-    return impl_->inject(f);
-}
-#endif
-
 work_queue& work_queue::get(pn_connection_t* c) {
     return connection_context::get(c).work_queue_;
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[04/20] qpid-proton git commit: PROTON-1400: [C++ binding] Change semantic for incoming xx_open - If not overridden then you get automatic outgoing matching xx_open - If overridden then it is assumed you will handle the outgoing open yourself.

Posted by as...@apache.org.
PROTON-1400: [C++ binding] Change semantic for incoming xx_open
- If not overridden then you get automatic outgoing matching xx_open
- If overridden then it is assumed you will handle the outgoing open
  yourself.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/ec2364f0
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/ec2364f0
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/ec2364f0

Branch: refs/heads/master
Commit: ec2364f0bb99937ff37165b7c7c4c74531f27633
Parents: 4eba80e
Author: Andrew Stitcher <as...@apache.org>
Authored: Fri Apr 14 02:13:12 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         |  3 ++
 examples/cpp/ssl.cpp                            |  3 ++
 examples/cpp/ssl_client_cert.cpp                |  3 ++
 .../bindings/cpp/src/connection_driver_test.cpp |  3 ++
 proton-c/bindings/cpp/src/handler.cpp           | 34 +++++++++++++++-----
 proton-c/bindings/cpp/src/messaging_adapter.cpp | 20 ------------
 6 files changed, 38 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec2364f0/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index e47a2a6..5b0982b 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -29,9 +29,11 @@
 #include <proton/listener.hpp>
 #include <proton/message.hpp>
 #include <proton/messaging_handler.hpp>
+#include <proton/receiver_options.hpp>
 #include <proton/sender_options.hpp>
 #include <proton/source_options.hpp>
 #include <proton/target.hpp>
+#include <proton/target_options.hpp>
 #include <proton/thread_safe.hpp>
 #include <proton/tracker.hpp>
 
@@ -180,6 +182,7 @@ class broker_connection_handler : public proton::messaging_handler {
             r.connection().container().stop(
                 proton::error_condition("shutdown", "stop broker"));
         } else {
+            r.open(proton::receiver_options().target(proton::target_options().address(qname)));
             std::cout << "receiving to " << qname << std::endl;
         }
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec2364f0/examples/cpp/ssl.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl.cpp b/examples/cpp/ssl.cpp
index 00bbccd..85dfa48 100644
--- a/examples/cpp/ssl.cpp
+++ b/examples/cpp/ssl.cpp
@@ -72,6 +72,9 @@ struct server_handler : public proton::messaging_handler {
         std::cout << "Inbound server connection connected via SSL.  Protocol: " <<
             c.transport().ssl().protocol() << std::endl;
         listener.stop();  // Just expecting the one connection.
+
+        // Go and do default inbound open stuff too
+        messaging_handler::on_connection_open(c);
     }
 
     void on_transport_error(proton::transport &t) OVERRIDE {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec2364f0/examples/cpp/ssl_client_cert.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl_client_cert.cpp b/examples/cpp/ssl_client_cert.cpp
index 630e74b..8ca2dc2 100644
--- a/examples/cpp/ssl_client_cert.cpp
+++ b/examples/cpp/ssl_client_cert.cpp
@@ -65,6 +65,9 @@ struct server_handler : public proton::messaging_handler {
             c.close();
         }
         listener.stop();
+
+        // Go and do default inbound open stuff too
+        messaging_handler::on_connection_open(c);
     }
 
     void on_message(proton::delivery &, proton::message &m) OVERRIDE {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec2364f0/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
index ae18ebe..db5bc90 100644
--- a/proton-c/bindings/cpp/src/connection_driver_test.cpp
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -131,14 +131,17 @@ struct record_handler : public messaging_handler {
     std::deque<proton::message> messages;
 
     void on_receiver_open(receiver &l) PN_CPP_OVERRIDE {
+        messaging_handler::on_receiver_open(l);
         receivers.push_back(l);
     }
 
     void on_sender_open(sender &l) PN_CPP_OVERRIDE {
+        messaging_handler::on_sender_open(l);
         senders.push_back(l);
     }
 
     void on_session_open(session &s) PN_CPP_OVERRIDE {
+        messaging_handler::on_session_open(s);
         sessions.push_back(s);
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec2364f0/proton-c/bindings/cpp/src/handler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/handler.cpp b/proton-c/bindings/cpp/src/handler.cpp
index 3137718..84d9e8a 100644
--- a/proton-c/bindings/cpp/src/handler.cpp
+++ b/proton-c/bindings/cpp/src/handler.cpp
@@ -21,17 +21,19 @@
 #include "proton/messaging_handler.hpp"
 
 #include "proton/connection.hpp"
+#include "proton/container.hpp"
 #include "proton/error_condition.hpp"
 #include "proton/receiver.hpp"
+#include "proton/receiver_options.hpp"
 #include "proton/sender.hpp"
+#include "proton/sender_options.hpp"
 #include "proton/session.hpp"
 #include "proton/transport.hpp"
 
-#include "messaging_adapter.hpp"
+#include "proton_bits.hpp"
 
-#include <proton/handlers.h>
-
-#include <algorithm>
+#include "proton/connection.h"
+#include "proton/session.h"
 
 namespace proton {
 
@@ -48,17 +50,33 @@ void messaging_handler::on_transport_error(transport &t) { on_error(t.error());
 void messaging_handler::on_transport_open(transport &) {}
 void messaging_handler::on_connection_close(connection &) {}
 void messaging_handler::on_connection_error(connection &c) { on_error(c.error()); }
-void messaging_handler::on_connection_open(connection &) {}
+void messaging_handler::on_connection_open(connection &c) {
+    if (c.uninitialized()) {
+        pn_connection_open(unwrap(c));
+    }
+}
 void messaging_handler::on_session_close(session &) {}
 void messaging_handler::on_session_error(session &s) { on_error(s.error()); }
-void messaging_handler::on_session_open(session &) {}
+void messaging_handler::on_session_open(session &s) {
+    if (s.uninitialized()) {
+        pn_session_open(unwrap(s));
+    }
+}
 void messaging_handler::on_receiver_close(receiver &) {}
 void messaging_handler::on_receiver_error(receiver &l) { on_error(l.error()); }
-void messaging_handler::on_receiver_open(receiver &) {}
+void messaging_handler::on_receiver_open(receiver &l) {
+    if (l.uninitialized()) {
+        l.open(l.connection().receiver_options());
+    }
+}
 void messaging_handler::on_receiver_detach(receiver &) {}
 void messaging_handler::on_sender_close(sender &) {}
 void messaging_handler::on_sender_error(sender &l) { on_error(l.error()); }
-void messaging_handler::on_sender_open(sender &) {}
+void messaging_handler::on_sender_open(sender &l) {
+    if (l.uninitialized()) {
+        l.open(l.connection().sender_options());
+    }
+}
 void messaging_handler::on_sender_detach(sender &) {}
 void messaging_handler::on_tracker_accept(tracker &) {}
 void messaging_handler::on_tracker_reject(tracker &) {}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ec2364f0/proton-c/bindings/cpp/src/messaging_adapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/messaging_adapter.cpp b/proton-c/bindings/cpp/src/messaging_adapter.cpp
index 521566c..cb1b776 100644
--- a/proton-c/bindings/cpp/src/messaging_adapter.cpp
+++ b/proton-c/bindings/cpp/src/messaging_adapter.cpp
@@ -176,14 +176,6 @@ void on_delivery(messaging_handler& handler, pn_event_t* event) {
     }
 }
 
-bool is_local_open(pn_state_t state) {
-    return state & PN_LOCAL_ACTIVE;
-}
-
-bool is_local_unititialised(pn_state_t state) {
-    return state & PN_LOCAL_UNINIT;
-}
-
 bool is_remote_unititialised(pn_state_t state) {
     return state & PN_REMOTE_UNINIT;
 }
@@ -256,18 +248,12 @@ void on_connection_remote_open(messaging_handler& handler, pn_event_t* event) {
     pn_connection_t *conn = pn_event_connection(event);
     connection c(make_wrapper(conn));
     handler.on_connection_open(c);
-    if (!is_local_open(pn_connection_state(conn)) && is_local_unititialised(pn_connection_state(conn))) {
-        pn_connection_open(conn);
-    }
 }
 
 void on_session_remote_open(messaging_handler& handler, pn_event_t* event) {
     pn_session_t *session = pn_event_session(event);
     class session s(make_wrapper(session));
     handler.on_session_open(s);
-    if (!is_local_open(pn_session_state(session)) && is_local_unititialised(pn_session_state(session))) {
-        pn_session_open(session);
-    }
 }
 
 void on_link_local_open(messaging_handler& handler, pn_event_t* event) {
@@ -286,16 +272,10 @@ void on_link_remote_open(messaging_handler& handler, pn_event_t* event) {
     if (pn_link_is_receiver(lnk)) {
       receiver r(make_wrapper<receiver>(lnk));
       handler.on_receiver_open(r);
-      if (is_local_unititialised(pn_link_state(lnk))) {
-          r.open(r.connection().receiver_options());
-      }
       credit_topup(lnk);
     } else {
       sender s(make_wrapper<sender>(lnk));
       handler.on_sender_open(s);
-      if (is_local_unititialised(pn_link_state(lnk))) {
-          s.open(s.connection().sender_options());
-      }
     }
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[07/20] qpid-proton git commit: PROTON-1400: [C++ binding] Removed proton_event and proton_handler - Removed old low level proton event handling completely - Now directly dispatch to the messaging_handler - Moved private message::decode directly into mes

Posted by as...@apache.org.
PROTON-1400: [C++ binding] Removed proton_event and proton_handler
- Removed old low level proton event handling completely
- Now directly dispatch to the messaging_handler
- Moved private message::decode directly into message handling code


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/1a513d64
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/1a513d64
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/1a513d64

Branch: refs/heads/master
Commit: 1a513d64f6f884c228e8a0a5b691c96949b3d1f4
Parents: 9c1797c
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon Jan 23 12:32:50 2017 -0500
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 proton-c/bindings/cpp/CMakeLists.txt            |   2 -
 .../bindings/cpp/include/proton/message.hpp     |   4 -
 proton-c/bindings/cpp/src/handler.cpp           |   1 -
 proton-c/bindings/cpp/src/include/contexts.hpp  |   2 -
 .../cpp/src/include/messaging_adapter.hpp       |  30 +-
 .../cpp/src/include/proactor_container_impl.hpp |   1 -
 .../bindings/cpp/src/include/proton_event.hpp   | 286 -------------------
 .../bindings/cpp/src/include/proton_handler.hpp |  92 ------
 .../bindings/cpp/src/io/connection_driver.cpp   |   5 +-
 proton-c/bindings/cpp/src/message.cpp           |  14 -
 proton-c/bindings/cpp/src/messaging_adapter.cpp | 208 ++++++++------
 .../cpp/src/proactor_container_impl.cpp         |   6 +-
 proton-c/bindings/cpp/src/proton_event.cpp      |  88 ------
 proton-c/bindings/cpp/src/proton_handler.cpp    |  74 -----
 14 files changed, 131 insertions(+), 682 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index 295a99e..625206f 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -55,8 +55,6 @@ set(qpid-proton-cpp-source
   src/node_options.cpp
   src/object.cpp
   src/proton_bits.cpp
-  src/proton_event.cpp
-  src/proton_handler.cpp
   src/receiver.cpp
   src/receiver_options.cpp
   src/reconnect_timer.cpp

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index a25f7db..a428c46 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -319,11 +319,7 @@ class message {
 
     mutable pn_message_t *pn_msg_;
 
-    /// Decode the message corresponding to a delivery from a link.
-    void decode(proton::delivery);
-
   PN_CPP_EXTERN friend void swap(message&, message&);
-  friend class messaging_adapter;
     /// @endcond
 };
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/handler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/handler.cpp b/proton-c/bindings/cpp/src/handler.cpp
index 5cf6208..3137718 100644
--- a/proton-c/bindings/cpp/src/handler.cpp
+++ b/proton-c/bindings/cpp/src/handler.cpp
@@ -27,7 +27,6 @@
 #include "proton/session.hpp"
 #include "proton/transport.hpp"
 
-#include "proton_event.hpp"
 #include "messaging_adapter.hpp"
 
 #include <proton/handlers.h>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/include/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp
index c096a6e..637cbec 100644
--- a/proton-c/bindings/cpp/src/include/contexts.hpp
+++ b/proton-c/bindings/cpp/src/include/contexts.hpp
@@ -32,8 +32,6 @@
 
 #include "proton/io/link_namer.hpp"
 
-#include "proton_handler.hpp"
-
 struct pn_record_t;
 struct pn_link_t;
 struct pn_session_t;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/messaging_adapter.hpp b/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
index d7eb6a0..10c7682 100644
--- a/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
+++ b/proton-c/bindings/cpp/src/include/messaging_adapter.hpp
@@ -22,37 +22,19 @@
  *
  */
 
-#include "proton/messaging_handler.hpp"
-
-#include "proton_handler.hpp"
-
-#include <proton/event.h>
-#include <proton/reactor.h>
-
 ///@cond INTERNAL
 
+struct pn_event_t;
+
 namespace proton {
 
+class messaging_handler;
+
 /// Convert the low level proton-c events to the higher level proton::messaging_handler calls
-class messaging_adapter : public proton_handler
+class messaging_adapter
 {
   public:
-    messaging_adapter(messaging_handler &delegate) : delegate_(delegate) {}
-
-    void on_link_flow(proton_event &e);
-    void on_delivery(proton_event &e);
-    void on_connection_remote_open(proton_event &e);
-    void on_connection_remote_close(proton_event &e);
-    void on_session_remote_open(proton_event &e);
-    void on_session_remote_close(proton_event &e);
-    void on_link_local_open(proton_event &e);
-    void on_link_remote_open(proton_event &e);
-    void on_link_remote_detach(proton_event & e);
-    void on_link_remote_close(proton_event &e);
-    void on_transport_closed(proton_event &e);
-
-  private:
-    messaging_handler &delegate_;  // The handler for generated messaging_event's
+    static void dispatch(messaging_handler& delegate, pn_event_t* e);
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
index 8c12c02..859493d 100644
--- a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
@@ -35,7 +35,6 @@
 #include "proton/sender_options.hpp"
 
 #include "proton_bits.hpp"
-#include "proton_handler.hpp"
 
 #include <list>
 #include <map>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/include/proton_event.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_event.hpp b/proton-c/bindings/cpp/src/include/proton_event.hpp
deleted file mode 100644
index be324e7..0000000
--- a/proton-c/bindings/cpp/src/include/proton_event.hpp
+++ /dev/null
@@ -1,286 +0,0 @@
-#ifndef PROTON_CPP_PROTONEVENT_H
-#define PROTON_CPP_PROTONEVENT_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/fwd.hpp"
-#include "proton/error.hpp"
-
-#include <proton/event.h>
-
-namespace proton {
-
-class proton_handler;
-
-/** Event information for a proton::proton_handler */
-class proton_event
-{
-  public:
-    /// The type of an event
-    enum event_type {
-    ///@name Event types
-    ///@{
-
-      /**
-      * Defined as a programming convenience. No event of this type will
-      * ever be generated.
-      */
-      EVENT_NONE=PN_EVENT_NONE,
-
-      /**
-      * A reactor has been started. Events of this type point to the reactor.
-      */
-      REACTOR_INIT=PN_REACTOR_INIT,
-
-      /**
-      * A reactor has no more events to process. Events of this type
-      * point to the reactor.
-      */
-      REACTOR_QUIESCED=PN_REACTOR_QUIESCED,
-
-      /**
-      * A reactor has been stopped. Events of this type point to the reactor.
-      */
-      REACTOR_FINAL=PN_REACTOR_FINAL,
-
-      /**
-      * A timer event has occurred.
-      */
-      TIMER_TASK=PN_TIMER_TASK,
-
-      /**
-      * The connection has been created. This is the first event that
-      * will ever be issued for a connection. Events of this type point
-      * to the relevant connection.
-      */
-      CONNECTION_INIT=PN_CONNECTION_INIT,
-
-      /**
-      * The connection has been bound to a transport. This event is
-      * issued when the transport::bind() is called.
-      */
-      CONNECTION_BOUND=PN_CONNECTION_BOUND,
-
-      /**
-      * The connection has been unbound from its transport. This event is
-      * issued when transport::unbind() is called.
-      */
-      CONNECTION_UNBOUND=PN_CONNECTION_UNBOUND,
-
-      /**
-      * The local connection endpoint has been closed. Events of this
-      * type point to the relevant connection.
-      */
-      CONNECTION_LOCAL_OPEN=PN_CONNECTION_LOCAL_OPEN,
-
-      /**
-      * The remote endpoint has opened the connection. Events of this
-      * type point to the relevant connection.
-      */
-      CONNECTION_REMOTE_OPEN=PN_CONNECTION_REMOTE_OPEN,
-
-      /**
-      * The local connection endpoint has been closed. Events of this
-      * type point to the relevant connection.
-      */
-      CONNECTION_LOCAL_CLOSE=PN_CONNECTION_LOCAL_CLOSE,
-
-      /**
-      *  The remote endpoint has closed the connection. Events of this
-      *  type point to the relevant connection.
-      */
-      CONNECTION_REMOTE_CLOSE=PN_CONNECTION_REMOTE_CLOSE,
-
-      /**
-      * The connection has been freed and any outstanding processing has
-      * been completed. This is the final event that will ever be issued
-      * for a connection.
-      */
-      CONNECTION_FINAL=PN_CONNECTION_FINAL,
-
-      /**
-      * The session has been created. This is the first event that will
-      * ever be issued for a session.
-      */
-      SESSION_INIT=PN_SESSION_INIT,
-
-      /**
-      * The local session endpoint has been opened. Events of this type
-      * point to the relevant session.
-      */
-      SESSION_LOCAL_OPEN=PN_SESSION_LOCAL_OPEN,
-
-      /**
-      * The remote endpoint has opened the session. Events of this type
-      * point to the relevant session.
-      */
-      SESSION_REMOTE_OPEN=PN_SESSION_REMOTE_OPEN,
-
-      /**
-      * The local session endpoint has been closed. Events of this type
-      * point ot the relevant session.
-      */
-      SESSION_LOCAL_CLOSE=PN_SESSION_LOCAL_CLOSE,
-
-      /**
-      * The remote endpoint has closed the session. Events of this type
-      * point to the relevant session.
-      */
-      SESSION_REMOTE_CLOSE=PN_SESSION_REMOTE_CLOSE,
-
-      /**
-      * The session has been freed and any outstanding processing has
-      * been completed. This is the final event that will ever be issued
-      * for a session.
-      */
-      SESSION_FINAL=PN_SESSION_FINAL,
-
-      /**
-      * The link has been created. This is the first event that will ever
-      * be issued for a link.
-      */
-      LINK_INIT=PN_LINK_INIT,
-
-      /**
-      * The local link endpoint has been opened. Events of this type
-      * point ot the relevant link.
-      */
-      LINK_LOCAL_OPEN=PN_LINK_LOCAL_OPEN,
-
-      /**
-      * The remote endpoint has opened the link. Events of this type
-      * point to the relevant link.
-      */
-      LINK_REMOTE_OPEN=PN_LINK_REMOTE_OPEN,
-
-      /**
-      * The local link endpoint has been closed. Events of this type
-      * point ot the relevant link.
-      */
-      LINK_LOCAL_CLOSE=PN_LINK_LOCAL_CLOSE,
-
-      /**
-      * The remote endpoint has closed the link. Events of this type
-      * point to the relevant link.
-      */
-      LINK_REMOTE_CLOSE=PN_LINK_REMOTE_CLOSE,
-
-      /**
-      * The local link endpoint has been detached. Events of this type
-      * point to the relevant link.
-      */
-      LINK_LOCAL_DETACH=PN_LINK_LOCAL_DETACH,
-
-      /**
-      * The remote endpoint has detached the link. Events of this type
-      * point to the relevant link.
-      */
-      LINK_REMOTE_DETACH=PN_LINK_REMOTE_DETACH,
-
-      /**
-      * The flow control state for a link has changed. Events of this
-      * type point to the relevant link.
-      */
-      LINK_FLOW=PN_LINK_FLOW,
-
-      /**
-      * The link has been freed and any outstanding processing has been
-      * completed. This is the final event that will ever be issued for a
-      * link. Events of this type point to the relevant link.
-      */
-      LINK_FINAL=PN_LINK_FINAL,
-
-      /**
-      * A delivery has been created or updated. Events of this type point
-      * to the relevant delivery.
-      */
-      DELIVERY=PN_DELIVERY,
-
-      /**
-      * The transport has new data to read and/or write. Events of this
-      * type point to the relevant transport.
-      */
-      TRANSPORT=PN_TRANSPORT,
-
-      /**
-      * The transport has authenticated, if this is received by a server
-      * the associated transport has authenticated an incoming connection
-      * and transport::user() can be used to obtain the authenticated
-      * user.
-      */
-      TRANSPORT_AUTHENTICATED=PN_TRANSPORT_AUTHENTICATED,
-
-      /**
-      * Indicates that a transport error has occurred. Use
-      * transport::condition() to access the details of the error
-      * from the associated transport.
-      */
-      TRANSPORT_ERROR=PN_TRANSPORT_ERROR,
-
-      /**
-      * Indicates that the head of the transport has been closed. This
-      * means the transport will never produce more bytes for output to
-      * the network. Events of this type point to the relevant transport.
-      */
-      TRANSPORT_HEAD_CLOSED=PN_TRANSPORT_HEAD_CLOSED,
-
-      /**
-      * Indicates that the tail of the transport has been closed. This
-      * means the transport will never be able to process more bytes from
-      * the network. Events of this type point to the relevant transport.
-      */
-      TRANSPORT_TAIL_CLOSED=PN_TRANSPORT_TAIL_CLOSED,
-
-      /**
-      * Indicates that the both the head and tail of the transport are
-      * closed. Events of this type point to the relevant transport.
-      */
-      TRANSPORT_CLOSED=PN_TRANSPORT_CLOSED,
-
-      SELECTABLE_INIT=PN_SELECTABLE_INIT,
-      SELECTABLE_UPDATED=PN_SELECTABLE_UPDATED,
-      SELECTABLE_READABLE=PN_SELECTABLE_READABLE,
-      SELECTABLE_WRITABLE=PN_SELECTABLE_WRITABLE,
-      SELECTABLE_ERROR=PN_SELECTABLE_ERROR,
-      SELECTABLE_EXPIRED=PN_SELECTABLE_EXPIRED,
-      SELECTABLE_FINAL=PN_SELECTABLE_FINAL
-    };
-    ///@}
-
-    proton_event(pn_event_t *ce) :
-      pn_event_(ce)
-    {}
-
-    pn_event_t* pn_event() const { return pn_event_; }
-
-    /// Get type of event
-    event_type type() const { return event_type(pn_event_type(pn_event_)); }
-
-    void dispatch(proton_handler& h);
-
-  private:
-    pn_event_t *pn_event_;
-};
-
-}
-
-#endif  /*!PROTON_CPP_PROTONEVENT_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/include/proton_handler.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_handler.hpp b/proton-c/bindings/cpp/src/include/proton_handler.hpp
deleted file mode 100644
index 9941396..0000000
--- a/proton-c/bindings/cpp/src/include/proton_handler.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef PROTON_CPP_PROTONHANDLER_H
-#define PROTON_CPP_PROTONHANDLER_H
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/internal/object.hpp"
-
-#include <vector>
-
-struct pn_handler_t;
-
-namespace proton {
-
-class event;
-class proton_event;
-
-/// Handler base class, subclass and over-ride event handling member functions.
-/// @see proton::proton_event for meaning of events.
-class proton_handler
-{
-  public:
-    proton_handler();
-    virtual ~proton_handler();
-
-    ///@name Over-ride these member functions to handle events
-    ///@{
-    virtual void on_reactor_init(proton_event &e);
-    virtual void on_reactor_quiesced(proton_event &e);
-    virtual void on_reactor_final(proton_event &e);
-    virtual void on_timer_task(proton_event &e);
-    virtual void on_connection_init(proton_event &e);
-    virtual void on_connection_bound(proton_event &e);
-    virtual void on_connection_unbound(proton_event &e);
-    virtual void on_connection_local_open(proton_event &e);
-    virtual void on_connection_local_close(proton_event &e);
-    virtual void on_connection_remote_open(proton_event &e);
-    virtual void on_connection_remote_close(proton_event &e);
-    virtual void on_connection_final(proton_event &e);
-    virtual void on_session_init(proton_event &e);
-    virtual void on_session_local_open(proton_event &e);
-    virtual void on_session_local_close(proton_event &e);
-    virtual void on_session_remote_open(proton_event &e);
-    virtual void on_session_remote_close(proton_event &e);
-    virtual void on_session_final(proton_event &e);
-    virtual void on_link_init(proton_event &e);
-    virtual void on_link_local_open(proton_event &e);
-    virtual void on_link_local_close(proton_event &e);
-    virtual void on_link_local_detach(proton_event &e);
-    virtual void on_link_remote_open(proton_event &e);
-    virtual void on_link_remote_close(proton_event &e);
-    virtual void on_link_remote_detach(proton_event &e);
-    virtual void on_link_flow(proton_event &e);
-    virtual void on_link_final(proton_event &e);
-    virtual void on_delivery(proton_event &e);
-    virtual void on_transport(proton_event &e);
-    virtual void on_transport_error(proton_event &e);
-    virtual void on_transport_head_closed(proton_event &e);
-    virtual void on_transport_tail_closed(proton_event &e);
-    virtual void on_transport_closed(proton_event &e);
-    virtual void on_selectable_init(proton_event &e);
-    virtual void on_selectable_updated(proton_event &e);
-    virtual void on_selectable_readable(proton_event &e);
-    virtual void on_selectable_writable(proton_event &e);
-    virtual void on_selectable_expired(proton_event &e);
-    virtual void on_selectable_error(proton_event &e);
-    virtual void on_selectable_final(proton_event &e);
-    virtual void on_unhandled(proton_event &e);
-    ///@}
-};
-
-}
-
-#endif  /*!PROTON_CPP_PROTONHANDLER_H*/

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/io/connection_driver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp
index d7c5e5c..0f5bc33 100644
--- a/proton-c/bindings/cpp/src/io/connection_driver.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -28,7 +28,6 @@
 #include "messaging_adapter.hpp"
 #include "msg.hpp"
 #include "proton_bits.hpp"
-#include "proton_event.hpp"
 
 #include <proton/connection.h>
 #include <proton/transport.h>
@@ -88,11 +87,9 @@ bool connection_driver::has_events() const {
 bool connection_driver::dispatch() {
     pn_event_t* c_event;
     while ((c_event = pn_connection_driver_next_event(&driver_)) != NULL) {
-        proton_event cpp_event(c_event);
         try {
             if (handler_ != 0) {
-                messaging_adapter adapter(*handler_);
-                cpp_event.dispatch(adapter);
+                messaging_adapter::dispatch(*handler_, c_event);
             }
         } catch (const std::exception& e) {
             pn_condition_t *cond = pn_transport_condition(driver_.transport);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index d121cc8..1fbdf70 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -300,20 +300,6 @@ void message::decode(const std::vector<char> &s) {
     check(pn_message_decode(pn_msg(), &s[0], s.size()));
 }
 
-void message::decode(proton::delivery delivery) {
-    std::vector<char> buf;
-    buf.resize(pn_delivery_pending(unwrap(delivery)));
-    if (buf.empty())
-        throw error("message decode: no delivery pending on link");
-    proton::receiver link = delivery.receiver();
-    assert(!buf.empty());
-    ssize_t n = pn_link_recv(unwrap(link), const_cast<char *>(&buf[0]), buf.size());
-    if (n != ssize_t(buf.size())) throw error(MSG("receiver read failure"));
-    clear();
-    decode(buf);
-    pn_link_advance(unwrap(link));
-}
-
 bool message::durable() const { return pn_message_is_durable(pn_msg()); }
 void message::durable(bool b) { pn_message_set_durable(pn_msg(), b); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/messaging_adapter.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/messaging_adapter.cpp b/proton-c/bindings/cpp/src/messaging_adapter.cpp
index 613808b..3a16930 100644
--- a/proton-c/bindings/cpp/src/messaging_adapter.cpp
+++ b/proton-c/bindings/cpp/src/messaging_adapter.cpp
@@ -23,6 +23,7 @@
 
 #include "proton/delivery.hpp"
 #include "proton/error.hpp"
+#include "proton/messaging_handler.hpp"
 #include "proton/receiver_options.hpp"
 #include "proton/sender.hpp"
 #include "proton/sender_options.hpp"
@@ -32,7 +33,6 @@
 #include "contexts.hpp"
 #include "msg.hpp"
 #include "proton_bits.hpp"
-#include "proton_event.hpp"
 
 #include <proton/connection.h>
 #include <proton/delivery.h>
@@ -42,62 +42,71 @@
 #include <proton/session.h>
 #include <proton/transport.h>
 
+#include <assert.h>
 #include <string.h>
 
 namespace proton {
 
 namespace {
+// This must only be called for receiver links
 void credit_topup(pn_link_t *link) {
-    if (link && pn_link_is_receiver(link)) {
-        int window = link_context::get(link).credit_window;
-        if (window) {
-            int delta = window - pn_link_credit(link);
-            pn_link_flow(link, delta);
-        }
+    assert(pn_link_is_receiver(link));
+    int window = link_context::get(link).credit_window;
+    if (window) {
+        int delta = window - pn_link_credit(link);
+        pn_link_flow(link, delta);
     }
 }
-}
 
-void messaging_adapter::on_link_flow(proton_event &pe) {
-    pn_event_t *pne = pe.pn_event();
-    pn_link_t *lnk = pn_event_link(pne);
+
+void on_link_flow(messaging_handler& handler, pn_event_t* event) {
+    pn_link_t *lnk = pn_event_link(event);
     // TODO: process session flow data, if no link-specific data, just return.
     if (!lnk) return;
-    link_context& lctx = link_context::get(lnk);
     int state = pn_link_state(lnk);
     if ((state&PN_LOCAL_ACTIVE) && (state&PN_REMOTE_ACTIVE)) {
+        link_context& lctx = link_context::get(lnk);
         if (pn_link_is_sender(lnk)) {
             if (pn_link_credit(lnk) > 0) {
                 sender s(make_wrapper<sender>(lnk));
-                if (pn_link_get_drain(lnk)) {
-                    if (!lctx.draining) {
-                        lctx.draining = true;
-                        delegate_.on_sender_drain_start(s);
-                    }
-                }
-                else {
-                    lctx.draining = false;
+                bool draining = pn_link_get_drain(lnk);
+                if ( draining && !lctx.draining) {
+                    handler.on_sender_drain_start(s);
                 }
+                lctx.draining = draining;
                 // create on_message extended event
-                delegate_.on_sendable(s);
+                handler.on_sendable(s);
             }
-        }
-        else {
+        } else {
             // receiver
             if (!pn_link_credit(lnk) && lctx.draining) {
                 lctx.draining = false;
                 receiver r(make_wrapper<receiver>(lnk));
-                delegate_.on_receiver_drain_finish(r);
+                handler.on_receiver_drain_finish(r);
             }
+            credit_topup(lnk);
         }
     }
-    credit_topup(lnk);
 }
 
-void messaging_adapter::on_delivery(proton_event &pe) {
-    pn_event_t *cevent = pe.pn_event();
-    pn_link_t *lnk = pn_event_link(cevent);
-    pn_delivery_t *dlv = pn_event_delivery(cevent);
+// Decode the message corresponding to a delivery from a link.
+void message_decode(message& msg, proton::delivery delivery) {
+    std::vector<char> buf;
+    buf.resize(pn_delivery_pending(unwrap(delivery)));
+    if (buf.empty())
+        throw error("message decode: no delivery pending on link");
+    proton::receiver link = delivery.receiver();
+    assert(!buf.empty());
+    ssize_t n = pn_link_recv(unwrap(link), const_cast<char *>(&buf[0]), buf.size());
+    if (n != ssize_t(buf.size())) throw error(MSG("receiver read failure"));
+    msg.clear();
+    msg.decode(buf);
+    pn_link_advance(unwrap(link));
+}
+
+void on_delivery(messaging_handler& handler, pn_event_t* event) {
+    pn_link_t *lnk = pn_event_link(event);
+    pn_delivery_t *dlv = pn_event_delivery(event);
     link_context& lctx = link_context::get(lnk);
 
     if (pn_link_is_receiver(lnk)) {
@@ -110,29 +119,29 @@ void messaging_adapter::on_delivery(proton_event &pe) {
             // Avoid expensive heap malloc/free overhead.
             // See PROTON-998
             class message &msg(ctx.event_message);
-            msg.decode(d);
+            message_decode(msg, d);
             if (pn_link_state(lnk) & PN_LOCAL_CLOSED) {
                 if (lctx.auto_accept)
                     d.release();
             } else {
-                delegate_.on_message(d, msg);
+                handler.on_message(d, msg);
                 if (lctx.auto_accept && !d.settled())
                     d.accept();
                 if (lctx.draining && !pn_link_credit(lnk)) {
                     lctx.draining = false;
                     receiver r(make_wrapper<receiver>(lnk));
-                    delegate_.on_receiver_drain_finish(r);
+                    handler.on_receiver_drain_finish(r);
                 }
             }
         }
         else if (pn_delivery_updated(dlv) && d.settled()) {
-            delegate_.on_delivery_settle(d);
+            handler.on_delivery_settle(d);
         }
         if (lctx.draining && pn_link_credit(lnk) == 0) {
             lctx.draining = false;
             pn_link_set_drain(lnk, false);
             receiver r(make_wrapper<receiver>(lnk));
-            delegate_.on_receiver_drain_finish(r);
+            handler.on_receiver_drain_finish(r);
             if (lctx.pending_credit) {
                 pn_link_flow(lnk, lctx.pending_credit);
                 lctx.pending_credit = 0;
@@ -145,17 +154,17 @@ void messaging_adapter::on_delivery(proton_event &pe) {
         if (pn_delivery_updated(dlv)) {
             uint64_t rstate = pn_delivery_remote_state(dlv);
             if (rstate == PN_ACCEPTED) {
-                delegate_.on_tracker_accept(t);
+                handler.on_tracker_accept(t);
             }
             else if (rstate == PN_REJECTED) {
-                delegate_.on_tracker_reject(t);
+                handler.on_tracker_reject(t);
             }
             else if (rstate == PN_RELEASED || rstate == PN_MODIFIED) {
-                delegate_.on_tracker_release(t);
+                handler.on_tracker_release(t);
             }
 
             if (t.settled()) {
-                delegate_.on_tracker_settle(t);
+                handler.on_tracker_settle(t);
             }
             if (lctx.auto_settle)
                 t.settle();
@@ -163,8 +172,6 @@ void messaging_adapter::on_delivery(proton_event &pe) {
     }
 }
 
-namespace {
-
 bool is_local_open(pn_state_t state) {
     return state & PN_LOCAL_ACTIVE;
 }
@@ -177,54 +184,48 @@ bool is_remote_unititialised(pn_state_t state) {
     return state & PN_REMOTE_UNINIT;
 }
 
-} // namespace
-
-void messaging_adapter::on_link_remote_detach(proton_event & pe) {
-    pn_event_t *cevent = pe.pn_event();
-    pn_link_t *lnk = pn_event_link(cevent);
+void on_link_remote_detach(messaging_handler& handler, pn_event_t* event) {
+    pn_link_t *lnk = pn_event_link(event);
     if (pn_link_is_receiver(lnk)) {
         receiver r(make_wrapper<receiver>(lnk));
-        delegate_.on_receiver_detach(r);
+        handler.on_receiver_detach(r);
     } else {
         sender s(make_wrapper<sender>(lnk));
-        delegate_.on_sender_detach(s);
+        handler.on_sender_detach(s);
     }
     pn_link_detach(lnk);
 }
 
-void messaging_adapter::on_link_remote_close(proton_event &pe) {
-    pn_event_t *cevent = pe.pn_event();
-    pn_link_t *lnk = pn_event_link(cevent);
+void on_link_remote_close(messaging_handler& handler, pn_event_t* event) {
+    pn_link_t *lnk = pn_event_link(event);
     if (pn_link_is_receiver(lnk)) {
         receiver r(make_wrapper<receiver>(lnk));
         if (pn_condition_is_set(pn_link_remote_condition(lnk))) {
-            delegate_.on_receiver_error(r);
+            handler.on_receiver_error(r);
         }
-        delegate_.on_receiver_close(r);
+        handler.on_receiver_close(r);
     } else {
         sender s(make_wrapper<sender>(lnk));
         if (pn_condition_is_set(pn_link_remote_condition(lnk))) {
-            delegate_.on_sender_error(s);
+            handler.on_sender_error(s);
         }
-        delegate_.on_sender_close(s);
+        handler.on_sender_close(s);
     }
     pn_link_close(lnk);
 }
 
-void messaging_adapter::on_session_remote_close(proton_event &pe) {
-    pn_event_t *cevent = pe.pn_event();
-    pn_session_t *session = pn_event_session(cevent);
+void on_session_remote_close(messaging_handler& handler, pn_event_t* event) {
+    pn_session_t *session = pn_event_session(event);
     class session s(make_wrapper(session));
     if (pn_condition_is_set(pn_session_remote_condition(session))) {
-        delegate_.on_session_error(s);
+        handler.on_session_error(s);
     }
-    delegate_.on_session_close(s);
+    handler.on_session_close(s);
     pn_session_close(session);
 }
 
-void messaging_adapter::on_connection_remote_close(proton_event &pe) {
-    pn_event_t *cevent = pe.pn_event();
-    pn_connection_t *conn = pn_event_connection(cevent);
+void on_connection_remote_close(messaging_handler& handler, pn_event_t* event) {
+    pn_connection_t *conn = pn_event_connection(event);
     pn_condition_t *cond = pn_connection_remote_condition(conn);
 
     // If we got a close with a condition of amqp:connection:forced then treat this
@@ -237,71 +238,108 @@ void messaging_adapter::on_connection_remote_close(proton_event &pe) {
 
     connection c(make_wrapper(conn));
     if (pn_condition_is_set(cond)) {
-        delegate_.on_connection_error(c);
+        handler.on_connection_error(c);
     }
-    delegate_.on_connection_close(c);
+    handler.on_connection_close(c);
     pn_connection_close(conn);
 }
 
-void messaging_adapter::on_connection_remote_open(proton_event &pe) {
+void on_connection_remote_open(messaging_handler& handler, pn_event_t* event) {
     // Generate on_transport_open event here until we find a better place
-    transport t(make_wrapper(pn_event_transport(pe.pn_event())));
-    delegate_.on_transport_open(t);
+    transport t(make_wrapper(pn_event_transport(event)));
+    handler.on_transport_open(t);
 
-    pn_connection_t *conn = pn_event_connection(pe.pn_event());
+    pn_connection_t *conn = pn_event_connection(event);
     connection c(make_wrapper(conn));
-    delegate_.on_connection_open(c);
+    handler.on_connection_open(c);
     if (!is_local_open(pn_connection_state(conn)) && is_local_unititialised(pn_connection_state(conn))) {
         pn_connection_open(conn);
     }
 }
 
-void messaging_adapter::on_session_remote_open(proton_event &pe) {
-    pn_session_t *session = pn_event_session(pe.pn_event());
+void on_session_remote_open(messaging_handler& handler, pn_event_t* event) {
+    pn_session_t *session = pn_event_session(event);
     class session s(make_wrapper(session));
-    delegate_.on_session_open(s);
+    handler.on_session_open(s);
     if (!is_local_open(pn_session_state(session)) && is_local_unititialised(pn_session_state(session))) {
         pn_session_open(session);
     }
 }
 
-void messaging_adapter::on_link_local_open(proton_event &pe) {
-    credit_topup(pn_event_link(pe.pn_event()));
+void on_link_local_open(messaging_handler& handler, pn_event_t* event) {
+    pn_link_t* lnk = pn_event_link(event);
+    if ( pn_link_is_receiver(lnk) ) {
+        credit_topup(lnk);
+    // We know local is active so don't check for it
+    } else if ( pn_link_state(lnk)&PN_REMOTE_ACTIVE && pn_link_credit(lnk) > 0) {
+        sender s(make_wrapper<sender>(lnk));
+        handler.on_sendable(s);
+    }
 }
 
-void messaging_adapter::on_link_remote_open(proton_event &pe) {
-    pn_link_t *lnk = pn_event_link(pe.pn_event());
+void on_link_remote_open(messaging_handler& handler, pn_event_t* event) {
+    pn_link_t *lnk = pn_event_link(event);
     if (pn_link_is_receiver(lnk)) {
       receiver r(make_wrapper<receiver>(lnk));
-      delegate_.on_receiver_open(r);
+      handler.on_receiver_open(r);
       if (is_local_unititialised(pn_link_state(lnk))) {
           r.open(r.connection().receiver_options());
       }
+      credit_topup(lnk);
     } else {
       sender s(make_wrapper<sender>(lnk));
-      delegate_.on_sender_open(s);
+      handler.on_sender_open(s);
       if (is_local_unititialised(pn_link_state(lnk))) {
           s.open(s.connection().sender_options());
       }
     }
-    credit_topup(lnk);
 }
 
-void messaging_adapter::on_transport_closed(proton_event &pe) {
-    pn_transport_t *tspt = pn_event_transport(pe.pn_event());
+void on_transport_closed(messaging_handler& handler, pn_event_t* event) {
+    pn_transport_t *tspt = pn_event_transport(event);
     transport t(make_wrapper(tspt));
 
     // If the connection isn't open generate on_transport_open event
     // because we didn't generate it yet and the events won't match.
-    pn_connection_t *conn = pn_event_connection(pe.pn_event());
+    pn_connection_t *conn = pn_event_connection(event);
     if (!conn || is_remote_unititialised(pn_connection_state(conn))) {
-        delegate_.on_transport_open(t);
+        handler.on_transport_open(t);
     }
 
     if (pn_condition_is_set(pn_transport_condition(tspt))) {
-        delegate_.on_transport_error(t);
+        handler.on_transport_error(t);
+    }
+    handler.on_transport_close(t);
+}
+
+}
+
+void messaging_adapter::dispatch(messaging_handler& handler, pn_event_t* event)
+{
+    pn_event_type_t type = pn_event_type(event);
+
+    // Only handle events we are interested in
+    switch(type) {
+
+      case PN_CONNECTION_REMOTE_OPEN: on_connection_remote_open(handler, event); break;
+      case PN_CONNECTION_REMOTE_CLOSE: on_connection_remote_close(handler, event); break;
+
+      case PN_SESSION_REMOTE_OPEN: on_session_remote_open(handler, event); break;
+      case PN_SESSION_REMOTE_CLOSE: on_session_remote_close(handler, event); break;
+
+      case PN_LINK_LOCAL_OPEN: on_link_local_open(handler, event); break;
+      case PN_LINK_REMOTE_OPEN: on_link_remote_open(handler, event); break;
+      case PN_LINK_REMOTE_CLOSE: on_link_remote_close(handler, event); break;
+      case PN_LINK_REMOTE_DETACH: on_link_remote_detach(handler, event); break;
+      case PN_LINK_FLOW: on_link_flow(handler, event); break;
+
+      case PN_DELIVERY: on_delivery(handler, event); break;
+
+      case PN_TRANSPORT_CLOSED: on_transport_closed(handler, event); break;
+
+      // Ignore everything else
+      default: break;
     }
-    delegate_.on_transport_close(t);
 }
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index 2b6b1de..2486e2b 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -35,7 +35,6 @@
 #include "contexts.hpp"
 #include "messaging_adapter.hpp"
 #include "proton_bits.hpp"
-#include "proton_event.hpp"
 
 #include <assert.h>
 
@@ -377,10 +376,7 @@ bool container::impl::handle(pn_event_t* event) {
     // This is pretty unusual, but possible if we use the default constructor for container
     if (!mh) return false;
 
-    // TODO: Currently create a throwaway messaging_adapter and proton_event so we can call dispatch, a bit inefficient
-    messaging_adapter ma(*mh);
-    proton_event pe(event);
-    pe.dispatch(ma);
+    messaging_adapter::dispatch(*mh, event);
     return false;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/proton_event.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_event.cpp b/proton-c/bindings/cpp/src/proton_event.cpp
deleted file mode 100644
index 9a1ffea..0000000
--- a/proton-c/bindings/cpp/src/proton_event.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton_event.hpp"
-
-#include "proton/error.hpp"
-
-#include "msg.hpp"
-#include "proton_handler.hpp"
-#include "types_internal.hpp"
-
-namespace proton {
-
-void proton_event::dispatch(proton_handler &handler) {
-    pn_event_type_t type = pn_event_type(pn_event_);
-    switch(type) {
-
-      case PN_REACTOR_INIT: handler.on_reactor_init(*this); break;
-      case PN_REACTOR_QUIESCED: handler.on_reactor_quiesced(*this); break;
-      case PN_REACTOR_FINAL: handler.on_reactor_final(*this); break;
-
-      case PN_TIMER_TASK: handler.on_timer_task(*this); break;
-
-      case PN_CONNECTION_INIT: handler.on_connection_init(*this); break;
-      case PN_CONNECTION_BOUND: handler.on_connection_bound(*this); break;
-      case PN_CONNECTION_UNBOUND: handler.on_connection_unbound(*this); break;
-      case PN_CONNECTION_LOCAL_OPEN: handler.on_connection_local_open(*this); break;
-      case PN_CONNECTION_LOCAL_CLOSE: handler.on_connection_local_close(*this); break;
-      case PN_CONNECTION_REMOTE_OPEN: handler.on_connection_remote_open(*this); break;
-      case PN_CONNECTION_REMOTE_CLOSE: handler.on_connection_remote_close(*this); break;
-      case PN_CONNECTION_FINAL: handler.on_connection_final(*this); break;
-
-      case PN_SESSION_INIT: handler.on_session_init(*this); break;
-      case PN_SESSION_LOCAL_OPEN: handler.on_session_local_open(*this); break;
-      case PN_SESSION_LOCAL_CLOSE: handler.on_session_local_close(*this); break;
-      case PN_SESSION_REMOTE_OPEN: handler.on_session_remote_open(*this); break;
-      case PN_SESSION_REMOTE_CLOSE: handler.on_session_remote_close(*this); break;
-      case PN_SESSION_FINAL: handler.on_session_final(*this); break;
-
-      case PN_LINK_INIT: handler.on_link_init(*this); break;
-      case PN_LINK_LOCAL_OPEN: handler.on_link_local_open(*this); break;
-      case PN_LINK_LOCAL_CLOSE: handler.on_link_local_close(*this); break;
-      case PN_LINK_LOCAL_DETACH: handler.on_link_local_detach(*this); break;
-      case PN_LINK_REMOTE_OPEN: handler.on_link_remote_open(*this); break;
-      case PN_LINK_REMOTE_CLOSE: handler.on_link_remote_close(*this); break;
-      case PN_LINK_REMOTE_DETACH: handler.on_link_remote_detach(*this); break;
-      case PN_LINK_FLOW: handler.on_link_flow(*this); break;
-      case PN_LINK_FINAL: handler.on_link_final(*this); break;
-
-      case PN_DELIVERY: handler.on_delivery(*this); break;
-
-      case PN_TRANSPORT: handler.on_transport(*this); break;
-      case PN_TRANSPORT_ERROR: handler.on_transport_error(*this); break;
-      case PN_TRANSPORT_HEAD_CLOSED: handler.on_transport_head_closed(*this); break;
-      case PN_TRANSPORT_TAIL_CLOSED: handler.on_transport_tail_closed(*this); break;
-      case PN_TRANSPORT_CLOSED: handler.on_transport_closed(*this); break;
-
-      case PN_SELECTABLE_INIT: handler.on_selectable_init(*this); break;
-      case PN_SELECTABLE_UPDATED: handler.on_selectable_updated(*this); break;
-      case PN_SELECTABLE_READABLE: handler.on_selectable_readable(*this); break;
-      case PN_SELECTABLE_WRITABLE: handler.on_selectable_writable(*this); break;
-      case PN_SELECTABLE_EXPIRED: handler.on_selectable_expired(*this); break;
-      case PN_SELECTABLE_ERROR: handler.on_selectable_error(*this); break;
-      case PN_SELECTABLE_FINAL: handler.on_selectable_final(*this); break;
-      default:
-        throw error(MSG("Invalid Proton event type " << type));
-    }
-}
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1a513d64/proton-c/bindings/cpp/src/proton_handler.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proton_handler.cpp b/proton-c/bindings/cpp/src/proton_handler.cpp
deleted file mode 100644
index 87d00a3..0000000
--- a/proton-c/bindings/cpp/src/proton_handler.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-#include "proton_handler.hpp"
-#include "proton_event.hpp"
-
-namespace proton {
-
-proton_handler::proton_handler() {}
-proton_handler::~proton_handler() {}
-
-// Everything goes to on_unhandled() unless overriden by subclass
-
-void proton_handler::on_reactor_init(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_reactor_quiesced(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_reactor_final(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_timer_task(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_init(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_bound(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_unbound(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_local_open(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_local_close(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_remote_open(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_remote_close(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_connection_final(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_session_init(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_session_local_open(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_session_local_close(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_session_remote_open(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_session_remote_close(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_session_final(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_init(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_local_open(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_local_close(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_local_detach(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_remote_open(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_remote_close(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_remote_detach(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_flow(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_link_final(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_delivery(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_transport(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_transport_error(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_transport_head_closed(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_transport_tail_closed(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_transport_closed(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_init(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_updated(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_readable(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_writable(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_expired(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_error(proton_event &e) { on_unhandled(e); }
-void proton_handler::on_selectable_final(proton_event &e) { on_unhandled(e); }
-
-void proton_handler::on_unhandled(proton_event &) {}
-
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[15/20] qpid-proton git commit: PROTON-1481: [C++ binding] Split out general work deferring functions to the work_queue header Add efficient C++11 versions of work factories Reorder defer arguments to be like std::bind Add extra overloads for defer like

Posted by as...@apache.org.
PROTON-1481: [C++ binding] Split out general work deferring functions to the work_queue header
Add efficient C++11 versions of work factories
Reorder defer arguments to be like std::bind
Add extra overloads for defer like std::bind (for free functions arbitrary work_queues)


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/efc899fb
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/efc899fb
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/efc899fb

Branch: refs/heads/master
Commit: efc899fb377611fcf9cf26280a2025c980bb0bf2
Parents: 5dd3f46
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon May 15 01:45:43 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         | 110 ++--------
 .../bindings/cpp/include/proton/work_queue.hpp  | 210 +++++++++++++++++++
 2 files changed, 222 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/efc899fb/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 9af60ba..a1ef3a5 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -70,92 +70,6 @@
 // SendMsg(msg)   - From a Queue to a Connection (sender)
 // Unsubscribed() - From a Queue to a Connection (sender)
 
-// Utilities to make injecting member functions palatable in C++03
-template <class T>
-struct work0 : public proton::void_function0 {
-    T& holder_;
-    void (T::* fn_)();
-
-    work0(T& h, void (T::* a)()) :
-        holder_(h), fn_(a) {}
-
-    void operator()() OVERRIDE {
-        (holder_.*fn_)();
-        delete this;
-    }
-};
-
-template <class T, class A>
-struct work1 : public proton::void_function0 {
-    T& holder_;
-    void (T::* fn_)(A);
-    A a_;
-
-    work1(T& h, void (T::* t)(A), A a) :
-        holder_(h), fn_(t), a_(a) {}
-
-    void operator()() OVERRIDE {
-        (holder_.*fn_)(a_);
-        delete this;
-    }
-};
-
-template <class T, class A, class B>
-struct work2 : public proton::void_function0 {
-    T& holder_;
-    void (T::* fn_)(A, B);
-    A a_;
-    B b_;
-
-    work2(T& h, void (T::* t)(A, B), A a, B b) :
-        holder_(h), fn_(t), a_(a), b_(b) {}
-
-    void operator()() OVERRIDE {
-        (holder_.*fn_)(a_, b_);
-        delete this;
-    }
-};
-
-template <class T, class A, class B, class C>
-struct work3 : public proton::void_function0 {
-    T& holder_;
-    void (T::* fn_)(A, B, C);
-    A a_;
-    B b_;
-    C c_;
-
-    work3(T& h, void (T::* t)(A, B, C), A a, B b, C c) :
-        holder_(h), fn_(t), a_(a), b_(b), c_(c) {}
-
-    void operator()() OVERRIDE {
-        (holder_.*fn_)(a_, b_, c_);
-        delete this;
-    }
-};
-
-template <class T>
-void defer(T* t, void (T::*f)()) {
-    work0<T>* w = new work0<T>(*t, f);
-    t->add(*w);
-}
-
-template <class T, class A>
-void defer(T* t, void (T::*f)(A), A a) {
-    work1<T, A>* w = new work1<T, A>(*t, f, a);
-    t->add(*w);
-}
-
-template <class T, class A, class B>
-void defer(T* t, void (T::*f)(A, B), A a, B b) {
-    work2<T, A, B>* w = new work2<T, A, B>(*t, f, a, b);
-    t->add(*w);
-}
-
-template <class T, class A, class B, class C>
-void defer(T* t, void (T::*f)(A, B, C), A a, B b, C c) {
-    work3<T, A, B, C>* w = new work3<T, A, B, C>(*t, f, a, b, c);
-    t->add(*w);
-}
 
 // Simple debug output
 bool verbose;
@@ -225,7 +139,7 @@ class Queue {
             DOUT(std::cerr << "(" << current_->second << ") ";);
             if (current_->second>0) {
                 DOUT(std::cerr << current_->first << " ";);
-                defer(current_->first, &Sender::sendMsg, messages_.front());
+                proton::defer(&Sender::sendMsg, current_->first, messages_.front());
                 messages_.pop_front();
                 --current_->second;
                 ++current_;
@@ -264,14 +178,14 @@ public:
         // If we're about to erase the current subscription move on
         if (current_ != subscriptions_.end() && current_->first==s) ++current_;
         subscriptions_.erase(s);
-        defer(s, &Sender::unsubscribed);
+        proton::defer(&Sender::unsubscribed, s);
     }
 };
 
 // We have credit to send a message.
 void Sender::on_sendable(proton::sender &sender) {
     if (queue_) {
-        defer(queue_, &Queue::flow, this, sender.credit());
+        proton::defer(&Queue::flow, queue_, this, sender.credit());
     } else {
         pending_credit_ = sender.credit();
     }
@@ -279,7 +193,7 @@ void Sender::on_sendable(proton::sender &sender) {
 
 void Sender::on_sender_close(proton::sender &sender) {
     if (queue_) {
-        defer(queue_, &Queue::unsubscribe, this);
+        proton::defer(&Queue::unsubscribe, queue_, this);
     } else {
         // TODO: Is it possible to be closed before we get the queue allocated?
         // If so, we should have a way to mark the sender deleted, so we can delete
@@ -293,12 +207,12 @@ void Sender::boundQueue(Queue* q, std::string qn) {
     queue_ = q;
     queue_name_ = qn;
 
-    defer(q, &Queue::subscribe, this);
+    proton::defer(&Queue::subscribe, q, this);
     sender_.open(proton::sender_options()
         .source((proton::source_options().address(queue_name_)))
         .handler(*this));
     if (pending_credit_>0) {
-        defer(queue_, &Queue::flow, this, pending_credit_);
+        proton::defer(&Queue::flow, queue_, this, pending_credit_);
     }
     std::cout << "sending from " << queue_name_ << std::endl;
 }
@@ -323,7 +237,7 @@ class Receiver : public proton::messaging_handler {
     void queueMsgs() {
         DOUT(std::cerr << "Receiver: " << this << " queueing " << messages_.size() << " msgs to: " << queue_ << "\n";);
         while (!messages_.empty()) {
-            defer(queue_, &Queue::queueMsg, messages_.front());
+            proton::defer(&Queue::queueMsg, queue_, messages_.front());
             messages_.pop_front();
         }
     }
@@ -381,7 +295,7 @@ public:
         } else {
             q = i->second;
         }
-        defer(&connection, &T::boundQueue, q, qn);
+        proton::defer(&T::boundQueue, &connection, q, qn);
     }
 
     void findQueueSender(Sender* s, std::string qn) {
@@ -411,7 +325,7 @@ public:
         std::string qn = sender.source().dynamic() ? "" : sender.source().address();
         Sender* s = new Sender(sender, senders_);
         senders_[sender] = s;
-        defer(&queue_manager_, &QueueManager::findQueueSender, s, qn);
+        proton::defer(&QueueManager::findQueueSender, &queue_manager_, s, qn);
     }
 
     // A receiver receives messages from a publisher to a queue.
@@ -427,7 +341,7 @@ public:
                 DOUT(std::cerr << "ODD - trying to attach to a empty address\n";);
             }
             Receiver* r = new Receiver(receiver);
-            defer(&queue_manager_, &QueueManager::findQueueReceiver, r, qname);
+            proton::defer(&QueueManager::findQueueReceiver, &queue_manager_, r, qname);
         }
     }
 
@@ -438,7 +352,7 @@ public:
             if (j == senders_.end()) continue;
             Sender* s = j->second;
             if (s->queue_) {
-                defer(s->queue_, &Queue::unsubscribe, s);
+                proton::defer(&Queue::unsubscribe, s->queue_, s);
             }
             senders_.erase(j);
         }
@@ -456,7 +370,7 @@ public:
             if (j == senders_.end()) continue;
             Sender* s = j->second;
             if (s->queue_) {
-                defer(s->queue_, &Queue::unsubscribe, s);
+                proton::defer(&Queue::unsubscribe, s->queue_, s);
             }
         }
         delete this;            // All done.

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/efc899fb/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index 7c21710..1937e11 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -117,6 +117,216 @@ class PN_CPP_CLASS_EXTERN work_queue {
     /// @endcond
 };
 
+// Utilities to make injecting functions/member functions palatable in C++03
+// Lots of repetition to handle functions with up to 3 arguments
+#if !PN_CPP_HAS_CPP11
+struct work0 : public proton::void_function0 {
+    void (* fn_)();
+
+    work0(void (* f)()) :
+        fn_(f) {}
+
+    void operator()() {
+        (*fn_)();
+        delete this;
+    }
+};
+
+template <class A>
+struct work1 : public proton::void_function0 {
+    void (* fn_)(A);
+    A a_;
+
+    work1(void (* t)(A), A a) :
+        fn_(t), a_(a) {}
+
+    void operator()() {
+        (*fn_)(a_);
+        delete this;
+    }
+};
+
+template <class A, class B>
+struct work2 : public proton::void_function0 {
+    void (* fn_)(A, B);
+    A a_;
+    B b_;
+
+    work2(void (* t)(A, B), A a, B b) :
+        fn_(t), a_(a), b_(b) {}
+
+    void operator()() {
+        (*fn_)(a_, b_);
+        delete this;
+    }
+};
+
+template <class A, class B, class C>
+struct work3 : public proton::void_function0 {
+    void (* fn_)(A, B, C);
+    A a_;
+    B b_;
+    C c_;
+
+    work3(void (* t)(A, B, C), A a, B b, C c) :
+        fn_(t), a_(a), b_(b), c_(c) {}
+
+    void operator()() {
+        (*fn_)(a_, b_, c_);
+        delete this;
+    }
+};
+
+template <class T>
+struct work_pmf0 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)();
+
+    work_pmf0(void (T::* a)(), T& h) :
+        holder_(h), fn_(a) {}
+
+    void operator()() {
+        (holder_.*fn_)();
+        delete this;
+    }
+};
+
+template <class T, class A>
+struct work_pmf1 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)(A);
+    A a_;
+
+    work_pmf1(void (T::* t)(A), T& h, A a) :
+        holder_(h), fn_(t), a_(a) {}
+
+    void operator()() {
+        (holder_.*fn_)(a_);
+        delete this;
+    }
+};
+
+template <class T, class A, class B>
+struct work_pmf2 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)(A, B);
+    A a_;
+    B b_;
+
+    work_pmf2(void (T::* t)(A, B), T& h, A a, B b) :
+        holder_(h), fn_(t), a_(a), b_(b) {}
+
+    void operator()() {
+        (holder_.*fn_)(a_, b_);
+        delete this;
+    }
+};
+
+template <class T, class A, class B, class C>
+struct work_pmf3 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)(A, B, C);
+    A a_;
+    B b_;
+    C c_;
+
+    work_pmf3(void (T::* t)(A, B, C), T& h, A a, B b, C c) :
+        holder_(h), fn_(t), a_(a), b_(b), c_(c) {}
+
+    void operator()() {
+        (holder_.*fn_)(a_, b_, c_);
+        delete this;
+    }
+};
+
+/// This version of proton::defer defers calling an object's member function to the object's work queue
+template <class T>
+void defer(void (T::*f)(), T* t) {
+    work_pmf0<T>* w = new work_pmf0<T>(f, *t);
+    t->add(*w);
+}
+
+template <class T, class A>
+void defer(void (T::*f)(A), T* t, A a) {
+    work_pmf1<T, A>* w = new work_pmf1<T, A>(f, *t, a);
+    t->add(*w);
+}
+
+template <class T, class A, class B>
+void defer(void (T::*f)(A, B), T* t, A a, B b) {
+    work_pmf2<T, A, B>* w = new work_pmf2<T, A, B>(f, *t, a, b);
+    t->add(*w);
+}
+
+template <class T, class A, class B, class C>
+void defer(void (T::*f)(A, B, C), T* t, A a, B b, C c) {
+    work_pmf3<T, A, B, C>* w = new work_pmf3<T, A, B, C>(f, *t, a, b, c);
+    t->add(*w);
+}
+
+/// This version of proton::defer defers calling a member function to an arbitrary work queue
+template <class T, class U>
+void defer(U* wq, void (T::*f)(), T* t) {
+    work_pmf0<T>* w = new work_pmf0<T>(f, *t);
+    wq->add(*w);
+}
+
+template <class T, class U, class A>
+void defer(U* wq, void (T::*f)(A), T* t, A a) {
+    work_pmf1<T, A>* w = new work_pmf1<T, A>(f, *t, a);
+    wq->add(*w);
+}
+
+template <class T, class U, class A, class B>
+void defer(U* wq, void (T::*f)(A, B), T* t, A a, B b) {
+    work_pmf2<T, A, B>* w = new work_pmf2<T, A, B>(f, *t, a, b);
+    wq->add(*w);
+}
+
+template <class T, class U, class A, class B, class C>
+void defer(U* wq, void (T::*f)(A, B, C), T* t, A a, B b, C c) {
+    work_pmf3<T, A, B, C>* w = new work_pmf3<T, A, B, C>(f, *t, a, b, c);
+    wq->add(*w);
+}
+
+/// This version of proton::defer defers calling a free function to an arbitrary work queue
+template <class U>
+void defer(U* wq, void (*f)()) {
+    work0* w = new work0(f);
+    wq->add(*w);
+}
+
+template <class U, class A>
+void defer(U* wq, void (*f)(A), A a) {
+    work1<A>* w = new work1<A>(f, a);
+    wq->add(*w);
+}
+
+template <class U, class A, class B>
+void defer(U* wq, void (*f)(A, B), A a, B b) {
+    work2<A, B>* w = new work2<A, B>(f, a, b);
+    wq->add(*w);
+}
+
+template <class U, class A, class B, class C>
+void defer(U* wq, void (*f)(A, B, C), A a, B b, C c) {
+    work3<A, B, C>* w = new work3<A, B, C>(f, a, b, c);
+    wq->add(*w);
+}
+#else
+// The C++11 version is *much* simpler and even so more general!
+// These 2 definitions encompass everything in the C++03 section
+template <class T, class... Rest>
+void defer(void(T::*f)(Rest...), T* t, Rest... r) {
+    t->add(std::bind(f, t, r...));
+}
+
+template <class U, class... Rest>
+void defer(U* wq, Rest&&... r) {
+    wq->add(std::bind(std::forward<Rest>(r)...));
+}
+#endif
+
 } // proton
 
 #endif // PROTON_WORK_QUEUE_HPP


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[09/20] qpid-proton git commit: PROTON-1400: [C++ binding] Implement container level event_loops

Posted by as...@apache.org.
PROTON-1400: [C++ binding] Implement container level event_loops


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/570d0a1a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/570d0a1a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/570d0a1a

Branch: refs/heads/master
Commit: 570d0a1aae29adfab861a76f37d2aa9f14488a9a
Parents: ec2364f
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Apr 20 15:20:40 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/container.hpp   |   1 +
 .../bindings/cpp/include/proton/event_loop.hpp  |   1 +
 proton-c/bindings/cpp/src/event_loop.cpp        |   3 +
 .../cpp/src/include/proactor_container_impl.hpp |  10 ++
 .../src/include/proactor_event_loop_impl.hpp    |  23 +--
 .../cpp/src/proactor_container_impl.cpp         | 156 ++++++++++++++-----
 6 files changed, 139 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/570d0a1a/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index be83e5e..0262e0f 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -224,6 +224,7 @@ class PN_CPP_CLASS_EXTERN container {
   friend class session_options;
   friend class receiver_options;
   friend class sender_options;
+  friend class event_loop;
 };
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/570d0a1a/proton-c/bindings/cpp/include/proton/event_loop.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/event_loop.hpp b/proton-c/bindings/cpp/include/proton/event_loop.hpp
index f49d211..6d1646e 100644
--- a/proton-c/bindings/cpp/include/proton/event_loop.hpp
+++ b/proton-c/bindings/cpp/include/proton/event_loop.hpp
@@ -50,6 +50,7 @@ class PN_CPP_CLASS_EXTERN event_loop {
   public:
     /// Create event_loop
     PN_CPP_EXTERN event_loop();
+    PN_CPP_EXTERN event_loop(container&);
 
     PN_CPP_EXTERN ~event_loop();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/570d0a1a/proton-c/bindings/cpp/src/event_loop.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/event_loop.cpp b/proton-c/bindings/cpp/src/event_loop.cpp
index ab39aa7..5320011 100644
--- a/proton-c/bindings/cpp/src/event_loop.cpp
+++ b/proton-c/bindings/cpp/src/event_loop.cpp
@@ -20,6 +20,7 @@
 #include "proton/event_loop.hpp"
 
 #include "contexts.hpp"
+#include "proactor_container_impl.hpp"
 #include "proactor_event_loop_impl.hpp"
 
 #include <proton/session.h>
@@ -28,6 +29,8 @@
 namespace proton {
 
 event_loop::event_loop() {}
+event_loop::event_loop(container& c) { *this = container::impl::make_event_loop(c); }
+
 event_loop::~event_loop() {}
 
 event_loop& event_loop::operator=(impl* i) { impl_.reset(i); return *this; }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/570d0a1a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
index 859493d..4b84a6e 100644
--- a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
@@ -28,6 +28,7 @@
 #include "proton/connection_options.hpp"
 #include "proton/duration.hpp"
 #include "proton/error_condition.hpp"
+#include "proton/event_loop.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/receiver.hpp"
 #include "proton/receiver_options.hpp"
@@ -38,6 +39,7 @@
 
 #include <list>
 #include <map>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -77,8 +79,12 @@ class container::impl {
 #endif
     template <class T> static void set_handler(T s, messaging_handler* h);
     template <class T> static messaging_handler* get_handler(T s);
+    static event_loop::impl* make_event_loop(container&);
 
   private:
+    class common_event_loop;
+    class connection_event_loop;
+    class container_event_loop;
     pn_listener_t* listen_common_lh(const std::string&);
     connection connect_common(const std::string&, const connection_options&);
 
@@ -89,6 +95,10 @@ class container::impl {
 
     container& container_;
 
+    typedef std::set<container_event_loop*> event_loops;
+    event_loops event_loops_;
+    container_event_loop* add_event_loop();
+    void remove_event_loop(container_event_loop*);
     struct scheduled {
         timestamp time; // duration from epoch for task
 #if PN_CPP_HAS_STD_FUNCTION

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/570d0a1a/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
index 8fa7acf..82ec129 100644
--- a/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
@@ -23,30 +23,19 @@
  */
 
 #include "proton/fwd.hpp"
-
-struct pn_connection_t;
+#include "proton/internal/config.hpp"
 
 namespace proton {
 
 class event_loop::impl {
   public:
-    impl(pn_connection_t*);
-
-    bool inject(void_function0& f);
+    virtual ~impl() {};
+    virtual bool inject(void_function0& f) = 0;
 #if PN_CPP_HAS_STD_FUNCTION
-    bool inject(std::function<void()> f);
-    typedef std::vector<std::function<void()> > jobs;
-#else
-    typedef std::vector<void_function0*> jobs;
+    virtual bool inject(std::function<void()> f) = 0;
 #endif
-
-
-    void run_all_jobs();
-    void finished();
-
-    jobs jobs_;
-    pn_connection_t* connection_;
-    bool finished_;
+    virtual void run_all_jobs() = 0;
+    virtual void finished() = 0;
 };
 
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/570d0a1a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index 2486e2b..4d526f2 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -43,30 +43,25 @@
 
 namespace proton {
 
-event_loop::impl::impl(pn_connection_t* c)
-    : connection_(c), finished_(false)
-{}
-
-void event_loop::impl::finished() {
-    finished_ = true;
-}
+class container::impl::common_event_loop : public event_loop::impl {
+  public:
+    common_event_loop(): finished_(false) {}
 
 #if PN_CPP_HAS_STD_FUNCTION
-bool event_loop::impl::inject(std::function<void()> f) {
-    // Note this is an unbounded work queue.
-    // A resource-safe implementation should be bounded.
-    if (finished_)
-         return false;
-    jobs_.push_back(f);
-    pn_connection_wake(connection_);
-    return true;
-}
+    typedef std::vector<std::function<void()> > jobs;
+#else
+    typedef std::vector<void_function0*> jobs;
+#endif
 
-bool event_loop::impl::inject(proton::void_function0& f) {
-    return inject([&f]() { f(); });
-}
+    void run_all_jobs();
+    void finished() { finished_ = true; }
 
-void event_loop::impl::run_all_jobs() {
+    jobs jobs_;
+    bool finished_;
+};
+
+#if PN_CPP_HAS_STD_FUNCTION
+void container::impl::common_event_loop::run_all_jobs() {
     decltype(jobs_) j;
     {
         std::swap(j, jobs_);
@@ -77,25 +72,93 @@ void event_loop::impl::run_all_jobs() {
     } catch (...) {};
 }
 #else
-bool event_loop::impl::inject(proton::void_function0& f) {
+void container::impl::common_event_loop::run_all_jobs() {
+    // Run queued work, but ignore any exceptions
+    for (jobs::iterator f = jobs_.begin(); f != jobs_.end(); ++f) try {
+        (**f)();
+    } catch (...) {};
+    jobs_.clear();
+    return;
+}
+#endif
+
+class container::impl::connection_event_loop : public common_event_loop {
+  public:
+    connection_event_loop(pn_connection_t* c): connection_(c) {}
+
+    bool inject(void_function0& f);
+#if PN_CPP_HAS_STD_FUNCTION
+    bool inject(std::function<void()> f);
+#endif
+
+    pn_connection_t* connection_;
+};
+
+#if PN_CPP_HAS_STD_FUNCTION
+bool container::impl::connection_event_loop::inject(std::function<void()> f) {
+    // Note this is an unbounded work queue.
+    // A resource-safe implementation should be bounded.
+    if (finished_) return false;
+    jobs_.emplace_back(std::move(f));
+    pn_connection_wake(connection_);
+    return true;
+}
+
+bool container::impl::connection_event_loop::inject(proton::void_function0& f) {
+    return inject([&f]() { f(); });
+}
+#else
+bool container::impl::connection_event_loop::inject(proton::void_function0& f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
-    if (finished_)
-         return false;
+    if (finished_) return false;
     jobs_.push_back(&f);
     pn_connection_wake(connection_);
     return true;
 }
+#endif
 
-void event_loop::impl::run_all_jobs() {
-    // Run queued work, but ignore any exceptions
-    for (event_loop::impl::jobs::iterator f = jobs_.begin(); f != jobs_.end(); ++f) try {
-        (**f)();
-    } catch (...) {};
-    jobs_.clear();
-    return;
+class container::impl::container_event_loop : public common_event_loop {
+  public:
+    container_event_loop(container::impl& c): container_(c) {}
+    ~container_event_loop() { container_.remove_event_loop(this); }
+
+    bool inject(void_function0& f);
+#if PN_CPP_HAS_STD_FUNCTION
+    bool inject(std::function<void()> f);
+#endif
+
+    container::impl& container_;
+};
+
+#if PN_CPP_HAS_STD_FUNCTION
+bool container::impl::container_event_loop::inject(std::function<void()> f) {
+    // Note this is an unbounded work queue.
+    // A resource-safe implementation should be bounded.
+    if (finished_) return false;
+    jobs_.emplace_back(std::move(f));
+    pn_proactor_set_timeout(container_.proactor_, 0);
+    return true;
+}
+
+bool container::impl::container_event_loop::inject(proton::void_function0& f) {
+    return inject([&f]() { f(); });
+}
+#else
+bool container::impl::container_event_loop::inject(proton::void_function0& f) {
+    // Note this is an unbounded work queue.
+    // A resource-safe implementation should be bounded.
+    if (finished_) return false;
+    jobs_.push_back(&f);
+    pn_proactor_set_timeout(container_.proactor_, 0);
+    return true;
 }
 #endif
+
+class event_loop::impl* container::impl::make_event_loop(container& c) {
+    return c.impl_->add_event_loop();
+}
+
 container::impl::impl(container& c, const std::string& id, messaging_handler* mh)
     : container_(c), proactor_(pn_proactor()), handler_(mh), id_(id),
       auto_stop_(true), stopping_(false)
@@ -109,6 +172,16 @@ container::impl::~impl() {
     pn_proactor_free(proactor_);
 }
 
+container::impl::container_event_loop* container::impl::add_event_loop() {
+    container_event_loop* c = new container_event_loop(*this);
+    event_loops_.insert(c);
+    return c;
+}
+
+void container::impl::remove_event_loop(container::impl::container_event_loop* l) {
+    event_loops_.erase(l);
+}
+
 proton::connection container::impl::connect_common(
     const std::string& addr,
     const proton::connection_options& user_opts)
@@ -125,7 +198,7 @@ proton::connection container::impl::connect_common(
     connection_context& cc(connection_context::get(pnc));
     cc.container = &container_;
     cc.handler = mh;
-    cc.event_loop_ = new event_loop::impl(pnc);
+    cc.event_loop_ = new container::impl::connection_event_loop(pnc);
 
     pn_connection_set_container(pnc, id_.c_str());
     pn_connection_set_hostname(pnc, url.host().c_str());
@@ -225,7 +298,7 @@ void container::impl::schedule(duration delay, void_function0& f) {
     pn_proactor_set_timeout(proactor_, delay.milliseconds());
 
     // Record timeout; Add callback to timeout sorted list
-    scheduled s={timestamp::now()+delay, &f};
+    scheduled s = {timestamp::now()+delay, &f};
     deferred_.push_back(s);
     std::push_heap(deferred_.begin(), deferred_.end());
 }
@@ -285,13 +358,20 @@ bool container::impl::handle(pn_event_t* event) {
     case PN_PROACTOR_INTERRUPT:
         return false;
 
-    case PN_PROACTOR_TIMEOUT:
-        // Maybe we got a timeout and have nothing scheduled (not sure if this is possible)
-        if  ( deferred_.size()==0 ) return false;
+    case PN_PROACTOR_TIMEOUT: {
+        // Can get an immediate timeout, if we have a container event loop inject
+        if  ( deferred_.size()>0 ) {
+            run_timer_jobs();
+        }
 
-        run_timer_jobs();
+        // Run every container event loop job
+        // This is not at all efficient and single threads all these jobs, but it does correctly
+        // serialise them
+        for (event_loops::iterator loop = event_loops_.begin(); loop!=event_loops_.end(); ++loop) {
+            (*loop)->run_all_jobs();
+        }
         return false;
-
+    }
     case PN_LISTENER_OPEN:
         return false;
 
@@ -312,7 +392,7 @@ bool container::impl::handle(pn_event_t* event) {
         cc.container = &container_;
         cc.listener_context_ = &lc;
         cc.handler = opts.handler();
-        cc.event_loop_ = new event_loop::impl(c);
+        cc.event_loop_ = new container::impl::connection_event_loop(c);
         pn_listener_accept(l, c);
         return false;
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[03/20] qpid-proton git commit: PROTON-1481: [C++ binding] Simplify code to use convenience functions

Posted by as...@apache.org.
PROTON-1481: [C++ binding] Simplify code to use convenience functions


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/ca446eac
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/ca446eac
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/ca446eac

Branch: refs/heads/master
Commit: ca446eac8d56ae9510f4ac5dbb1a9ab3dba93ac5
Parents: bf3a2b4
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu May 18 14:14:58 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 .../bindings/cpp/include/proton/thread_safe.hpp    | 17 ++---------------
 .../bindings/cpp/include/proton/work_queue.hpp     |  9 ---------
 2 files changed, 2 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca446eac/proton-c/bindings/cpp/include/proton/thread_safe.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/thread_safe.hpp b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
index e5f5303..04e39df 100644
--- a/proton-c/bindings/cpp/include/proton/thread_safe.hpp
+++ b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
@@ -63,12 +63,6 @@ template <class T>
 class thread_safe : private internal::pn_ptr_base, private internal::endpoint_traits<T> {
     typedef typename T::pn_type pn_type;
 
-    struct inject_decref : public void_function0 {
-        pn_type* ptr_;
-        inject_decref(pn_type* p) : ptr_(p) {}
-        void operator()() PN_CPP_OVERRIDE { decref(ptr_); delete this; }
-    };
-
   public:
     /// @cond INTERNAL
     static void operator delete(void*) {}
@@ -76,15 +70,8 @@ class thread_safe : private internal::pn_ptr_base, private internal::endpoint_tr
 
     ~thread_safe() {
         if (ptr()) {
-            if (!!work_queue()) {
-#if PN_CPP_HAS_STD_BIND
-                work_queue().add(std::bind(&decref, ptr()));
-#else
-                work_queue().add(*new inject_decref(ptr()));
-#endif
-            } else {
-                decref(ptr());
-            }
+            if (!!work_queue().impl_) defer(&work_queue(), &decref, (void*)ptr());
+            else decref(ptr());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ca446eac/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
index 4d843c2..fe739f5 100644
--- a/proton-c/bindings/cpp/include/proton/work_queue.hpp
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -87,15 +87,6 @@ class PN_CPP_CLASS_EXTERN work_queue {
 
     PN_CPP_EXTERN ~work_queue();
 
-#if PN_CPP_HAS_EXPLICIT_CONVERSIONS
-    /// When using C++11 (or later) you can use work_queue in a bool context
-    /// to indicate if there is an event loop set.
-    PN_CPP_EXTERN explicit operator bool() const { return bool(impl_); }
-#endif
-
-    /// No event loop set.
-    PN_CPP_EXTERN bool operator !() const { return !impl_; }
-
     /// Add work to the work queue: f() will be called serialised with other work in the queue:
     /// deferred and possibly in another thread.
     ///


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[12/20] qpid-proton git commit: PROTON-1481: [C++ binding] Rename event_loop API to work_queue

Posted by as...@apache.org.
PROTON-1481: [C++ binding] Rename event_loop API to work_queue


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/45d5612b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/45d5612b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/45d5612b

Branch: refs/heads/master
Commit: 45d5612bd674fa5055767ae66a261b9d81433edf
Parents: 2b2666b
Author: Andrew Stitcher <as...@apache.org>
Authored: Mon May 15 01:27:54 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp                         | 40 ++++-----
 examples/cpp/scheduled_send.cpp                 | 12 +--
 examples/cpp/scheduled_send_03.cpp              | 10 +--
 proton-c/bindings/cpp/CMakeLists.txt            |  2 +-
 .../bindings/cpp/include/proton/container.hpp   |  2 +-
 .../bindings/cpp/include/proton/event_loop.hpp  | 94 --------------------
 proton-c/bindings/cpp/include/proton/fwd.hpp    |  2 +-
 .../cpp/include/proton/io/connection_driver.hpp |  2 +-
 .../bindings/cpp/include/proton/thread_safe.hpp | 12 +--
 .../bindings/cpp/include/proton/work_queue.hpp  | 94 ++++++++++++++++++++
 proton-c/bindings/cpp/src/connection.cpp        |  2 +-
 proton-c/bindings/cpp/src/event_loop.cpp        | 60 -------------
 proton-c/bindings/cpp/src/include/contexts.hpp  |  4 +-
 .../cpp/src/include/proactor_container_impl.hpp | 18 ++--
 .../src/include/proactor_event_loop_impl.hpp    | 43 ---------
 .../src/include/proactor_work_queue_impl.hpp    | 43 +++++++++
 .../bindings/cpp/src/io/connection_driver.cpp   |  2 +-
 .../cpp/src/proactor_container_impl.cpp         | 54 +++++------
 proton-c/bindings/cpp/src/work_queue.cpp        | 60 +++++++++++++
 19 files changed, 278 insertions(+), 278 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 2fbe077..8c2d2ff 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -136,25 +136,25 @@ struct work3 : public proton::void_function0 {
 template <class T>
 void defer(T* t, void (T::*f)()) {
     work0<T>* w = new work0<T>(*t, f);
-    t->inject(*w);
+    t->add(*w);
 }
 
 template <class T, class A>
 void defer(T* t, void (T::*f)(A), A a) {
     work1<T, A>* w = new work1<T, A>(*t, f, a);
-    t->inject(*w);
+    t->add(*w);
 }
 
 template <class T, class A, class B>
 void defer(T* t, void (T::*f)(A, B), A a, B b) {
     work2<T, A, B>* w = new work2<T, A, B>(*t, f, a, b);
-    t->inject(*w);
+    t->add(*w);
 }
 
 template <class T, class A, class B, class C>
 void defer(T* t, void (T::*f)(A, B, C), A a, B b, C c) {
     work3<T, A, B, C>* w = new work3<T, A, B, C>(*t, f, a, b, c);
-    t->inject(*w);
+    t->add(*w);
 }
 
 // Simple debug output
@@ -171,7 +171,7 @@ class Sender : public proton::messaging_handler {
 
     proton::sender sender_;
     senders& senders_;
-    proton::event_loop& event_loop_;
+    proton::work_queue& work_queue_;
     std::string queue_name_;
     Queue* queue_;
     int pending_credit_;
@@ -182,11 +182,11 @@ class Sender : public proton::messaging_handler {
 
 public:
     Sender(proton::sender s, senders& ss) :
-        sender_(s), senders_(ss), event_loop_(make_thread_safe(s).get()->event_loop()), queue_(0), pending_credit_(0)
+        sender_(s), senders_(ss), work_queue_(make_thread_safe(s).get()->work_queue()), queue_(0), pending_credit_(0)
     {}
 
-    void inject(proton::void_function0& f) {
-        event_loop_.inject(f);
+    void add(proton::void_function0& f) {
+        work_queue_.add(f);
     }
 
 
@@ -203,7 +203,7 @@ public:
 
 // Queue - round robin subscriptions
 class Queue {
-    proton::event_loop event_loop_;
+    proton::work_queue work_queue_;
     const std::string name_;
     std::deque<proton::message> messages_;
     typedef std::map<Sender*, int> subscriptions; // With credit
@@ -238,11 +238,11 @@ class Queue {
 
 public:
     Queue(proton::container& c, const std::string& n) :
-        event_loop_(c), name_(n), current_(subscriptions_.end())
+        work_queue_(c), name_(n), current_(subscriptions_.end())
     {}
 
-    void inject(proton::void_function0& f) {
-        event_loop_.inject(f);
+    void add(proton::void_function0& f) {
+        work_queue_.add(f);
     }
 
     void queueMsg(proton::message m) {
@@ -307,7 +307,7 @@ class Receiver : public proton::messaging_handler {
     friend class connection_handler;
 
     proton::receiver receiver_;
-    proton::event_loop& event_loop_;
+    proton::work_queue& work_queue_;
     Queue* queue_;
     std::deque<proton::message> messages_;
 
@@ -330,11 +330,11 @@ class Receiver : public proton::messaging_handler {
 
 public:
     Receiver(proton::receiver r) :
-        receiver_(r), event_loop_(make_thread_safe(r).get()->event_loop()), queue_(0)
+        receiver_(r), work_queue_(make_thread_safe(r).get()->work_queue()), queue_(0)
     {}
 
-    void inject(proton::void_function0& f) {
-        event_loop_.inject(f);
+    void add(proton::void_function0& f) {
+        work_queue_.add(f);
     }
 
     void boundQueue(Queue* q, std::string qn) {
@@ -351,18 +351,18 @@ public:
 
 class QueueManager {
     proton::container& container_;
-    proton::event_loop event_loop_;
+    proton::work_queue work_queue_;
     typedef std::map<std::string, Queue*> queues;
     queues queues_;
     int next_id_; // Use to generate unique queue IDs.
 
 public:
     QueueManager(proton::container& c) :
-        container_(c), event_loop_(c), next_id_(0)
+        container_(c), work_queue_(c), next_id_(0)
     {}
 
-    void inject(proton::void_function0& f) {
-        event_loop_.inject(f);
+    void add(proton::void_function0& f) {
+        work_queue_.add(f);
     }
 
     template <class T>

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/examples/cpp/scheduled_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send.cpp b/examples/cpp/scheduled_send.cpp
index de04c3b..bbef15b 100644
--- a/examples/cpp/scheduled_send.cpp
+++ b/examples/cpp/scheduled_send.cpp
@@ -23,12 +23,12 @@
 
 #include <proton/container.hpp>
 #include <proton/default_container.hpp>
-#include <proton/event_loop.hpp>
 #include <proton/message.hpp>
 #include <proton/messaging_handler.hpp>
 #include <proton/sender.hpp>
 #include <proton/thread_safe.hpp>
 #include <proton/tracker.hpp>
+#include <proton/work_queue.hpp>
 
 #include <iostream>
 
@@ -40,7 +40,7 @@ class scheduled_sender : public proton::messaging_handler {
     std::string url;
     proton::sender sender;
     proton::duration interval, timeout;
-    proton::event_loop* event_loop;
+    proton::work_queue* work_queue;
     bool ready, canceled;
 
   public:
@@ -57,11 +57,11 @@ class scheduled_sender : public proton::messaging_handler {
     // and must arrange lambdas for send and close to happen in the connection context.
     void on_container_start(proton::container &c) OVERRIDE {
         sender = c.open_sender(url);
-        event_loop = &proton::make_thread_safe(sender).get()->event_loop();
+        work_queue = &proton::make_thread_safe(sender).get()->work_queue();
         // Call this->cancel after timeout.
-        c.schedule(timeout, [this]() { this->event_loop->inject( [this]() { this->cancel(); }); });
+        c.schedule(timeout, [this]() { this->work_queue->add( [this]() { this->cancel(); }); });
          // Start regular ticks every interval.
-        c.schedule(interval, [this]() { this->event_loop->inject( [this]() { this->tick(); }); });
+        c.schedule(interval, [this]() { this->work_queue->add( [this]() { this->tick(); }); });
     }
 
     void cancel() {
@@ -72,7 +72,7 @@ class scheduled_sender : public proton::messaging_handler {
     void tick() {
         // Schedule the next tick unless we have been cancelled.
         if (!canceled)
-            sender.container().schedule(interval, [this]() { this->event_loop->inject( [this]() { this->tick(); }); });
+            sender.container().schedule(interval, [this]() { this->work_queue->add( [this]() { this->tick(); }); });
         if (sender.credit() > 0) // Only send if we have credit
             send();
         else

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/examples/cpp/scheduled_send_03.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/scheduled_send_03.cpp b/examples/cpp/scheduled_send_03.cpp
index d106d29..4b1b626 100644
--- a/examples/cpp/scheduled_send_03.cpp
+++ b/examples/cpp/scheduled_send_03.cpp
@@ -25,13 +25,13 @@
 #include <proton/connection.hpp>
 #include <proton/default_container.hpp>
 #include <proton/duration.hpp>
-#include <proton/event_loop.hpp>
 #include <proton/function.hpp>
 #include <proton/message.hpp>
 #include <proton/messaging_handler.hpp>
 #include <proton/sender.hpp>
 #include <proton/thread_safe.hpp>
 #include <proton/tracker.hpp>
+#include <proton/work_queue.hpp>
 
 #include <iostream>
 
@@ -43,7 +43,7 @@ class scheduled_sender : public proton::messaging_handler {
   private:
     std::string url;
     proton::duration interval, timeout;
-    proton::event_loop *event_loop;
+    proton::work_queue *work_queue;
     bool ready, canceled;
 
     struct cancel_fn : public proton::void_function0 {
@@ -65,13 +65,13 @@ class scheduled_sender : public proton::messaging_handler {
     struct defer_cancel_fn : public proton::void_function0 {
         scheduled_sender& parent;
         defer_cancel_fn(scheduled_sender& ss) : parent(ss) {}
-        void operator()() { parent.event_loop->inject(parent.do_cancel); }
+        void operator()() { parent.work_queue->add(parent.do_cancel); }
     };
 
     struct defer_tick_fn : public proton::void_function0 {
         scheduled_sender& parent;
         defer_tick_fn(scheduled_sender& ss) : parent(ss) {}
-        void operator()() { parent.event_loop->inject(parent.do_tick); }
+        void operator()() { parent.work_queue->add(parent.do_tick); }
     };
 
     tick_fn do_tick;
@@ -96,7 +96,7 @@ class scheduled_sender : public proton::messaging_handler {
     }
 
     void on_sender_open(proton::sender & s) OVERRIDE {
-        event_loop = &proton::make_thread_safe(s).get()->event_loop();
+        work_queue = &proton::make_thread_safe(s).get()->work_queue();
 
         do_cancel = cancel_fn(*this, s);
         do_tick = tick_fn(*this, s);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index 625206f..21ff26c 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -44,7 +44,6 @@ set(qpid-proton-cpp-source
   src/endpoint.cpp
   src/error.cpp
   src/error_condition.cpp
-  src/event_loop.cpp
   src/handler.cpp
   src/io/connection_driver.cpp
   src/io/link_namer.cpp
@@ -77,6 +76,7 @@ set(qpid-proton-cpp-source
   src/url.cpp
   src/uuid.cpp
   src/value.cpp
+  src/work_queue.cpp
   )
 
 set_source_files_properties (

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/include/proton/container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/container.hpp b/proton-c/bindings/cpp/include/proton/container.hpp
index 0262e0f..383aa3c 100644
--- a/proton-c/bindings/cpp/include/proton/container.hpp
+++ b/proton-c/bindings/cpp/include/proton/container.hpp
@@ -224,7 +224,7 @@ class PN_CPP_CLASS_EXTERN container {
   friend class session_options;
   friend class receiver_options;
   friend class sender_options;
-  friend class event_loop;
+  friend class work_queue;
 };
 
 } // proton

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/include/proton/event_loop.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/event_loop.hpp b/proton-c/bindings/cpp/include/proton/event_loop.hpp
deleted file mode 100644
index 6d1646e..0000000
--- a/proton-c/bindings/cpp/include/proton/event_loop.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef PROTON_EVENT_LOOP_HPP
-#define PROTON_EVENT_LOOP_HPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "./fwd.hpp"
-#include "./internal/config.hpp"
-#include "./internal/export.hpp"
-#include "./internal/pn_unique_ptr.hpp"
-
-#include <functional>
-
-struct pn_connection_t;
-struct pn_session_t;
-struct pn_link_t;
-
-namespace proton {
-
-/// **Experimental** - A serial execution context.
-///
-/// Event handler functions associated with a single proton::connection are called in sequence.
-/// The connection's @ref event_loop allows you to "inject" extra work from any thread,
-/// and have it executed in the same sequence.
-///
-class PN_CPP_CLASS_EXTERN event_loop {
-    /// @cond internal
-    class impl;
-    event_loop& operator=(impl* i);
-    /// @endcond
-
-  public:
-    /// Create event_loop
-    PN_CPP_EXTERN event_loop();
-    PN_CPP_EXTERN event_loop(container&);
-
-    PN_CPP_EXTERN ~event_loop();
-
-#if PN_CPP_HAS_EXPLICIT_CONVERSIONS
-    /// When using C++11 (or later) you can use event_loop in a bool context
-    /// to indicate if there is an event loop set.
-    PN_CPP_EXTERN explicit operator bool() const { return bool(impl_); }
-#endif
-
-    /// No event loop set.
-    PN_CPP_EXTERN bool operator !() const { return !impl_; }
-
-    /// Arrange to have f() called in the event_loop's sequence: possibly
-    /// deferred, possibly in another thread.
-    ///
-    /// @return true if f() has or will be called, false if the event_loop is ended
-    /// and f() cannot be injected.
-    PN_CPP_EXTERN bool inject(void_function0& f);
-
-#if PN_CPP_HAS_STD_FUNCTION
-    /// @copydoc inject(void_function0&)
-    PN_CPP_EXTERN bool inject(std::function<void()> f);
-#endif
-
-  private:
-    PN_CPP_EXTERN static event_loop& get(pn_connection_t*);
-    PN_CPP_EXTERN static event_loop& get(pn_session_t*);
-    PN_CPP_EXTERN static event_loop& get(pn_link_t*);
-
-    internal::pn_unique_ptr<impl> impl_;
-
-    /// @cond INTERNAL
-  friend class container;
-  friend class io::connection_driver;
-  template <class T> friend class thread_safe;
-    /// @endcond
-};
-
-} // proton
-
-#endif // PROTON_EVENT_LOOP_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/include/proton/fwd.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/fwd.hpp b/proton-c/bindings/cpp/include/proton/fwd.hpp
index 54d7646..6ad216e 100644
--- a/proton-c/bindings/cpp/include/proton/fwd.hpp
+++ b/proton-c/bindings/cpp/include/proton/fwd.hpp
@@ -31,7 +31,7 @@ class container;
 class delivery;
 class error_condition;
 class event;
-class event_loop;
+class work_queue;
 class message;
 class message_id;
 class messaging_handler;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
index 8d0be85..5df210d 100644
--- a/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
+++ b/proton-c/bindings/cpp/include/proton/io/connection_driver.hpp
@@ -40,7 +40,7 @@
 
 namespace proton {
 
-class event_loop;
+class work_queue;
 class proton_handler;
 
 namespace io {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/thread_safe.hpp b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
index 608a1ca..e5f5303 100644
--- a/proton-c/bindings/cpp/include/proton/thread_safe.hpp
+++ b/proton-c/bindings/cpp/include/proton/thread_safe.hpp
@@ -25,10 +25,10 @@
 #include "./fwd.hpp"
 #include "./internal/config.hpp"
 #include "./connection.hpp"
-#include "./event_loop.hpp"
 #include "./function.hpp"
 #include "./internal/object.hpp"
 #include "./internal/type_traits.hpp"
+#include "./work_queue.hpp"
 
 #include <functional>
 
@@ -76,11 +76,11 @@ class thread_safe : private internal::pn_ptr_base, private internal::endpoint_tr
 
     ~thread_safe() {
         if (ptr()) {
-            if (!!event_loop()) {
+            if (!!work_queue()) {
 #if PN_CPP_HAS_STD_BIND
-                event_loop().inject(std::bind(&decref, ptr()));
+                work_queue().add(std::bind(&decref, ptr()));
 #else
-                event_loop().inject(*new inject_decref(ptr()));
+                work_queue().add(*new inject_decref(ptr()));
 #endif
             } else {
                 decref(ptr());
@@ -88,8 +88,8 @@ class thread_safe : private internal::pn_ptr_base, private internal::endpoint_tr
         }
     }
 
-    /// Get the event loop for this object.
-    class event_loop& event_loop() { return event_loop::get(ptr()); }
+    /// Get the work queue for this object.
+    class work_queue& work_queue() { return work_queue::get(ptr()); }
 
     /// Get the thread-unsafe proton object wrapped by this thread_safe<T>
     T unsafe() { return T(ptr()); }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/include/proton/work_queue.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/work_queue.hpp b/proton-c/bindings/cpp/include/proton/work_queue.hpp
new file mode 100644
index 0000000..7acd507
--- /dev/null
+++ b/proton-c/bindings/cpp/include/proton/work_queue.hpp
@@ -0,0 +1,94 @@
+#ifndef PROTON_WORK_QUEUE_HPP
+#define PROTON_WORK_QUEUE_HPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "./fwd.hpp"
+#include "./internal/config.hpp"
+#include "./internal/export.hpp"
+#include "./internal/pn_unique_ptr.hpp"
+
+#include <functional>
+
+struct pn_connection_t;
+struct pn_session_t;
+struct pn_link_t;
+
+namespace proton {
+
+/// **Experimental** - A serial execution context.
+///
+/// Event handler functions associated with a single proton::connection are called in sequence.
+/// The connection's @ref event_loop allows you to "inject" extra work from any thread,
+/// and have it executed in the same sequence.
+///
+class PN_CPP_CLASS_EXTERN work_queue {
+    /// @cond internal
+    class impl;
+    work_queue& operator=(impl* i);
+    /// @endcond
+
+  public:
+    /// Create event_loop
+    PN_CPP_EXTERN work_queue();
+    PN_CPP_EXTERN work_queue(container&);
+
+    PN_CPP_EXTERN ~work_queue();
+
+#if PN_CPP_HAS_EXPLICIT_CONVERSIONS
+    /// When using C++11 (or later) you can use event_loop in a bool context
+    /// to indicate if there is an event loop set.
+    PN_CPP_EXTERN explicit operator bool() const { return bool(impl_); }
+#endif
+
+    /// No event loop set.
+    PN_CPP_EXTERN bool operator !() const { return !impl_; }
+
+    /// Arrange to have f() called in the event_loop's sequence: possibly
+    /// deferred, possibly in another thread.
+    ///
+    /// @return true if f() has or will be called, false if the event_loop is ended
+    /// and f() cannot be injected.
+    PN_CPP_EXTERN bool add(void_function0& f);
+
+#if PN_CPP_HAS_STD_FUNCTION
+    /// @copydoc inject(void_function0&)
+    PN_CPP_EXTERN bool add(std::function<void()> f);
+#endif
+
+  private:
+    PN_CPP_EXTERN static work_queue& get(pn_connection_t*);
+    PN_CPP_EXTERN static work_queue& get(pn_session_t*);
+    PN_CPP_EXTERN static work_queue& get(pn_link_t*);
+
+    internal::pn_unique_ptr<impl> impl_;
+
+    /// @cond INTERNAL
+  friend class container;
+  friend class io::connection_driver;
+  template <class T> friend class thread_safe;
+    /// @endcond
+};
+
+} // proton
+
+#endif // PROTON_WORK_QUEUE_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/connection.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection.cpp b/proton-c/bindings/cpp/src/connection.cpp
index 11d5624..5432a42 100644
--- a/proton-c/bindings/cpp/src/connection.cpp
+++ b/proton-c/bindings/cpp/src/connection.cpp
@@ -25,12 +25,12 @@
 #include "proton/connection_options.hpp"
 #include "proton/container.hpp"
 #include "proton/error.hpp"
-#include "proton/event_loop.hpp"
 #include "proton/receiver_options.hpp"
 #include "proton/sender_options.hpp"
 #include "proton/session.hpp"
 #include "proton/session_options.hpp"
 #include "proton/transport.hpp"
+#include "proton/work_queue.hpp"
 
 #include "contexts.hpp"
 #include "msg.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/event_loop.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/event_loop.cpp b/proton-c/bindings/cpp/src/event_loop.cpp
deleted file mode 100644
index 5320011..0000000
--- a/proton-c/bindings/cpp/src/event_loop.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "proton/event_loop.hpp"
-
-#include "contexts.hpp"
-#include "proactor_container_impl.hpp"
-#include "proactor_event_loop_impl.hpp"
-
-#include <proton/session.h>
-#include <proton/link.h>
-
-namespace proton {
-
-event_loop::event_loop() {}
-event_loop::event_loop(container& c) { *this = container::impl::make_event_loop(c); }
-
-event_loop::~event_loop() {}
-
-event_loop& event_loop::operator=(impl* i) { impl_.reset(i); return *this; }
-
-bool event_loop::inject(void_function0& f) {
-    return impl_->inject(f);
-}
-
-#if PN_CPP_HAS_STD_FUNCTION
-bool event_loop::inject(std::function<void()> f) {
-    return impl_->inject(f);
-}
-#endif
-
-event_loop& event_loop::get(pn_connection_t* c) {
-    return connection_context::get(c).event_loop_;
-}
-
-event_loop& event_loop::get(pn_session_t* s) {
-    return get(pn_session_connection(s));
-}
-
-event_loop& event_loop::get(pn_link_t* l) {
-    return get(pn_link_session(l));
-}
-
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/include/contexts.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/contexts.hpp b/proton-c/bindings/cpp/src/include/contexts.hpp
index ab0661a..0c829db 100644
--- a/proton-c/bindings/cpp/src/include/contexts.hpp
+++ b/proton-c/bindings/cpp/src/include/contexts.hpp
@@ -22,7 +22,7 @@
  *
  */
 
-#include "proton/event_loop.hpp"
+#include "proton/work_queue.hpp"
 #include "proton/message.hpp"
 #include "proton/internal/pn_unique_ptr.hpp"
 
@@ -92,7 +92,7 @@ class connection_context : public context {
     messaging_handler* handler;
     internal::pn_unique_ptr<reconnect_timer> reconnect;
     listener_context* listener_context_;
-    event_loop event_loop_;
+    work_queue work_queue_;
 };
 
 class listener_context : public context {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
index 4b84a6e..9b4be11 100644
--- a/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
+++ b/proton-c/bindings/cpp/src/include/proactor_container_impl.hpp
@@ -28,12 +28,12 @@
 #include "proton/connection_options.hpp"
 #include "proton/duration.hpp"
 #include "proton/error_condition.hpp"
-#include "proton/event_loop.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/receiver.hpp"
 #include "proton/receiver_options.hpp"
 #include "proton/sender.hpp"
 #include "proton/sender_options.hpp"
+#include "proton/work_queue.hpp"
 
 #include "proton_bits.hpp"
 
@@ -79,12 +79,12 @@ class container::impl {
 #endif
     template <class T> static void set_handler(T s, messaging_handler* h);
     template <class T> static messaging_handler* get_handler(T s);
-    static event_loop::impl* make_event_loop(container&);
+    static work_queue::impl* make_work_queue(container&);
 
   private:
-    class common_event_loop;
-    class connection_event_loop;
-    class container_event_loop;
+    class common_work_queue;
+    class connection_work_queue;
+    class container_work_queue;
     pn_listener_t* listen_common_lh(const std::string&);
     connection connect_common(const std::string&, const connection_options&);
 
@@ -95,10 +95,10 @@ class container::impl {
 
     container& container_;
 
-    typedef std::set<container_event_loop*> event_loops;
-    event_loops event_loops_;
-    container_event_loop* add_event_loop();
-    void remove_event_loop(container_event_loop*);
+    typedef std::set<container_work_queue*> work_queues;
+    work_queues work_queues_;
+    container_work_queue* add_work_queue();
+    void remove_work_queue(container_work_queue*);
     struct scheduled {
         timestamp time; // duration from epoch for task
 #if PN_CPP_HAS_STD_FUNCTION

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
deleted file mode 100644
index 82ec129..0000000
--- a/proton-c/bindings/cpp/src/include/proactor_event_loop_impl.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef PROTON_CPP_EVENT_LOOP_IMPL_HPP
-#define PROTON_CPP_EVENT_LOOP_IMPL_HPP
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include "proton/fwd.hpp"
-#include "proton/internal/config.hpp"
-
-namespace proton {
-
-class event_loop::impl {
-  public:
-    virtual ~impl() {};
-    virtual bool inject(void_function0& f) = 0;
-#if PN_CPP_HAS_STD_FUNCTION
-    virtual bool inject(std::function<void()> f) = 0;
-#endif
-    virtual void run_all_jobs() = 0;
-    virtual void finished() = 0;
-};
-
-}
-
-#endif // PROTON_CPP_EVENT_LOOP_IMPL_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
new file mode 100644
index 0000000..57fc4c0
--- /dev/null
+++ b/proton-c/bindings/cpp/src/include/proactor_work_queue_impl.hpp
@@ -0,0 +1,43 @@
+#ifndef PROTON_CPP_EVENT_LOOP_IMPL_HPP
+#define PROTON_CPP_EVENT_LOOP_IMPL_HPP
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "proton/fwd.hpp"
+#include "proton/internal/config.hpp"
+
+namespace proton {
+
+class work_queue::impl {
+  public:
+    virtual ~impl() {};
+    virtual bool inject(void_function0& f) = 0;
+#if PN_CPP_HAS_STD_FUNCTION
+    virtual bool inject(std::function<void()> f) = 0;
+#endif
+    virtual void run_all_jobs() = 0;
+    virtual void finished() = 0;
+};
+
+}
+
+#endif // PROTON_CPP_EVENT_LOOP_IMPL_HPP

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/io/connection_driver.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/io/connection_driver.cpp b/proton-c/bindings/cpp/src/io/connection_driver.cpp
index 58af052..d907e5c 100644
--- a/proton-c/bindings/cpp/src/io/connection_driver.cpp
+++ b/proton-c/bindings/cpp/src/io/connection_driver.cpp
@@ -20,10 +20,10 @@
 #include "proton/io/connection_driver.hpp"
 
 #include "proton/container.hpp"
-#include "proton/event_loop.hpp"
 #include "proton/error.hpp"
 #include "proton/messaging_handler.hpp"
 #include "proton/uuid.hpp"
+#include "proton/work_queue.hpp"
 
 #include "contexts.hpp"
 #include "messaging_adapter.hpp"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/proactor_container_impl.cpp b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
index 4d526f2..78ccabf 100644
--- a/proton-c/bindings/cpp/src/proactor_container_impl.cpp
+++ b/proton-c/bindings/cpp/src/proactor_container_impl.cpp
@@ -18,7 +18,7 @@
  */
 
 #include "proactor_container_impl.hpp"
-#include "proactor_event_loop_impl.hpp"
+#include "proactor_work_queue_impl.hpp"
 
 #include "proton/error_condition.hpp"
 #include "proton/function.hpp"
@@ -43,9 +43,9 @@
 
 namespace proton {
 
-class container::impl::common_event_loop : public event_loop::impl {
+class container::impl::common_work_queue : public work_queue::impl {
   public:
-    common_event_loop(): finished_(false) {}
+    common_work_queue(): finished_(false) {}
 
 #if PN_CPP_HAS_STD_FUNCTION
     typedef std::vector<std::function<void()> > jobs;
@@ -61,7 +61,7 @@ class container::impl::common_event_loop : public event_loop::impl {
 };
 
 #if PN_CPP_HAS_STD_FUNCTION
-void container::impl::common_event_loop::run_all_jobs() {
+void container::impl::common_work_queue::run_all_jobs() {
     decltype(jobs_) j;
     {
         std::swap(j, jobs_);
@@ -72,7 +72,7 @@ void container::impl::common_event_loop::run_all_jobs() {
     } catch (...) {};
 }
 #else
-void container::impl::common_event_loop::run_all_jobs() {
+void container::impl::common_work_queue::run_all_jobs() {
     // Run queued work, but ignore any exceptions
     for (jobs::iterator f = jobs_.begin(); f != jobs_.end(); ++f) try {
         (**f)();
@@ -82,9 +82,9 @@ void container::impl::common_event_loop::run_all_jobs() {
 }
 #endif
 
-class container::impl::connection_event_loop : public common_event_loop {
+class container::impl::connection_work_queue : public common_work_queue {
   public:
-    connection_event_loop(pn_connection_t* c): connection_(c) {}
+    connection_work_queue(pn_connection_t* c): connection_(c) {}
 
     bool inject(void_function0& f);
 #if PN_CPP_HAS_STD_FUNCTION
@@ -95,7 +95,7 @@ class container::impl::connection_event_loop : public common_event_loop {
 };
 
 #if PN_CPP_HAS_STD_FUNCTION
-bool container::impl::connection_event_loop::inject(std::function<void()> f) {
+bool container::impl::connection_work_queue::inject(std::function<void()> f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
     if (finished_) return false;
@@ -104,11 +104,11 @@ bool container::impl::connection_event_loop::inject(std::function<void()> f) {
     return true;
 }
 
-bool container::impl::connection_event_loop::inject(proton::void_function0& f) {
+bool container::impl::connection_work_queue::inject(proton::void_function0& f) {
     return inject([&f]() { f(); });
 }
 #else
-bool container::impl::connection_event_loop::inject(proton::void_function0& f) {
+bool container::impl::connection_work_queue::inject(proton::void_function0& f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
     if (finished_) return false;
@@ -118,10 +118,10 @@ bool container::impl::connection_event_loop::inject(proton::void_function0& f) {
 }
 #endif
 
-class container::impl::container_event_loop : public common_event_loop {
+class container::impl::container_work_queue : public common_work_queue {
   public:
-    container_event_loop(container::impl& c): container_(c) {}
-    ~container_event_loop() { container_.remove_event_loop(this); }
+    container_work_queue(container::impl& c): container_(c) {}
+    ~container_work_queue() { container_.remove_work_queue(this); }
 
     bool inject(void_function0& f);
 #if PN_CPP_HAS_STD_FUNCTION
@@ -132,7 +132,7 @@ class container::impl::container_event_loop : public common_event_loop {
 };
 
 #if PN_CPP_HAS_STD_FUNCTION
-bool container::impl::container_event_loop::inject(std::function<void()> f) {
+bool container::impl::container_work_queue::inject(std::function<void()> f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
     if (finished_) return false;
@@ -141,11 +141,11 @@ bool container::impl::container_event_loop::inject(std::function<void()> f) {
     return true;
 }
 
-bool container::impl::container_event_loop::inject(proton::void_function0& f) {
+bool container::impl::container_work_queue::inject(proton::void_function0& f) {
     return inject([&f]() { f(); });
 }
 #else
-bool container::impl::container_event_loop::inject(proton::void_function0& f) {
+bool container::impl::container_work_queue::inject(proton::void_function0& f) {
     // Note this is an unbounded work queue.
     // A resource-safe implementation should be bounded.
     if (finished_) return false;
@@ -155,8 +155,8 @@ bool container::impl::container_event_loop::inject(proton::void_function0& f) {
 }
 #endif
 
-class event_loop::impl* container::impl::make_event_loop(container& c) {
-    return c.impl_->add_event_loop();
+class work_queue::impl* container::impl::make_work_queue(container& c) {
+    return c.impl_->add_work_queue();
 }
 
 container::impl::impl(container& c, const std::string& id, messaging_handler* mh)
@@ -172,14 +172,14 @@ container::impl::~impl() {
     pn_proactor_free(proactor_);
 }
 
-container::impl::container_event_loop* container::impl::add_event_loop() {
-    container_event_loop* c = new container_event_loop(*this);
-    event_loops_.insert(c);
+container::impl::container_work_queue* container::impl::add_work_queue() {
+    container_work_queue* c = new container_work_queue(*this);
+    work_queues_.insert(c);
     return c;
 }
 
-void container::impl::remove_event_loop(container::impl::container_event_loop* l) {
-    event_loops_.erase(l);
+void container::impl::remove_work_queue(container::impl::container_work_queue* l) {
+    work_queues_.erase(l);
 }
 
 proton::connection container::impl::connect_common(
@@ -198,7 +198,7 @@ proton::connection container::impl::connect_common(
     connection_context& cc(connection_context::get(pnc));
     cc.container = &container_;
     cc.handler = mh;
-    cc.event_loop_ = new container::impl::connection_event_loop(pnc);
+    cc.work_queue_ = new container::impl::connection_work_queue(pnc);
 
     pn_connection_set_container(pnc, id_.c_str());
     pn_connection_set_hostname(pnc, url.host().c_str());
@@ -344,7 +344,7 @@ bool container::impl::handle(pn_event_t* event) {
     // If we have any pending connection work, do it now
     pn_connection_t* c = pn_event_connection(event);
     if (c) {
-        event_loop::impl* loop = connection_context::get(c).event_loop_.impl_.get();
+        work_queue::impl* loop = connection_context::get(c).work_queue_.impl_.get();
         loop->run_all_jobs();
     }
 
@@ -367,7 +367,7 @@ bool container::impl::handle(pn_event_t* event) {
         // Run every container event loop job
         // This is not at all efficient and single threads all these jobs, but it does correctly
         // serialise them
-        for (event_loops::iterator loop = event_loops_.begin(); loop!=event_loops_.end(); ++loop) {
+        for (work_queues::iterator loop = work_queues_.begin(); loop!=work_queues_.end(); ++loop) {
             (*loop)->run_all_jobs();
         }
         return false;
@@ -392,7 +392,7 @@ bool container::impl::handle(pn_event_t* event) {
         cc.container = &container_;
         cc.listener_context_ = &lc;
         cc.handler = opts.handler();
-        cc.event_loop_ = new container::impl::connection_event_loop(c);
+        cc.work_queue_ = new container::impl::connection_work_queue(c);
         pn_listener_accept(l, c);
         return false;
     }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/45d5612b/proton-c/bindings/cpp/src/work_queue.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/work_queue.cpp b/proton-c/bindings/cpp/src/work_queue.cpp
new file mode 100644
index 0000000..961e5f0
--- /dev/null
+++ b/proton-c/bindings/cpp/src/work_queue.cpp
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "proton/work_queue.hpp"
+
+#include "contexts.hpp"
+#include "proactor_container_impl.hpp"
+#include "proactor_work_queue_impl.hpp"
+
+#include <proton/session.h>
+#include <proton/link.h>
+
+namespace proton {
+
+work_queue::work_queue() {}
+work_queue::work_queue(container& c) { *this = container::impl::make_work_queue(c); }
+
+work_queue::~work_queue() {}
+
+work_queue& work_queue::operator=(impl* i) { impl_.reset(i); return *this; }
+
+bool work_queue::add(void_function0& f) {
+    return impl_->inject(f);
+}
+
+#if PN_CPP_HAS_STD_FUNCTION
+bool work_queue::add(std::function<void()> f) {
+    return impl_->inject(f);
+}
+#endif
+
+work_queue& work_queue::get(pn_connection_t* c) {
+    return connection_context::get(c).work_queue_;
+}
+
+work_queue& work_queue::get(pn_session_t* s) {
+    return get(pn_session_connection(s));
+}
+
+work_queue& work_queue::get(pn_link_t* l) {
+    return get(pn_link_session(l));
+}
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[19/20] qpid-proton git commit: PROTON-1400: [C++ example] Fix ssl test example to not rely on catching a specific exception thrown out of container::run.

Posted by as...@apache.org.
PROTON-1400: [C++ example] Fix ssl test example to not rely on catching a specific exception thrown out of container::run.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2a606538
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2a606538
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2a606538

Branch: refs/heads/master
Commit: 2a606538336a15da4de38684b34432e4157a02b9
Parents: e4eca5c
Author: Andrew Stitcher <as...@apache.org>
Authored: Thu Jul 13 08:42:52 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/ssl.cpp | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2a606538/examples/cpp/ssl.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl.cpp b/examples/cpp/ssl.cpp
index 85dfa48..166bd61 100644
--- a/examples/cpp/ssl.cpp
+++ b/examples/cpp/ssl.cpp
@@ -50,10 +50,11 @@ ssl_certificate platform_certificate(const std::string &base_name, const std::st
 std::string find_CN(const std::string &);
 
 namespace {
-    std::string verify_full("full");  // Normal verification
-    std::string verify_noname("noname"); // Skip matching host name against the certificate
-    std::string verify_fail("fail");  // Force name mismatch failure
+    const std::string verify_full("full");  // Normal verification
+    const std::string verify_noname("noname"); // Skip matching host name against the certificate
+    const std::string verify_fail("fail");  // Force name mismatch failure
     std::string verify(verify_full);  // Default for example
+    bool verify_failed(false);
     std::string cert_directory;
 
     class example_cert_error : public std::runtime_error
@@ -137,8 +138,10 @@ class hello_world_direct : public proton::messaging_handler {
 
     void on_transport_error(proton::transport &t) OVERRIDE {
         std::string err = t.error().what();
-        if (err.find("certificate"))
+        if (err.find("certificate")) {
+            verify_failed = true;
             throw example_cert_error(err);
+        }
     }
 
     void on_sendable(proton::sender &s) OVERRIDE {
@@ -179,13 +182,15 @@ int main(int argc, char **argv) {
         hello_world_direct hwd(address);
         proton::default_container(hwd).run();
         return 0;
-    } catch (const example_cert_error& ce) {
-        if (verify == verify_fail) {
-            std::cout << "Expected failure of connection with wrong peer name: " << ce.what() << std::endl;
-            return 0;
-        }
-        std::cerr << "unexpected internal certificate failure: " << ce.what() << std::endl;
     } catch (const std::exception& e) {
+        if (verify_failed) {
+            if (verify == verify_fail) {
+                std::cout << "Expected failure of connection with wrong peer name: " << e.what() << std::endl;
+                return 0;
+            } else {
+                std::cerr << "unexpected internal certificate failure: ";
+            }
+        }
         std::cerr << e.what() << std::endl;
     }
     return 1;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[11/20] qpid-proton git commit: PROTON-1400: [C++ example] Rework broker to use container event loops

Posted by as...@apache.org.
PROTON-1400: [C++ example] Rework broker to use container event loops


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2b2666b2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2b2666b2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2b2666b2

Branch: refs/heads/master
Commit: 2b2666b2758c5d493d07441a3eaad4a52d2bfbe1
Parents: 570d0a1
Author: Andrew Stitcher <as...@apache.org>
Authored: Tue Mar 28 13:45:28 2017 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Fri Jul 21 12:50:06 2017 -0400

----------------------------------------------------------------------
 examples/cpp/broker.cpp | 553 +++++++++++++++++++++++++++++--------------
 1 file changed, 377 insertions(+), 176 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2b2666b2/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 5b0982b..2fbe077 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -25,6 +25,7 @@
 #include <proton/default_container.hpp>
 #include <proton/delivery.hpp>
 #include <proton/error_condition.hpp>
+#include <proton/function.hpp>
 #include <proton/listen_handler.hpp>
 #include <proton/listener.hpp>
 #include <proton/message.hpp>
@@ -36,238 +37,436 @@
 #include <proton/target_options.hpp>
 #include <proton/thread_safe.hpp>
 #include <proton/tracker.hpp>
+#include <proton/transport.hpp>
 
-#include <atomic>
 #include <deque>
-#include <functional>
 #include <iostream>
 #include <map>
-#include <mutex>
 #include <string>
 
 #include "fake_cpp11.hpp"
 
-// Thread safe queue.
-// Stores messages, notifies subscribed connections when there is data.
-class queue {
-  public:
-    queue(const std::string& name) : name_(name) {}
+// This is a simplified model for a message broker, that only allows for messages to go to a
+// single receiver.
+//
+// Queues are only created and never destroyed
+//
+// Broker Entities (that need to be individually serialised)
+// QueueManager - Creates new queues, finds queues
+// Queue        - Queues msgs, records subscribers, sends msgs to subscribers
+// Connection   - Receives Messages from network, sends messages to network.
+
+// Work
+// FindQueue(queueName, connection) - From a Connection to the QueueManager
+//     This will create the queue if it doesn't already exist and send a BoundQueue
+//     message back to the connection.
+// BoundQueue(queue) - From the QueueManager to a Connection
+//
+// QueueMsg(msg)        - From a Connection (receiver) to a Queue
+// Subscribe(sender)    - From a Connection (sender) to a Queue
+// Flow(sender, credit) - From a Connection (sender) to a Queue
+// Unsubscribe(sender)  - From a Connection (sender) to a Queue
+//
+// SendMsg(msg)   - From a Queue to a Connection (sender)
+// Unsubscribed() - From a Queue to a Connection (sender)
+
+// Utilities to make injecting member functions palatable in C++03
+template <class T>
+struct work0 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)();
+
+    work0(T& h, void (T::* a)()) :
+        holder_(h), fn_(a) {}
+
+    void operator()() OVERRIDE {
+        (holder_.*fn_)();
+        delete this;
+    }
+};
+
+template <class T, class A>
+struct work1 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)(A);
+    A a_;
+
+    work1(T& h, void (T::* t)(A), A a) :
+        holder_(h), fn_(t), a_(a) {}
+
+    void operator()() OVERRIDE {
+        (holder_.*fn_)(a_);
+        delete this;
+    }
+};
+
+template <class T, class A, class B>
+struct work2 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)(A, B);
+    A a_;
+    B b_;
+
+    work2(T& h, void (T::* t)(A, B), A a, B b) :
+        holder_(h), fn_(t), a_(a), b_(b) {}
+
+    void operator()() OVERRIDE {
+        (holder_.*fn_)(a_, b_);
+        delete this;
+    }
+};
+
+template <class T, class A, class B, class C>
+struct work3 : public proton::void_function0 {
+    T& holder_;
+    void (T::* fn_)(A, B, C);
+    A a_;
+    B b_;
+    C c_;
+
+    work3(T& h, void (T::* t)(A, B, C), A a, B b, C c) :
+        holder_(h), fn_(t), a_(a), b_(b), c_(c) {}
+
+    void operator()() OVERRIDE {
+        (holder_.*fn_)(a_, b_, c_);
+        delete this;
+    }
+};
+
+template <class T>
+void defer(T* t, void (T::*f)()) {
+    work0<T>* w = new work0<T>(*t, f);
+    t->inject(*w);
+}
+
+template <class T, class A>
+void defer(T* t, void (T::*f)(A), A a) {
+    work1<T, A>* w = new work1<T, A>(*t, f, a);
+    t->inject(*w);
+}
+
+template <class T, class A, class B>
+void defer(T* t, void (T::*f)(A, B), A a, B b) {
+    work2<T, A, B>* w = new work2<T, A, B>(*t, f, a, b);
+    t->inject(*w);
+}
+
+template <class T, class A, class B, class C>
+void defer(T* t, void (T::*f)(A, B, C), A a, B b, C c) {
+    work3<T, A, B, C>* w = new work3<T, A, B, C>(*t, f, a, b, c);
+    t->inject(*w);
+}
+
+// Simple debug output
+bool verbose;
+#define DOUT(x) do {if (verbose) {x};} while (false)
+
+class Queue;
+class Sender;
 
-    std::string name() const { return name_; }
+typedef std::map<proton::sender, Sender*> senders;
 
-    // Push a message onto the queue.
-    // If the queue was previously empty, notify subscribers it has messages.
-    // Called from receiver's connection.
-    void push(const proton::message &m) {
-        std::lock_guard<std::mutex> g(lock_);
+class Sender : public proton::messaging_handler {
+    friend class connection_handler;
+
+    proton::sender sender_;
+    senders& senders_;
+    proton::event_loop& event_loop_;
+    std::string queue_name_;
+    Queue* queue_;
+    int pending_credit_;
+
+    // Messaging handlers
+    void on_sendable(proton::sender &sender) OVERRIDE;
+    void on_sender_close(proton::sender &sender) OVERRIDE;
+
+public:
+    Sender(proton::sender s, senders& ss) :
+        sender_(s), senders_(ss), event_loop_(make_thread_safe(s).get()->event_loop()), queue_(0), pending_credit_(0)
+    {}
+
+    void inject(proton::void_function0& f) {
+        event_loop_.inject(f);
+    }
+
+
+    void boundQueue(Queue* q, std::string qn);
+    void sendMsg(proton::message m) {
+        DOUT(std::cerr << "Sender:   " << this << " sending\n";);
+        sender_.send(m);
+    }
+    void unsubscribed() {
+        DOUT(std::cerr << "Sender:   " << this << " deleting\n";);
+        delete this;
+    }
+};
+
+// Queue - round robin subscriptions
+class Queue {
+    proton::event_loop event_loop_;
+    const std::string name_;
+    std::deque<proton::message> messages_;
+    typedef std::map<Sender*, int> subscriptions; // With credit
+    subscriptions subscriptions_;
+    subscriptions::iterator current_;
+
+    void tryToSend() {
+        DOUT(std::cerr << "Queue:    " << this << " tryToSend: " << subscriptions_.size(););
+        // Starting at current_, send messages to subscriptions with credit:
+        // After each send try to find another subscription; Wrap around;
+        // Finish when we run out of messages or credit.
+        size_t outOfCredit = 0;
+        while (!messages_.empty() && outOfCredit<subscriptions_.size()) {
+            // If we got the end (or haven't started yet) start at the beginning
+            if (current_==subscriptions_.end()) {
+                current_=subscriptions_.begin();
+            }
+            // If we have credit send the message
+            DOUT(std::cerr << "(" << current_->second << ") ";);
+            if (current_->second>0) {
+                DOUT(std::cerr << current_->first << " ";);
+                defer(current_->first, &Sender::sendMsg, messages_.front());
+                messages_.pop_front();
+                --current_->second;
+                ++current_;
+            } else {
+                ++outOfCredit;
+            }
+        }
+        DOUT(std::cerr << "\n";);
+    }
+
+public:
+    Queue(proton::container& c, const std::string& n) :
+        event_loop_(c), name_(n), current_(subscriptions_.end())
+    {}
+
+    void inject(proton::void_function0& f) {
+        event_loop_.inject(f);
+    }
+
+    void queueMsg(proton::message m) {
+        DOUT(std::cerr << "Queue:    " << this << "(" << name_ << ") queueMsg\n";);
         messages_.push_back(m);
-        if (messages_.size() == 1) { // Non-empty, notify subscribers
-            for (auto cb : callbacks_)
-                cb(this);
-            callbacks_.clear();
+        tryToSend();
+    }
+    void flow(Sender* s, int c) {
+        DOUT(std::cerr << "Queue:    " << this << "(" << name_ << ") flow: " << c << " to " << s << "\n";);
+        subscriptions_[s] = c;
+        tryToSend();
+    }
+    void subscribe(Sender* s) {
+        DOUT(std::cerr << "Queue:    " << this << "(" << name_ << ") subscribe Sender: " << s << "\n";);
+        subscriptions_[s] = 0;
+    }
+    void unsubscribe(Sender* s) {
+        DOUT(std::cerr << "Queue:    " << this << "(" << name_ << ") unsubscribe Sender: " << s << "\n";);
+        // If we're about to erase the current subscription move on
+        if (current_ != subscriptions_.end() && current_->first==s) ++current_;
+        subscriptions_.erase(s);
+        defer(s, &Sender::unsubscribed);
+    }
+};
+
+// We have credit to send a message.
+void Sender::on_sendable(proton::sender &sender) {
+    if (queue_) {
+        defer(queue_, &Queue::flow, this, sender.credit());
+    } else {
+        pending_credit_ = sender.credit();
+    }
+}
+
+void Sender::on_sender_close(proton::sender &sender) {
+    if (queue_) {
+        defer(queue_, &Queue::unsubscribe, this);
+    } else {
+        // TODO: Is it possible to be closed before we get the queue allocated?
+        // If so, we should have a way to mark the sender deleted, so we can delete
+        // on queue binding
+    }
+    senders_.erase(sender);
+}
+
+void Sender::boundQueue(Queue* q, std::string qn) {
+    DOUT(std::cerr << "Sender:   " << this << " bound to Queue: " << q <<"(" << qn << ")\n";);
+    queue_ = q;
+    queue_name_ = qn;
+
+    defer(q, &Queue::subscribe, this);
+    sender_.open(proton::sender_options()
+        .source((proton::source_options().address(queue_name_)))
+        .handler(*this));
+    if (pending_credit_>0) {
+        defer(queue_, &Queue::flow, this, pending_credit_);
+    }
+    std::cout << "sending from " << queue_name_ << std::endl;
+}
+
+class Receiver : public proton::messaging_handler {
+    friend class connection_handler;
+
+    proton::receiver receiver_;
+    proton::event_loop& event_loop_;
+    Queue* queue_;
+    std::deque<proton::message> messages_;
+
+    // A message is received.
+    void on_message(proton::delivery &, proton::message &m) OVERRIDE {
+        messages_.push_back(m);
+
+        if (queue_) {
+            queueMsgs();
         }
     }
 
-    // If the queue is not empty, pop a message into m and return true.
-    // Otherwise save callback to be called when there are messages and return false.
-    // Called from sender's connection.
-    bool pop(proton::message& m, std::function<void(queue*)> callback) {
-        std::lock_guard<std::mutex> g(lock_);
-        if (messages_.empty()) {
-            callbacks_.push_back(callback);
-            return false;
-        } else {
-            m = std::move(messages_.front());
+    void queueMsgs() {
+        DOUT(std::cerr << "Receiver: " << this << " queueing " << messages_.size() << " msgs to: " << queue_ << "\n";);
+        while (!messages_.empty()) {
+            defer(queue_, &Queue::queueMsg, messages_.front());
             messages_.pop_front();
-            return true;
         }
     }
 
-  private:
-    const std::string name_;
-    std::mutex lock_;
-    std::deque<proton::message> messages_;
-    std::vector<std::function<void(queue*)> > callbacks_;
+public:
+    Receiver(proton::receiver r) :
+        receiver_(r), event_loop_(make_thread_safe(r).get()->event_loop()), queue_(0)
+    {}
+
+    void inject(proton::void_function0& f) {
+        event_loop_.inject(f);
+    }
+
+    void boundQueue(Queue* q, std::string qn) {
+        DOUT(std::cerr << "Receiver: " << this << " bound to Queue: " << q << "(" << qn << ")\n";);
+        queue_ = q;
+        receiver_.open(proton::receiver_options()
+            .source((proton::source_options().address(qn)))
+            .handler(*this));
+        std::cout << "receiving to " << qn << std::endl;
+
+        queueMsgs();
+    }
 };
 
-/// Thread safe map of queues.
-class queues {
-  public:
-    queues() : next_id_(0) {}
+class QueueManager {
+    proton::container& container_;
+    proton::event_loop event_loop_;
+    typedef std::map<std::string, Queue*> queues;
+    queues queues_;
+    int next_id_; // Use to generate unique queue IDs.
 
-    // Get or create the named queue.
-    queue* get(const std::string& name) {
-        std::lock_guard<std::mutex> g(lock_);
-        auto i = queues_.insert(queue_map::value_type(name, nullptr)).first;
-        if (!i->second)
-            i->second.reset(new queue(name));
-        return i->second.get();
+public:
+    QueueManager(proton::container& c) :
+        container_(c), event_loop_(c), next_id_(0)
+    {}
+
+    void inject(proton::void_function0& f) {
+        event_loop_.inject(f);
     }
 
-    // Create a dynamic queue with a unique name.
-    queue* dynamic() {
-        std::ostringstream os;
-        os << "_dynamic_" << next_id_++;
-        return get(os.str());
+    template <class T>
+    void findQueue(T& connection, std::string& qn) {
+        if (qn.empty()) {
+            // Dynamic queue creation
+            std::ostringstream os;
+            os << "_dynamic_" << next_id_++;
+            qn = os.str();
+        }
+        Queue* q = 0;
+        queues::iterator i = queues_.find(qn);
+        if (i==queues_.end()) {
+            q = new Queue(container_, qn);
+            queues_[qn] = q;
+        } else {
+            q = i->second;
+        }
+        defer(&connection, &T::boundQueue, q, qn);
     }
 
-  private:
-    typedef std::map<std::string, std::unique_ptr<queue> > queue_map;
+    void findQueueSender(Sender* s, std::string qn) {
+        findQueue(*s, qn);
+    }
 
-    std::mutex lock_;
-    queue_map queues_;
-    std::atomic<int> next_id_; // Use to generate unique queue IDs.
+    void findQueueReceiver(Receiver* r, std::string qn) {
+        findQueue(*r, qn);
+    }
 };
 
-/// Broker connection handler. Things to note:
-///
-/// 1. Each handler manages a single connection.
-///
-/// 2. For a *single connection* calls to proton::handler functions and calls to
-/// function objects passed to proton::event_loop::inject() are serialized,
-/// i.e. never called concurrently. Handlers can have per-connection state
-/// without needing locks.
-///
-/// 3. Handler/injected functions for *different connections* can be called
-/// concurrently. Resources used by multiple connections (e.g. the queues in
-/// this example) must be thread-safe.
-///
-/// 4. You can 'inject' work to be done sequentially using a connection's
-/// proton::event_loop. In this example, we create a std::function callback
-/// that we pass to queues, so they can notify us when they have messages.
-///
-class broker_connection_handler : public proton::messaging_handler {
-  public:
-    broker_connection_handler(queues& qs) : queues_(qs) {}
+class connection_handler : public proton::messaging_handler {
+    QueueManager& queue_manager_;
+    senders senders_;
 
-    void on_connection_open(proton::connection& c) OVERRIDE {
-        // Create the has_messages callback for queue subscriptions.
-        //
-        // Make a std::shared_ptr to a thread_safe handle for our proton::connection.
-        // The connection's proton::event_loop will remain valid as a shared_ptr exists.
-        std::shared_ptr<proton::thread_safe<proton::connection> > ts_c = make_shared_thread_safe(c);
-
-        // Make a lambda function to inject a call to this->has_messages() via the proton::event_loop.
-        // The function is bound to a shared_ptr so this is safe. If the connection has already closed
-        // proton::event_loop::inject() will drop the callback.
-        has_messages_callback_ = [this, ts_c](queue* q) mutable {
-            ts_c->event_loop().inject(
-                std::bind(&broker_connection_handler::has_messages, this, q));
-        };
+public:
+    connection_handler(QueueManager& qm) :
+        queue_manager_(qm)
+    {}
 
+    void on_connection_open(proton::connection& c) OVERRIDE {
         c.open();            // Accept the connection
     }
 
     // A sender sends messages from a queue to a subscriber.
     void on_sender_open(proton::sender &sender) OVERRIDE {
-        queue *q = sender.source().dynamic() ?
-            queues_.dynamic() : queues_.get(sender.source().address());
-        sender.open(proton::sender_options().source((proton::source_options().address(q->name()))));
-        std::cout << "sending from " << q->name() << std::endl;
-    }
-
-    // We have credit to send a message.
-    void on_sendable(proton::sender &s) OVERRIDE {
-        queue* q = sender_queue(s);
-        if (!do_send(q, s))     // Queue is empty, save ourselves in the blocked set.
-            blocked_.insert(std::make_pair(q, s));
+        std::string qn = sender.source().dynamic() ? "" : sender.source().address();
+        Sender* s = new Sender(sender, senders_);
+        senders_[sender] = s;
+        defer(&queue_manager_, &QueueManager::findQueueSender, s, qn);
     }
 
     // A receiver receives messages from a publisher to a queue.
-    void on_receiver_open(proton::receiver &r) OVERRIDE {
-        std::string qname = r.target().address();
+    void on_receiver_open(proton::receiver &receiver) OVERRIDE {
+        std::string qname = receiver.target().address();
         if (qname == "shutdown") {
             std::cout << "broker shutting down" << std::endl;
             // Sending to the special "shutdown" queue stops the broker.
-            r.connection().container().stop(
+            receiver.connection().container().stop(
                 proton::error_condition("shutdown", "stop broker"));
         } else {
-            r.open(proton::receiver_options().target(proton::target_options().address(qname)));
-            std::cout << "receiving to " << qname << std::endl;
+            if (qname.empty()) {
+                DOUT(std::cerr << "ODD - trying to attach to a empty address\n";);
+            }
+            Receiver* r = new Receiver(receiver);
+            defer(&queue_manager_, &QueueManager::findQueueReceiver, r, qname);
         }
     }
 
-    // A message is received.
-    void on_message(proton::delivery &d, proton::message &m) OVERRIDE {
-        std::string qname = d.receiver().target().address();
-        queues_.get(qname)->push(m);
-    }
-
     void on_session_close(proton::session &session) OVERRIDE {
-        // Erase all blocked senders that belong to session.
-        auto predicate = [session](const proton::sender& s) {
-            return s.session() == session;
-        };
-        erase_sender_if(blocked_.begin(), blocked_.end(), predicate);
-    }
-
-    void on_sender_close(proton::sender &sender) OVERRIDE {
-        // Erase sender from the blocked set.
-        auto range = blocked_.equal_range(sender_queue(sender));
-        auto predicate = [sender](const proton::sender& s) { return s == sender; };
-        erase_sender_if(range.first, range.second, predicate);
+        // Unsubscribe all senders that belong to session.
+        for (proton::sender_iterator i = session.senders().begin(); i != session.senders().end(); ++i) {
+            senders::iterator j = senders_.find(*i);
+            if (j == senders_.end()) continue;
+            Sender* s = j->second;
+            if (s->queue_) {
+                defer(s->queue_, &Queue::unsubscribe, s);
+            }
+            senders_.erase(j);
+        }
     }
 
     void on_error(const proton::error_condition& e) OVERRIDE {
         std::cerr << "error: " << e.what() << std::endl;
     }
-    // The container calls on_transport_close() last.
-    void on_transport_close(proton::transport&) OVERRIDE {
-        delete this;            // All done.
-    }
 
-  private:
-    typedef std::multimap<queue*, proton::sender> blocked_map;
-
-    // Get the queue associated with a sender.
-    queue* sender_queue(const proton::sender& s) {
-        return queues_.get(s.source().address()); // Thread safe.
-    }
-
-    // Only called if we have credit. Return true if we sent a message.
-    bool do_send(queue* q, proton::sender &s) {
-        proton::message m;
-        bool popped =  q->pop(m, has_messages_callback_);
-        if (popped)
-            s.send(m);
-        /// if !popped the queue has saved the callback for later.
-        return popped;
-    }
-
-    // Called via the connection's proton::event_loop when q has messages.
-    // Try all the blocked senders.
-    void has_messages(queue* q) {
-        auto range = blocked_.equal_range(q);
-        for (auto i = range.first; i != range.second;) {
-            if (i->second.credit() <= 0 || do_send(q, i->second))
-                i = blocked_.erase(i); // No credit or send was successful, stop blocked.
-            else
-                ++i;            // have credit, didn't send, keep blocked
-        }
-    }
-
-    // Use to erase closed senders from blocked_ set.
-    template <class Predicate>
-    void erase_sender_if(blocked_map::iterator begin, blocked_map::iterator end, Predicate p) {
-        for (auto i = begin; i != end; ) {
-            if (p(i->second))
-                i = blocked_.erase(i);
-            else
-                ++i;
+    // The container calls on_transport_close() last.
+    void on_transport_close(proton::transport& t) OVERRIDE {
+        // Unsubscribe all senders.
+        for (proton::sender_iterator i = t.connection().senders().begin(); i != t.connection().senders().end(); ++i) {
+            senders::iterator j = senders_.find(*i);
+            if (j == senders_.end()) continue;
+            Sender* s = j->second;
+            if (s->queue_) {
+                defer(s->queue_, &Queue::unsubscribe, s);
+            }
         }
+        delete this;            // All done.
     }
-
-    queues& queues_;
-    blocked_map blocked_;
-    std::function<void(queue*)> has_messages_callback_;
-    proton::connection connection_;
 };
 
-
 class broker {
   public:
     broker(const std::string addr) :
-        container_("mt_broker"), listener_(queues_)
+        container_("broker"), queues_(container_), listener_(queues_)
     {
         container_.listen(addr, listener_);
         std::cout << "broker listening on " << addr << std::endl;
@@ -279,21 +478,21 @@ class broker {
 
   private:
     struct listener : public proton::listen_handler {
-        listener(queues& qs) : queues_(qs) {}
+        listener(QueueManager& c) : queues_(c) {}
 
         proton::connection_options on_accept(proton::listener&) OVERRIDE{
-            return proton::connection_options().handler(*(new broker_connection_handler(queues_)));
+            return proton::connection_options().handler(*(new connection_handler(queues_)));
         }
 
         void on_error(proton::listener&, const std::string& s) OVERRIDE {
             std::cerr << "listen error: " << s << std::endl;
             throw std::runtime_error(s);
         }
-        queues& queues_;
+        QueueManager& queues_;
     };
 
-    queues queues_;
     proton::container container_;
+    QueueManager queues_;
     listener listener_;
 };
 
@@ -302,9 +501,11 @@ int main(int argc, char **argv) {
     std::string address("0.0.0.0");
     example::options opts(argc, argv);
 
+    opts.add_flag(verbose, 'v', "verbose", "verbose (debugging) output");
     opts.add_value(address, 'a', "address", "listen on URL", "URL");
 
     try {
+        verbose = false;
         opts.parse();
         broker(address).run();
         return 0;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org