Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r51641 - in sandbox: channel channel/boost channel/boost/channel channel/boost/channel/dispatchers channel/boost/channel/executors channel/boost/channel/name_spaces channel/boost/channel/platforms channel/boost/channel/queues channel/boost/channel/streams channel/libs channel/libs/channel channel/libs/channel/build channel/libs/channel/doc channel/libs/channel/example channel/libs/channel/example/buffered_async_join channel/libs/channel/example/buffered_sync_sendrecv channel/libs/channel/example/chat_assoc channel/libs/channel/example/chat_direct channel/libs/channel/example/chat_regex channel/libs/channel/example/chat_shmem channel/libs/channel/example/chat_thru_server channel/libs/channel/example/dist_evt_chan channel/libs/channel/example/filter_translator channel/libs/channel/example/gui_evt channel/libs/channel/example/ping_pong channel/libs/channel/example/prime_sieve channel/libs/channel/example/sample_dispatcher channel/libs/channel/src channel/libs/channel/test join join/boost join/boost/join join/boost/join/base join/boost/join/idioms join/libs join/libs/join join/libs/join/doc join/libs/join/doc/tutorials join/libs/join/examples join/libs/join/examples/func_api join/libs/join/examples/func_api/thread_safe_events join/libs/join/examples/port_api
From: yigongliu_at_[hidden]
Date: 2009-03-07 13:45:39


Author: yigongliu
Date: 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
New Revision: 51641
URL: http://svn.boost.org/trac/boost/changeset/51641

Log:
Initial import
Added:
   sandbox/channel/
   sandbox/channel/boost/
   sandbox/channel/boost/channel/
   sandbox/channel/boost/channel/binder.hpp (contents, props changed)
   sandbox/channel/boost/channel/channel.hpp (contents, props changed)
   sandbox/channel/boost/channel/config.hpp (contents, props changed)
   sandbox/channel/boost/channel/connection.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/
   sandbox/channel/boost/channel/dispatchers/always_latest_dispatcher.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/arbiters_async.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/arbiters_sync.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/broadcast_dispatcher.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/dispatcher_base.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/pull_dispatcher.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/pull_dispatcher_base.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/push_dispatcher_base.hpp (contents, props changed)
   sandbox/channel/boost/channel/dispatchers/round_robin_dispatcher.hpp (contents, props changed)
   sandbox/channel/boost/channel/executors/
   sandbox/channel/boost/channel/executors/asio_executor.hpp (contents, props changed)
   sandbox/channel/boost/channel/executors/delayed_executor.hpp (contents, props changed)
   sandbox/channel/boost/channel/executors/executor_base.hpp (contents, props changed)
   sandbox/channel/boost/channel/executors/in_place_executor.hpp (contents, props changed)
   sandbox/channel/boost/channel/executors/thread_pool_executor.hpp (contents, props changed)
   sandbox/channel/boost/channel/executors/threadpool_executor.hpp (contents, props changed)
   sandbox/channel/boost/channel/interface.hpp (contents, props changed)
   sandbox/channel/boost/channel/marshaler.hpp (contents, props changed)
   sandbox/channel/boost/channel/message.hpp (contents, props changed)
   sandbox/channel/boost/channel/name.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/
   sandbox/channel/boost/channel/name_spaces/assoc_id_trait.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/hierarchical_id_trait.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/hierarchical_name_space.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/linear_id_trait.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/linear_name_space.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/name_space_change_notify.hpp (contents, props changed)
   sandbox/channel/boost/channel/name_spaces/null_name_space.hpp (contents, props changed)
   sandbox/channel/boost/channel/named_in_out.hpp (contents, props changed)
   sandbox/channel/boost/channel/peer.hpp (contents, props changed)
   sandbox/channel/boost/channel/platforms/
   sandbox/channel/boost/channel/platforms/boost_platform.hpp (contents, props changed)
   sandbox/channel/boost/channel/platforms/null_condition.hpp (contents, props changed)
   sandbox/channel/boost/channel/platforms/null_mutex.hpp (contents, props changed)
   sandbox/channel/boost/channel/platforms/synch_policy.hpp (contents, props changed)
   sandbox/channel/boost/channel/pub_sub.hpp (contents, props changed)
   sandbox/channel/boost/channel/queues/
   sandbox/channel/boost/channel/queues/bounded_queue.hpp (contents, props changed)
   sandbox/channel/boost/channel/queues/dropping_queue.hpp (contents, props changed)
   sandbox/channel/boost/channel/queues/flow_controlled_queue.hpp (contents, props changed)
   sandbox/channel/boost/channel/queues/queues.hpp (contents, props changed)
   sandbox/channel/boost/channel/queues/timed_queue.hpp (contents, props changed)
   sandbox/channel/boost/channel/queues/unbounded_queue.hpp (contents, props changed)
   sandbox/channel/boost/channel/streams/
   sandbox/channel/boost/channel/streams/asio_connector_async.hpp (contents, props changed)
   sandbox/channel/boost/channel/streams/asio_connector_sync.hpp (contents, props changed)
   sandbox/channel/boost/channel/streams/asio_stream_async.hpp (contents, props changed)
   sandbox/channel/boost/channel/streams/asio_stream_sync.hpp (contents, props changed)
   sandbox/channel/boost/channel/streams/shmem_stream.hpp (contents, props changed)
   sandbox/channel/boost/channel/unnamed_in_out.hpp (contents, props changed)
   sandbox/channel/libs/
   sandbox/channel/libs/channel/
   sandbox/channel/libs/channel/build/
   sandbox/channel/libs/channel/build/Jamfile (contents, props changed)
   sandbox/channel/libs/channel/build/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/doc/
   sandbox/channel/libs/channel/doc/assoc_id_text.html (contents, props changed)
   sandbox/channel/libs/channel/doc/design.html (contents, props changed)
   sandbox/channel/libs/channel/doc/index.html (contents, props changed)
   sandbox/channel/libs/channel/example/
   sandbox/channel/libs/channel/example/buffered_async_join/
   sandbox/channel/libs/channel/example/buffered_async_join/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_async_join/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_async_join/chat_join.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_async_join/chat_join_2chan.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_async_join/chat_join_timer.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_async_join/sample6_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_sync_sendrecv/
   sandbox/channel/libs/channel/example/buffered_sync_sendrecv/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_sync_sendrecv/sample5_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/buffered_sync_sendrecv/sync_send_recv.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_assoc/
   sandbox/channel/libs/channel/example/chat_assoc/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/chat_assoc/chat1.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_assoc/chat2.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_assoc/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_assoc/sample10_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/chat_direct/
   sandbox/channel/libs/channel/example/chat_direct/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/chat_direct/chat1.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_direct/chat2.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_direct/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_direct/sample4_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/chat_regex/
   sandbox/channel/libs/channel/example/chat_regex/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/chat_regex/chat1.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_regex/chat2.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_regex/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_regex/sample9_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/chat_regex/test.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_shmem/
   sandbox/channel/libs/channel/example/chat_shmem/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/chat_shmem/chat1.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_shmem/chat2.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_shmem/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_shmem/sample8_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/chat_thru_server/
   sandbox/channel/libs/channel/example/chat_thru_server/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/chat_thru_server/chat_cli.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_thru_server/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_thru_server/chat_srv.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/chat_thru_server/sample7_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/dist_evt_chan/
   sandbox/channel/libs/channel/example/dist_evt_chan/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan1.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan2.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/dist_evt_chan/sample3_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/filter_translator/
   sandbox/channel/libs/channel/example/filter_translator/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/filter_translator/chat_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/filter_translator/cli.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/filter_translator/sample11_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/filter_translator/srv.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/
   sandbox/channel/libs/channel/example/gui_evt/Jamfile (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/gui_evt3.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/gui_evt_chan1.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/gui_evt_chan2.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/sample1_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/gui_evt/sample2_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/ping_pong/
   sandbox/channel/libs/channel/example/ping_pong/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/ping_pong/ping.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/ping_pong/pingpong_defs.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/ping_pong/pong.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/prime_sieve/
   sandbox/channel/libs/channel/example/prime_sieve/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/prime_sieve/prime_sieve.cpp (contents, props changed)
   sandbox/channel/libs/channel/example/prime_sieve/sample12_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/sample_dispatcher/
   sandbox/channel/libs/channel/example/sample_dispatcher/Jamfile.v2 (contents, props changed)
   sandbox/channel/libs/channel/example/sample_dispatcher/dispatcher_text.html (contents, props changed)
   sandbox/channel/libs/channel/example/sample_dispatcher/pull_dispatcher_sample.hpp (contents, props changed)
   sandbox/channel/libs/channel/example/sample_dispatcher/sync_send_recv.cpp (contents, props changed)
   sandbox/channel/libs/channel/index.html (contents, props changed)
   sandbox/channel/libs/channel/src/
   sandbox/channel/libs/channel/src/assoc_id_trait.cpp (contents, props changed)
   sandbox/channel/libs/channel/src/hierarchical_id_trait.cpp (contents, props changed)
   sandbox/channel/libs/channel/src/linear_id_trait.cpp (contents, props changed)
   sandbox/channel/libs/channel/src/name.cpp (contents, props changed)
   sandbox/channel/libs/channel/test/
   sandbox/join/
   sandbox/join/boost/
   sandbox/join/boost/join/
   sandbox/join/boost/join/base/
   sandbox/join/boost/join/base/actor.hpp (contents, props changed)
   sandbox/join/boost/join/base/exceptions.hpp (contents, props changed)
   sandbox/join/boost/join/base/join_base.hpp (contents, props changed)
   sandbox/join/boost/join/base/port.hpp (contents, props changed)
   sandbox/join/boost/join/base/port_sig.hpp (contents, props changed)
   sandbox/join/boost/join/base/utils.hpp (contents, props changed)
   sandbox/join/boost/join/idioms/
   sandbox/join/boost/join/idioms/asio_executor.hpp (contents, props changed)
   sandbox/join/boost/join/idioms/executor.hpp (contents, props changed)
   sandbox/join/boost/join/idioms/rr_executor.hpp (contents, props changed)
   sandbox/join/boost/join/join.hpp (contents, props changed)
   sandbox/join/libs/
   sandbox/join/libs/join/
   sandbox/join/libs/join/doc/
   sandbox/join/libs/join/doc/boost_join_design.html (contents, props changed)
   sandbox/join/libs/join/doc/compare.html (contents, props changed)
   sandbox/join/libs/join/doc/compare_future.html (contents, props changed)
   sandbox/join/libs/join/doc/concur_design.html (contents, props changed)
   sandbox/join/libs/join/doc/dynamicjoin.html (contents, props changed)
   sandbox/join/libs/join/doc/internals.html (contents, props changed)
   sandbox/join/libs/join/doc/references.html (contents, props changed)
   sandbox/join/libs/join/doc/source_integration.html (contents, props changed)
   sandbox/join/libs/join/doc/staticjoin.html (contents, props changed)
   sandbox/join/libs/join/doc/support_message_passing.html (contents, props changed)
   sandbox/join/libs/join/doc/support_shared_state.html (contents, props changed)
   sandbox/join/libs/join/doc/synopsis_func.html (contents, props changed)
   sandbox/join/libs/join/doc/synopsis_port.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/
   sandbox/join/libs/join/doc/tutorials.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/act_obj_tutorial.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/aggreg_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/async_call_ret_tutorial.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/async_msg_state_tutorial.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/buffer_tutorial.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/dyn_chord_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/events_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/exe_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/future_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/guard_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/one_place_buffer_tutorial.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/override_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/parallel_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/prime_sieve_tut.html (contents, props changed)
   sandbox/join/libs/join/doc/tutorials/spawn_tutorial.html (contents, props changed)
   sandbox/join/libs/join/examples/
   sandbox/join/libs/join/examples/func_api/
   sandbox/join/libs/join/examples/func_api/Jamfile.v2 (contents, props changed)
   sandbox/join/libs/join/examples/func_api/active_object.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/async_call_ret.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/bounded_buffer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/buffer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/buffer_func_pointer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/ccr1.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/ccr2.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/ccr_service.cs (contents, props changed)
   sandbox/join/libs/join/examples/func_api/chord_override.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/counter.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/future.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/jocaml1.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/join_many.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/lambda1.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/logged_buffer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/one_place_buffer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/parallel.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/prime_sieve.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/rwlock.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/semaphore.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/spawner1.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/spawner2.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/thread_safe_events/
   sandbox/join/libs/join/examples/func_api/thread_safe_events/event1.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/thread_safe_events/event2.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/thread_safe_events/event3.cpp (contents, props changed)
   sandbox/join/libs/join/examples/func_api/with_stl.cpp (contents, props changed)
   sandbox/join/libs/join/examples/port_api/
   sandbox/join/libs/join/examples/port_api/Jamfile.v2 (contents, props changed)
   sandbox/join/libs/join/examples/port_api/bounded_buffer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/port_api/buffer.cpp (contents, props changed)
   sandbox/join/libs/join/examples/port_api/executor.hpp (contents, props changed)

Added: sandbox/channel/boost/channel/binder.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/binder.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,94 @@
+//
+// binder.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BINDER_HPP
+#define BINDER_HPP
+
+namespace boost {
+ namespace channel {
+ /**
+ * The name_space filters/translators defined here only manipulte ids/msg-types
+ * and affect name_space management
+ * message content is UNTOUCHED!
+ */
+
+ /**
+ * filter_types:
+ * 1. provision the permissions which messages/ids can flow in/out
+ * channel thru interfaces
+ * 2. ONLY works on sub/pub msgs, not other(application) msgs
+ * affect how sub/pub msgs are exchanged between local channel and
+ * remote channel - how remote and local name_spaces "merge"
+ * not affect the normal message passing process
+ * 3. Default filter_types are "transparent" - all Ids allowed in/out:
+ *
+ */
+ template<class id_type>
+ class filter_type {
+ public:
+ virtual bool block_inward(id_type&) {
+ return false;
+ }
+ virtual bool block_outward(id_type&) {
+ return false;
+ }
+ virtual ~filter_type() {
+ }
+ };
+
+ /**
+ * translator_type:
+ * 1. translate inward/outward msg ids, help integration of name_spaces
+ * 2. ONLY works on application msgs
+ * affect (potentially change) each msgs passed in/out interfaces -
+ * must be highly efficient
+ * 3. Default translator_type is non-op
+ */
+ template<class id_type>
+ class translator_type {
+ public:
+ virtual void translate_inward(id_type&) {
+ }
+ virtual void translate_outward(id_type &id) {
+ }
+ virtual ~translator_type() {
+ }
+ };
+
+ /**
+ * binder_type:
+ * 1. affect ONLY the interface - the "binding" point between local
+ * channel and remote connections
+ * 2. contains both filter and transltor
+ * 3. if filters/translators are NULL, they are no-op
+ */
+ template<class id_type>
+ class binder_type {
+ public:
+ typedef filter_type<id_type> filter_type;
+ typedef translator_type<id_type> translator_type;
+ filter_type *filter;
+ translator_type *translator;
+ binder_type(filter_type *f = NULL, translator_type *t = NULL) {
+ filter = f;
+ translator = t;
+ }
+ ~binder_type() {
+ if (filter != NULL)
+ delete filter;
+ if (translator != NULL)
+ delete translator;
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/channel.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/channel.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,221 @@
+//
+// channel.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef CHANNEL_HPP
+#define CHANNEL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if !defined(WIN32_LEAN_AND_MEAN)
+# define WIN32_LEAN_AND_MEAN
+# endif // !defined(WIN32_LEAN_AND_MEAN)
+#endif
+
+#include <set>
+#include <boost/channel/binder.hpp>
+#include <boost/channel/connection.hpp>
+#include <boost/channel/peer.hpp>
+#include <boost/channel/dispatchers/broadcast_dispatcher.hpp>
+#include <boost/channel/dispatchers/round_robin_dispatcher.hpp>
+#include <boost/channel/dispatchers/always_latest_dispatcher.hpp>
+#include <boost/channel/dispatchers/pull_dispatcher.hpp>
+#include <boost/channel/executors/executor_base.hpp>
+#include <boost/channel/interface.hpp>
+#include <boost/channel/name_spaces/linear_id_trait.hpp>
+#include <boost/channel/name_spaces/assoc_id_trait.hpp>
+#include <boost/channel/name_spaces/linear_name_space.hpp>
+#include <boost/channel/name_spaces/hierarchical_id_trait.hpp>
+#include <boost/channel/name_spaces/hierarchical_name_space.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/unnamed_in_out.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/platforms/boost_platform.hpp>
+#include <boost/channel/marshaler.hpp>
+#include <boost/channel/queues/queues.hpp>
+#include <boost/channel/pub_sub.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<
+ typename idtype,
+ typename platform_type = boost_platform,
+ typename synchpolicy = mt_synch<platform_type> ,
+ typename executor_type = abstract_executor, //force in-line execution
+ typename name_space = linear_name_space<idtype, executor_type, synchpolicy>,
+ typename dispatcher = broadcast_dispatcher<name_space, platform_type>
+ >
+ class channel: public id_trait<idtype> , public name_space {
+ public:
+ typedef idtype id_type;
+ typedef id_trait<id_type> id_trait;
+ typedef platform_type platform;
+ typedef synchpolicy synch_policy;
+ typedef name_space name_space_type;
+ typedef executor_type executor;
+ typedef dispatcher dispatch_policy;
+ typedef channel<id_type, platform, synch_policy, executor, name_space, dispatcher> channel_type;
+ typedef message<id_type> message_type;
+ typedef named_in<name_space_type, typename dispatch_policy::recver> in;
+ typedef named_out<name_space_type, typename dispatch_policy::sender> out;
+ typedef subscriber<name_space_type, typename dispatch_policy::recver> subscriber;
+ typedef publisher<name_space_type, typename dispatch_policy::sender> publisher;
+ typedef port<executor, id_type, platform, synch_policy, name_space_type, dispatch_policy> port;
+ typedef signal<executor, id_type, platform, synch_policy, name_space_type, dispatch_policy> signal;
+ typedef peer_type<id_type> peer_type;
+ typedef binder_type<id_type> binder_type;
+ typedef interface<channel_type> interface;
+ typedef connection<id_type> connection;
+ typedef marshaler_registry<id_type, id_trait, synch_policy, text_archive> text_marshaler_registry;
+ typedef marshaler_registry<id_type, id_trait, synch_policy, binary_archive> binary_marshaler_registry;
+ typedef marshaler_registry<id_type, id_trait, synch_policy, xml_archive> xml_marshaler_registry;
+ typedef named_in<name_space_type, typename broadcast_dispatcher<name_space, platform>::recver> sys_named_in;
+ typedef named_out<name_space_type, typename broadcast_dispatcher<name_space, platform>::sender> sys_named_out;
+ typedef named_out_bundle<name_space, typename broadcast_dispatcher<name_space, platform>::sender> sys_named_outs;
+ typedef named_in_bundle<name_space, typename broadcast_dispatcher<name_space, platform>::recver> sys_named_ins;
+
+ channel(executor *e = NULL) :
+ name_space(e) {
+ }
+
+ ~channel() {
+ platform::log("... channel destructor called ...");
+ for (typename std::set<interface*>::iterator iter = intfs_.begin(); iter != intfs_.end();) {
+ typename std::set<interface*>::iterator curr = iter++;
+ //need to get to next first, release() will callback and remove iter from set
+ //release interface and kill connection; interface obj will be
+ //deleted in connection's destructor
+ (*curr)->release();
+ }
+ }
+
+ template<typename recver_type>
+ in * bind_name_in(id_type id, recver_type r, typename in::scope_type scope = in::scope_global,
+ typename in::member_type type = in::member_local, executor *e = NULL) {
+ return new in(*this, id, r, scope, type, e);
+ }
+ out * bind_name_out(id_type id, typename out::scope_type scope = out::scope_global,
+ typename out::member_type type = out::member_local, executor *e = NULL) {
+ return new out(*this, id, scope, type, e);
+ }
+
+ void add_intf(interface *c) {
+ typename synch_policy::scoped_lock lock(lock_);
+ intfs_.insert(c);
+ }
+
+ void del_intf(interface *c) {
+ typename synch_policy::scoped_lock lock(lock_);
+ intfs_.erase(c);
+ }
+
+ int num_conn(void) {
+ return intfs_.size();
+ }
+
+ private:
+ typename synch_policy::mutex lock_;
+ std::set<interface *> intfs_;
+ };
+
+ /**
+ * function to connect 2 local channels of the same type
+ */
+ template<typename channel>
+ typename channel::connection* connect(channel &peer1, channel &peer2,
+ typename channel::binder_type *binder1 = NULL,
+ typename channel::binder_type *binder2 = NULL) {
+ typedef typename channel::interface interface;
+ typedef typename channel::peer_type peer_type;
+ typedef typename channel::connection connection;
+ interface *intf1 = new interface(peer1, binder1);
+ interface *intf2 = new interface(peer2, binder2);
+ connection *conn = new connection(connection::local_connection,
+ intf1, intf2);
+ intf1->bind_peer(intf2, peer_type::active_role, conn);
+ intf2->bind_peer(intf1, peer_type::passive_role, conn);
+
+ //start connection setup hand-shaking
+ intf1->send2remote_channel_info_msg();
+
+ return conn;
+ }
+
+ /**
+ * function to connect 2 local channels of different types
+ */
+ template <typename channel1, typename channel2>
+ typename channel1::connection* connect(channel1 &peer1, channel2 &peer2,
+ typename channel1::binder_type *binder1 = NULL,
+ typename channel2::binder_type *binder2 = NULL) {
+ typedef typename channel1::interface interface1;
+ typedef typename channel2::interface interface2;
+ typedef typename channel1::peer_type peer_type;
+ typedef typename channel1::connection connection;
+ interface1 *intf1 = new interface1(peer1, binder1);
+ interface2 *intf2 = new interface2(peer2, binder2);
+ connection *conn = new connection(connection::local_connection,
+ intf1, intf2);
+ intf1->bind_peer(intf2, peer_type::active_role, conn);
+ intf2->bind_peer(intf1, peer_type::passive_role, conn);
+
+ //start connection setup hand-shaking
+ intf1->send2remote_channel_info_msg();
+
+ return conn;
+ }
+
+ /**
+ * function to connect local channel to remote peer thru a stream obj
+ */
+ template <typename channel, typename stream_t>
+ typename channel::connection* connect(channel &peer,
+ stream_t * stream,
+ bool active,
+ typename channel::binder_type *binder = NULL
+ )
+ {
+ typedef typename channel::interface interface;
+ typedef typename channel::peer_type peer_type;
+ typedef typename channel::connection connection;
+ interface *intf = new interface(peer, binder);
+ connection *conn = new connection(connection::remote_connection,
+ intf, stream);
+ intf->bind_peer(stream, active?peer_type::active_role:peer_type::passive_role, conn);
+ stream->bind_peer(intf, active?peer_type::active_role:peer_type::passive_role, conn);
+
+ if (active) {
+ //start connection setup hand-shaking
+ intf->send2remote_channel_info_msg();
+ }
+
+ return conn;
+ }
+
+ /**
+ * generic functions to directly bind/unbind any pair of named_out and named_in
+ */
+ template <typename name>
+ void bind(name *named_out, name *named_in) {
+ named_out->bind(named_in);
+ named_in->bind(named_out);
+ }
+ template <typename name>
+ void unbind(name *named_out, name *named_in) {
+ named_out->unbind(named_in);
+ named_in->unbind(named_out);
+ }
+
+}
+}
+
+#endif

Added: sandbox/channel/boost/channel/config.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/config.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright (c) 1998-2002
+ * John Maddock
+ *
+ * Copyright (c) 2003-2004
+ * Douglas Gregor
+ *
+ * Copyright (c) 2005-2009
+ * Yigong Liu
+ *
+ * Distributed under the Boost Software License, Version 1.0. (See
+ * accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ *
+ */
+
+#ifndef BOOST_CHANNEL_CONFIG_HPP
+#define BOOST_CHANNEL_CONFIG_HPP
+
+#include <boost/config.hpp>
+
+#ifdef BOOST_HAS_DECLSPEC
+# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHANNEL_DYN_LINK)
+# ifdef BOOST_CHANNEL_SOURCE
+# define BOOST_CHANNEL_DECL __declspec(dllexport)
+# else
+# define BOOST_CHANNEL_DECL __declspec(dllimport)
+# endif // BOOST_CHANNEL_SOURCE
+# endif // DYN_LINK
+#endif // BOOST_HAS_DECLSPEC
+#ifndef BOOST_CHANNEL_DECL
+# define BOOST_CHANNEL_DECL
+#endif
+
+// Setup autolinking
+#if !defined(BOOST_CHANNEL_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_CHANNEL_NO_LIB)
+# define BOOST_LIB_NAME boost_channel
+
+# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHANNEL_DYN_LINK)
+# define BOOST_DYN_LINK
+# endif
+
+# include <boost/config/auto_link.hpp>
+#endif // autolinking on
+#endif // BOOST_CHANNEL_CONFIG_HPP
+

Added: sandbox/channel/boost/channel/connection.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/connection.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,43 @@
+//
+// connection.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef CONNECTION_HPP
+#define CONNECTION_HPP
+
+#include <set>
+#include <boost/channel/peer.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<typename id_type>
+ class connection {
+ public:
+ typedef peer_type<id_type> peer_type;
+ enum type {
+ local_connection = 0, remote_connection
+ };
+ type type_;
+ peer_type *peer1_, *peer2_;
+ connection(type t, peer_type *peer1, peer_type *peer2) :
+ type_(t), peer1_(peer1), peer2_(peer2) {
+ }
+
+ ~connection() {
+ peer1_->unbind();
+ peer2_->unbind();
+ delete peer1_;
+ if (type_ == local_connection)
+ delete peer2_; //should we delete stream for remote_conn?
+ }
+ };
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/always_latest_dispatcher.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/always_latest_dispatcher.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,64 @@
+//
+// always_latest_dispatcher.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ALWAYS_LATEST_DISPATCHER_HPP
+#define ALWAYS_LATEST_DISPATCHER_HPP
+
+////imitate plan9/inferno's "union" name_space:
+////later bound names will overlap older names, ie. latest mounted server will
+////take over and serve all msgs on the covered names
+////so always the latest bound name get dispatched
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/dispatcher_base.hpp>
+#include <boost/channel/dispatchers/push_dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ template<typename name_space, typename platform>
+ struct always_latest_algo {
+ typedef typename name_space::id_type id_type;
+ typedef message<id_type> msg_type;
+ typedef push_recver_base<name_space,platform> recver_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+
+ template<typename bindings_type>
+ void operator() (bindings_type &bindings,
+ boost::shared_ptr<msg_type> msg) {
+ if (!bindings.empty()) {
+ typename bindings_type::iterator iter = bindings.begin();
+ named_in_type *named_in = (named_in_type *)(*iter);
+ recver_type *recver = (recver_type *)named_in;
+ recver->push(msg);
+ }
+ }
+ };
+
+ }
+
+ template <typename name_space, typename platform>
+ struct always_latest_dispatcher {
+ typedef detail::push_sender_base<name_space,platform,detail::always_latest_algo> sender;
+ typedef detail::push_recver_base<name_space,platform> recver;
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/arbiters_async.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/arbiters_async.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,331 @@
+//
+// arbiters_async.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef ARBITERS_ASYNC_HPP
+#define ARBITERS_ASYNC_HPP
+
+#include <deque>
+#include <list>
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/channel/queues/unbounded_queue.hpp>
+#include <boost/channel/dispatchers/pull_dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+ namespace detail {
+
+ /**
+ * Async arbiters:
+ * asynch message passing synchronization patterns (choice, join)
+ * part of pull_dispatcher
+ * see CCR and Comega document
+ */
+ /**
+ * choice
+ */
+ template<typename name_space, typename platform,
+ template<class , class , class > class queue_type = unbounded_que>
+ class choice_arbiter_async {
+ public:
+ typedef pull_recver_base<name_space, platform, queue_type> recver_type;
+ typedef pull_sender_base<name_space, platform, queue_type> sender_type;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::name name;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef message<id_type> msg_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+ typedef named_out<name_space, sender_type> named_out_type;
+ typedef choice_arbiter_async<name_space,platform,queue_type> my_type;
+
+ typedef boost::function1<void, boost::shared_ptr<void> > call_back_t;
+
+ name_space *ch_;
+ executor *exec_;
+ struct entry {
+ named_in_type *in_;
+ call_back_t handler_;
+ ~entry() {
+ if (in_ != NULL) delete in_;
+ }
+ };
+ std::map<id_type, entry*> ins_map_;
+ std::deque<entry*> ins_;
+ typename synch_policy::mutex mutex_;
+
+ choice_arbiter_async(name_space &ch, executor *e = NULL) :
+ ch_(&ch),
+ exec_(e!=NULL?e:ch.get_exec()) {}
+
+ choice_arbiter_async(executor *e = NULL) :
+ ch_(NULL),
+ exec_(e) {}
+
+ ~choice_arbiter_async() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<entry*>::iterator iter;
+ for (iter = ins_.begin(); iter != ins_.end(); iter++)
+ if ((*iter) != NULL) {
+ delete (*iter);
+ }
+ }
+
+ //called from inside dispatcher
+ void invoke(named_in_type * &in, id_type, boost::shared_ptr<void>) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<entry*>::iterator iter;
+ bool found = false;
+ for(iter = ins_.begin(); iter != ins_.end() && !found; iter++)
+ if(in == (*iter)->in_) {
+ found = true;
+ break;
+ }
+ if(found && in->claim()) {
+ boost::shared_ptr<msg_type> msg;
+ if (in->pull(msg) > 0) {
+ //successfully get a msg here, should we use executor to run callback?
+ //since invoke already run in executor, so dont delay again
+ (*iter)->handler_(msg->data_);
+ }
+ }
+ }
+
+ bool bind(id_type & id,
+ call_back_t cb,
+ typename named_in_type::scope_type scope = named_in_type::scope_global) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (ins_map_.find(id) == ins_map_.end()) {
+ entry * ent = new entry();
+ ent->in_ = new named_in_type(*ch_,id,
+ boost::bind(&my_type::invoke, this, boost::ref(ent->in_), _1, _2),
+ scope,named_in_type::member_local,exec_);
+ ent->handler_ = cb;
+ ins_.push_back(ent);
+ ins_map_[id] = ent;
+ return true;
+ }
+ return false;
+ }
+
+ bool unbind(id_type & id) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::map<id_type, entry*>::iterator iter = ins_map_.find(id);
+ if (iter != ins_map_.end()) {
+ delete iter->second;
+ ins_.erase(iter->second);
+ ins_map_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+
+ bool bind(named_out_type & no, call_back_t cb) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ entry * ent = new entry();
+ ent->in_ = new named_in_type(boost::bind(&my_type::invoke, this, boost::ref(ent->in_), _1, _2),
+ exec_);
+ ent->handler_ = cb;
+ ins_.push_back(ent);
+ //bind named_out and named_in
+ no.bind(ent->in_);
+ ent->in_->bind(&no);
+ return true;
+ }
+
+ bool unbind(named_out_type & no) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ std::list<name *> & bindings = no.bindings();
+ typename std::list<name *>::iterator iter, curr;
+ typename std::deque<entry*>::iterator iterq;
+ for(iter = bindings.begin(); iter != bindings.end(); ) {
+ curr = iter; iter++;
+ named_in_type *ni = (*curr);
+ iterq = std::find(ins_.begin(), ins_.end(),ni);
+ if (iterq != ins_.end()) {
+ ins_.erase(iterq);
+ delete ni;
+ }
+ }
+ return true;
+ }
+
+ };
+
+ /**
+ * join
+ */
+ template <typename name_space, typename platform,
+ template <class,class,class> class queue_type = unbounded_que>
+ class join_arbiter_async {
+ public:
+ public:
+ typedef pull_recver_base<name_space,platform,queue_type> recver_type;
+ typedef pull_sender_base<name_space,platform,queue_type> sender_type;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::name name;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef message<id_type> msg_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+ typedef named_out<name_space, sender_type> named_out_type;
+ typedef join_arbiter_async<name_space,platform,queue_type> my_type;
+
+ typedef boost::function1<void, std::vector<boost::shared_ptr<void> >& > call_back_t;
+
+ name_space *ch_;
+ executor *exec_;
+ call_back_t handler_;
+ std::deque<named_in_type*> ins_;
+ std::map<id_type, named_in_type*> ins_map_; //keep locking order
+ typename synch_policy::mutex mutex_;
+
+ join_arbiter_async(name_space &ch,
+ std::vector<std::pair<id_type, typename named_in_type::scope_type> > & ids,
+ call_back_t cb,
+ executor *e = NULL) :
+ ch_(&ch),
+ exec_(e!=NULL?e:ch.get_exec()),
+ handler_(cb) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::vector<std::pair<id_type,
+ typename named_in_type::scope_type> >::iterator iter;
+ for(iter = ids.begin(); iter != ids.end(); iter++) {
+ named_in_type * ni = new named_in_type(*ch_,iter->first,
+ boost::bind(&my_type::invoke, this, _1, _2),
+ iter->second,
+ named_in_type::member_local,exec_);
+ ins_.push_back(ni); //keep order to avoid deadlock
+ ins_map_[iter->first] = ni;
+ }
+ }
+
+ join_arbiter_async(name_space &ch,
+ call_back_t cb,
+ executor *e = NULL) :
+ ch_(&ch),
+ exec_(e!=NULL?e:ch.get_exec()),
+ handler_(cb) {
+ }
+
+ join_arbiter_async(call_back_t cb, executor *e = NULL) :
+ ch_(NULL),
+ exec_(e),
+ handler_(cb) {}
+
+ ~join_arbiter_async() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ for (iter = ins_.begin(); iter != ins_.end(); iter++)
+ delete (*iter);
+ }
+
+ //called from inside dispatcher
+ //2 phase protocol
+ void invoke(id_type, boost::shared_ptr<void>) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ //first claim the messages
+ //for (typename std::map<id_type,named_in_type*>::iterator iter1 = ins_map_.begin(); iter1 != ins_map_.end(); iter1++) {
+ for (iter = ins_.begin(); iter != ins_.end(); iter++) {
+ named_in_type *in = (*iter);
+ if(!in->claim()) {
+ //roll back
+ //for (typename std::map<id_type,named_in_type*>::iterator iter2 = ins_map_.begin();
+ //iter2 != iter1; iter2++)
+ for (typename std::deque<named_in_type*>::iterator iter2 = ins_.begin();
+ iter2 != iter; iter2++)
+ (*iter2)->unclaim();
+ return;
+ }
+ }
+ //reaching here, we have claimed all the member messages,
+ //commit (pull msgs and run callback)
+ boost::shared_ptr<msg_type> msg;
+ std::vector<boost::shared_ptr<void> > result;
+ for (iter = ins_.begin(); iter != ins_.end(); iter++) {
+ named_in_type *in = (*iter);
+ msg.reset();
+ in->pull(msg);
+ result.push_back(msg->data_);
+ }
+ handler_(result);
+ }
+
+ bool bind(id_type & id,
+ typename named_in_type::scope_type scope = named_in_type::scope_global) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ for(iter = ins_.begin(); iter != ins_.end(); iter++)
+ if ((*iter)->id_ == id)
+ return false;
+ named_in_type * ni = new named_in_type(*ch_,id,
+ boost::bind(&my_type::invoke, this, _1, _2),
+ scope,
+ named_in_type::member_local,exec_);
+ ins_.push_back(ni); //keep order to avoid deadlock
+ ins_map_[id] = ni;
+ return true;
+ }
+
+ bool unbind(id_type & id) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ for(iter = ins_.begin(); iter != ins_.end(); iter++)
+ if ((*iter)->id_ == id) {
+ ins_map_.erase(id);
+ delete (*iter);
+ ins_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+
+ bool bind(named_out_type & no, call_back_t cb) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ named_in_type * ni = new named_in_type(boost::bind(&my_type::invoke, this, _1, _2),
+ exec_);
+ ins_.push_back(ni);
+ //bind named_out and named_in
+ no.bind(ni);
+ ni->bind(&no);
+ return true;
+ }
+
+ bool unbind(named_out_type & no) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ std::list<name *> & bindings = no.bindings();
+ typename std::list<name *>::iterator iter, curr;
+ typename std::deque<name *>::iterator iterq;
+ for(iter = bindings.begin(); iter != bindings.end(); ) {
+ curr = iter; iter++;
+ named_in_type *ni = (*curr);
+ iterq = std::find(ins_.begin(), ins_.end(),ni);
+ if (iterq != ins_.end()) {
+ ins_.erase(iterq);
+ delete ni;
+ }
+ }
+ return true;
+ }
+ };
+
+ }
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/arbiters_sync.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/arbiters_sync.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,450 @@
+//
+// arbiters_sync.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef ARBITERS_SYNC_HPP
+#define ARBITERS_SYNC_HPP
+
+#include <deque>
+#include <list>
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/channel/queues/unbounded_queue.hpp>
+#include <boost/channel/dispatchers/pull_dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ /**
+ * synchronous arbiters:
+ * message passing synchronization patterns (choice, join)
+ * part of pull_dispatcher
+ * see CCR and Comega document
+ */
+ /**
+ * choice
+ */
+ template<typename name_space, typename platform,
+ template<class , class , class > class queue_type = unbounded_que>
+ class choice_arbiter_sync {
+ public:
+ typedef pull_recver_base<name_space, platform, queue_type> recver_type;
+ typedef pull_sender_base<name_space, platform, queue_type> sender_type;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::name name;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef message<id_type> msg_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+ typedef named_out<name_space, sender_type> named_out_type;
+ typedef choice_arbiter_sync<name_space,platform,queue_type> my_type;
+
+ typedef boost::function1<void, boost::shared_ptr<void> > call_back_t;
+
+ name_space *ch_;
+ struct entry {
+ named_in_type *in_;
+ call_back_t handler_;
+ ~entry() {
+ if (in_ != NULL) delete in_;
+ }
+ };
+ std::map<id_type, entry*> ins_map_;
+ std::deque<entry*> ins_;
+ typename synch_policy::mutex mutex_;
+ typename synch_policy::condition cond_;
+ int num_waiting_;
+ bool ready_in_set;
+ named_in_type *ready_in;
+
+ choice_arbiter_sync(name_space &ch) :
+ ch_(&ch), num_waiting_(0), ready_in_set(false), ready_in(NULL) {}
+
+ ~choice_arbiter_sync() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<entry*>::iterator iter;
+ for (iter = ins_.begin(); iter != ins_.end(); iter++)
+ if ((*iter) != NULL) {
+ delete (*iter);
+ }
+ }
+
+ //recving thread will block here and wait for notify from senders
+ void recv(id_type & id, boost::shared_ptr<void> & msg) {
+ boost::shared_ptr<msg_type> mesg;
+ typename std::deque<entry*>::iterator iter;
+ typename synch_policy::scoped_lock lock(mutex_);
+ while(1) {
+ //pull data
+ if (ready_in_set) {
+ ready_in_set = false;
+ named_in_type *in = ready_in;
+ bool found = false;
+ for(iter = ins_.begin(); iter != ins_.end() && !found; iter++)
+ if(in == (*iter)->in_) {
+ found = true;
+ break;
+ }
+ if(found && in->claim()) {
+ if (in->pull(mesg) > 0) {
+ if ((*iter)->handler_)
+ (*iter)->handler_(mesg->data_);
+ id = mesg->id_;
+ msg = mesg->data_;
+ return;
+ }
+ }
+ }
+ else {
+ for(iter = ins_.begin(); iter != ins_.end(); iter++) {
+ named_in_type *in = (*iter)->in_;
+ if(in->claim()) {
+ if (in->pull(mesg) > 0) {
+ if ((*iter)->handler_)
+ (*iter)->handler_(mesg->data_);
+ id = mesg->id_;
+ msg = mesg->data_;
+ return;
+ }
+ }
+ }
+ }
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ }
+ }
+
+ //recving thread will block here and wait for notify from senders
+ void wait(void) {
+ boost::shared_ptr<msg_type> mesg;
+ typename std::map<id_type, entry>::iterator iter;
+ typename synch_policy::scoped_lock lock(mutex_);
+ while(1) {
+ //pull data
+ if (ready_in_set) {
+ ready_in_set = false;
+ named_in_type *in = ready_in;
+ bool found = false;
+ for(iter = ins_.begin(); iter != ins_.end() && !found; iter++)
+ if(in == iter->in_) {
+ found = true;
+ break;
+ }
+ if(found && in->claim()) {
+ if (in->pull(mesg) > 0) {
+ if (iter->handler_)
+ iter->handler_(mesg->data_);
+ return;
+ }
+ }
+ }
+ else {
+ for(iter = ins_.begin(); iter != ins_.end(); iter++) {
+ named_in_type *in = iter->in_;
+ if(in->claim()) {
+ if (in->pull(mesg) > 0) {
+ if (iter->handler_)
+ iter->handler_(mesg->data_);
+ return;
+ }
+ }
+ }
+ }
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ }
+ }
+
+ //called from inside dispatcher
+ void invoke(named_in_type * &ni, id_type, boost::shared_ptr<void>) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ ready_in = ni;
+ ready_in_set = true;
+ if (num_waiting_ > 0)
+ cond_.notify_one();
+ }
+
+ bool bind(id_type & id,
+ call_back_t cb = 0,
+ typename named_in_type::scope_type scope = named_in_type::scope_global) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (ch_ != NULL && ins_map_.find(id) == ins_map_.end()) {
+ entry *ent = new entry();
+ ent->in_ = new named_in_type(*ch_,id,
+ boost::bind(&my_type::invoke, this, boost::ref(ent->in_), _1, _2),
+ scope);
+ ent->handler_ = cb;
+ ins_.push_back(ent);
+ ins_map_[id] = ent;
+ return true;
+ }
+ return false;
+ }
+
+ bool unbind(id_type & id) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::map<id_type, entry*>::iterator iter = ins_map_.find(id);
+ if (iter != ins_map_.end()) {
+ delete iter->second;
+ ins_.erase(iter->second);
+ ins_map_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+
+ bool bind(named_out_type & no, call_back_t cb) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ entry * ent = new entry();
+ ent->in_ = new named_in_type(boost::bind(&my_type::invoke, this, boost::ref(ent->in_), _1, _2));
+ ent->handler_ = cb;
+ ins_.push_back(ent);
+ //bind named_out and named_in
+ no.bind(ent->in_);
+ ent->in_->bind(&no);
+ return true;
+ }
+
+ bool unbind(named_out_type & no) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ std::list<name *> & bindings = no.bindings();
+ typename std::list<name *>::iterator iter, curr;
+ typename std::deque<entry*>::iterator iterq;
+ for(iter = bindings.begin(); iter != bindings.end(); ) {
+ curr = iter; iter++;
+ named_in_type *ni = (*curr);
+ iterq = ins_.find(ni);
+ if (iterq != ins_.end()) {
+ ins_.erase(ni);
+ delete ni;
+ }
+ }
+ return true;
+ }
+
+ };
+
+ /**
+ * join
+ */
+ template <typename name_space, typename platform,
+ template <class,class,class> class queue_type = unbounded_que>
+ class join_arbiter_sync {
+ public:
+ public:
+ typedef pull_recver_base<name_space,platform,queue_type> recver_type;
+ typedef pull_sender_base<name_space,platform,queue_type> sender_type;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::name name;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef message<id_type> msg_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+ typedef named_out<name_space, sender_type> named_out_type;
+ typedef join_arbiter_sync<name_space,platform,queue_type> my_type;
+
+ typedef boost::function1<void, std::vector<boost::shared_ptr<void> >& > call_back_t;
+
+ name_space *ch_;
+ call_back_t handler_;
+ std::deque<named_in_type*> ins_; //keep parameter order
+ std::map<id_type, named_in_type*> ins_map_; //keep locking order
+ typename synch_policy::mutex mutex_;
+ typename synch_policy::condition cond_;
+ int num_waiting_;
+
+ join_arbiter_sync(name_space &ch,
+ std::vector<std::pair<id_type, typename named_in_type::scope_type> > & ids,
+ call_back_t cb = 0) :
+ ch_(&ch),
+ handler_(cb), num_waiting_(0) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::vector<std::pair<id_type,
+ typename named_in_type::scope_type> >::iterator iter;
+ for(iter = ids.begin(); iter != ids.end(); iter++) {
+ named_in_type * ni = new named_in_type(*ch_,iter->first,
+ boost::bind(&my_type::invoke, this, _1, _2),
+ iter->second);
+ ins_.push_back(ni);
+ ins_map_[iter->first] = ni;
+ }
+ }
+
+ join_arbiter_sync(name_space &ch,
+ call_back_t cb = 0) :
+ ch_(&ch),
+ handler_(cb), num_waiting_(0) {
+ }
+
+ join_arbiter_sync(call_back_t cb = 0) :
+ ch_(NULL),
+ handler_(cb), num_waiting_(0) {
+ }
+
+ ~join_arbiter_sync() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ for (iter = ins_.begin(); iter != ins_.end(); iter++)
+ delete (*iter);
+ }
+
+ //called from inside dispatcher
+ //2 phase protocol
+ void recv(std::vector<boost::shared_ptr<void> > & result) {
+ boost::shared_ptr<msg_type> msg;
+ typename std::deque<named_in_type*>::iterator iter;
+ typename synch_policy::scoped_lock lock(mutex_);
+ while(1) {
+ bool claimed = true;
+ //first claim the messages in proper order based on ids to avoid deadlock
+ for (iter = ins_.begin(); iter != ins_.end() && claimed; iter++) {
+ named_in_type *in = (*iter);
+ if(!in->claim()) {
+ //roll back
+ for (typename std::deque<named_in_type*>::iterator iter2 = ins_.begin();
+ iter2 != iter; iter2++)
+ (*iter2)->unclaim();
+ claimed = false;
+ }
+ }
+ if(claimed) {
+ //reaching here, we have claimed all the member messages,
+ //commit (pull msgs and run callback)
+ result.clear();
+ for (iter = ins_.begin(); iter != ins_.end(); iter++) {
+ named_in_type *in = (*iter);
+ msg.reset();
+ in->pull(msg);
+ result.push_back(msg->data_);
+ }
+ if(handler_)
+ handler_(result);
+ return;
+ } else {
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ }
+ }
+ }
+ void wait(void) {
+ boost::shared_ptr<msg_type> msg;
+ std::vector<boost::shared_ptr<void> > result;
+ typename std::deque<named_in_type*>::iterator iter;
+ typename synch_policy::scoped_lock lock(mutex_);
+ while(1) {
+ bool claimed = true;
+ //first claim the messages in proper order based on ids to avoid deadlock
+ for (iter = ins_.begin(); iter != ins_.end() && claimed; iter++) {
+ named_in_type *in = (*iter);
+ if(!in->claim()) {
+ //roll back
+ for (typename std::deque<named_in_type*>::iterator iter2 = ins_.begin();
+ iter2 != iter; iter2++)
+ (*iter2)->unclaim();
+ claimed = false;
+ }
+ }
+ if(claimed) {
+ //reaching here, we have claimed all the member messages,
+ //commit (pull msgs and run callback)
+ result.clear();
+ for (iter = ins_.begin(); iter != ins_.end(); iter++) {
+ named_in_type *in = (*iter);
+ msg.reset();
+ in->pull(msg);
+ result.push_back(msg->data_);
+ }
+ if(handler_)
+ handler_(result);
+ return;
+ } else {
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ }
+ }
+ }
+
+ void invoke(id_type, boost::shared_ptr<void>) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (num_waiting_ > 0)
+ cond_.notify_one();
+ }
+
+ bool bind(id_type & id,
+ typename named_in_type::scope_type scope = named_in_type::scope_global) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ for(iter = ins_.begin(); iter != ins_.end(); iter++)
+ if ((*iter)->id_ == id)
+ return false;
+ named_in_type * ni = new named_in_type(*ch_,id,
+ boost::bind(&my_type::invoke, this, _1, _2),
+ scope);
+ ins_.push_back(ni); //keep order to avoid deadlock
+ ins_map_[id] = ni;
+ return true;
+ }
+
+ bool unbind(id_type & id) {
+ if (ch_ == NULL) return false;
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<named_in_type*>::iterator iter;
+ for(iter = ins_.begin(); iter != ins_.end(); iter++)
+ if ((*iter)->id_ == id) {
+ ins_map_.erase(id);
+ delete (*iter);
+ ins_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+
+ bool bind(named_out_type & no, call_back_t cb) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ named_in_type * ni = new named_in_type(boost::bind(&my_type::invoke, this, _1, _2));
+ ins_.push_back(ni);
+ //bind named_out and named_in
+ no.bind(ni);
+ ni->bind(&no);
+ return true;
+ }
+
+ bool unbind(named_out_type & no) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ std::list<name *> & bindings = no.bindings();
+ typename std::list<name *>::iterator iter, curr;
+ typename std::deque<name *>::iterator iterq;
+ for(iter = bindings.begin(); iter != bindings.end(); ) {
+ curr = iter; iter++;
+ named_in_type *ni = (*curr);
+ iterq = ins_.find(ni);
+ if (iterq != ins_.end()) {
+ ins_.erase(ni);
+ delete ni;
+ }
+ }
+ return true;
+ }
+ };
+
+ }
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/broadcast_dispatcher.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/broadcast_dispatcher.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,65 @@
+//
+// broadcast_dispatcher.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+//// broadcast dispatcher
+
+#ifndef BROADCAST_DISPATCHER_HPP
+#define BROADCAST_DISPATCHER_HPP
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/dispatcher_base.hpp>
+#include <boost/channel/dispatchers/push_dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ //the following is for 3 simple "push" dispatchers: broadcast, roundrobin, union
+ template<typename name_space, typename platform>
+ struct broadcast_algo {
+ typedef typename name_space::id_type id_type;
+ typedef message<id_type> msg_type;
+ typedef push_recver_base<name_space,platform> recver_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+
+ template<typename bindings_type>
+ void operator() (bindings_type &bindings,
+ boost::shared_ptr<msg_type> msg) {
+ if (!bindings.empty()) {
+ for(typename bindings_type::iterator iter = bindings.begin();
+ iter != bindings.end(); iter++) {
+ named_in_type *named_in = (named_in_type *)(*iter);
+ recver_type *recver = (recver_type *)named_in;
+ recver->push(msg);
+ }
+ }
+ }
+ };
+
+ }
+
+ template <typename name_space, typename platform>
+ struct broadcast_dispatcher {
+ typedef detail::push_sender_base<name_space,platform,detail::broadcast_algo> sender;
+ typedef detail::push_recver_base<name_space,platform> recver;
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/dispatcher_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/dispatcher_base.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,138 @@
+//
+// dispatcher_base.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+//// dispatcher_base:
+//// base handler definitions; should we use boost::function instead?
+////
+
+#ifndef DISPATCHER_BASE_HPP
+#define DISPATCHER_BASE_HPP
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ //message handlers; should i use boost::function instead of
+ //duplicating all these code?
+ template<typename id_type>
+ class msg_handler_base {
+ public:
+ void invoke(id_type id, boost::shared_ptr<void> msg) {
+ invoke_func_(this, id, msg);
+ }
+
+ void destroy() {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(msg_handler_base*, id_type id,
+ boost::shared_ptr<void> msg);
+ typedef void (*destroy_func_type)(msg_handler_base*);
+
+ msg_handler_base(invoke_func_type invoke_func,
+ destroy_func_type destroy_func) :
+ invoke_func_(invoke_func), destroy_func_(destroy_func) {
+ }
+
+ ~msg_handler_base() {
+ }
+
+ private:
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ template<typename id_type, typename handler_type>
+ class msg_handler: public msg_handler_base<id_type> {
+ typedef msg_handler_base<id_type> msg_handler_base;
+ public:
+ msg_handler(handler_type handler) :
+ msg_handler_base(&msg_handler<id_type, handler_type>::invoke_handler,
+ &msg_handler<id_type, handler_type>::destroy_handler),
+ handler_(handler) {
+ }
+
+ static void invoke_handler(msg_handler_base* base, id_type id,
+ boost::shared_ptr<void> msg) {
+ static_cast<msg_handler<id_type, handler_type>*> (base)->handler_(id,
+ msg);
+ }
+
+ static void destroy_handler(msg_handler_base* base) {
+ delete static_cast<msg_handler<id_type, handler_type>*> (base);
+ }
+
+ private:
+ handler_type handler_;
+ };
+
+ template<typename id_type>
+ class msg_handler_base2 {
+ public:
+ void invoke(id_type id) {
+ invoke_func_(this, id);
+ }
+
+ void destroy() {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(msg_handler_base2*, id_type id);
+ typedef void (*destroy_func_type)(msg_handler_base2*);
+
+ msg_handler_base2(invoke_func_type invoke_func,
+ destroy_func_type destroy_func) :
+ invoke_func_(invoke_func), destroy_func_(destroy_func) {
+ }
+
+ ~msg_handler_base2() {
+ }
+
+ private:
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ template<typename id_type, typename handler_type>
+ class msg_handler2: public msg_handler_base2<id_type> {
+ typedef msg_handler_base2<id_type> msg_handler_base2;
+ public:
+ msg_handler2(handler_type handler) :
+ msg_handler_base2(&msg_handler2<id_type, handler_type>::invoke_handler,
+ &msg_handler2<id_type, handler_type>::destroy_handler),
+ handler_(handler) {
+ }
+
+ static void invoke_handler(msg_handler_base2* base, id_type id) {
+ static_cast<msg_handler2<id_type, handler_type>*> (base)->handler_(id);
+ }
+
+ static void destroy_handler(msg_handler_base2* base) {
+ delete static_cast<msg_handler2<id_type, handler_type>*> (base);
+ }
+
+ private:
+ handler_type handler_;
+ };
+
+ }
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/pull_dispatcher.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/pull_dispatcher.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,40 @@
+//
+// pull_dispatcher.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef PULL_DISPATCHER_HPP
+#define PULL_DISPATCHER_HPP
+
+#include <boost/channel/queues/unbounded_queue.hpp>
+#include <boost/channel/dispatchers/pull_dispatcher_base.hpp>
+#include <boost/channel/dispatchers/arbiters_async.hpp>
+#include <boost/channel/dispatchers/arbiters_sync.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<typename name_space, typename platform,
+ template<class , class , class > class queue_type = unbounded_que>
+ struct pull_dispatcher {
+ typedef detail::pull_sender_base<name_space, platform, queue_type> sender;
+ typedef detail::pull_recver_base<name_space, platform, queue_type> recver;
+ typedef detail::choice_arbiter_async<name_space, platform, queue_type>
+ choice_async;
+ typedef detail::join_arbiter_async<name_space, platform, queue_type>
+ join_async;
+ typedef detail::choice_arbiter_sync<name_space, platform, queue_type>
+ choice_sync;
+ typedef detail::join_arbiter_sync<name_space, platform, queue_type>
+ join_sync;
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/pull_dispatcher_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/pull_dispatcher_base.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,244 @@
+//
+// pull_dispatcher_base.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef PULL_DISPATCHER_BASE_HPP
+#define PULL_DISPATCHER_BASE_HPP
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+ namespace detail {
+
+ template<class , class , template<class , class , class > class> class pull_recver_base;
+
+ //base pull_sender class, shared by most pull dispatchers
+ template<typename name_space, typename platform,
+ template<class , class , class > class msg_queue_type>
+ struct pull_sender_base: public msg_queue_type<boost::shared_ptr<message<
+ typename name_space::id_type> >, typename name_space::synch_policy,
+ platform> {
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef name<id_type,executor,synch_policy> name_type;
+ typedef message<id_type> msg_type;
+ typedef msg_queue_type<boost::shared_ptr<msg_type>,
+ synch_policy,
+ platform> que_type;
+ typedef typename name_type::binding_set_type binding_set_type;
+ typedef pull_recver_base<name_space, platform,msg_queue_type> recver_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+
+ name_type * name_;
+ executor *exec_;
+ typename synch_policy::mutex claim_lock_;
+ int num_claimed_;
+
+ pull_sender_base(name_type *n, executor *e) : que_type(), name_(n),
+ exec_(e), num_claimed_(0) {}
+ ~pull_sender_base() {}
+
+ void notify(boost::shared_ptr<msg_type> msg) {
+ //first store msg in que, only buffered msgs destined for local
+ //msgs destined for remote will not be buffered, sent using always_first?
+ if (name_->scope_ != name_base::scope_remote) {
+ this->put(msg);
+ }
+ //notify recevers
+ typename synch_policy::scoped_lock lock(this->name_->bind_lock_);
+ binding_set_type &bindings = this->name_->bindings_;
+ if (!bindings.empty()) {
+ ///let all interested recvers know that a message is available
+ for(typename binding_set_type::iterator iter = bindings.begin();
+ iter != bindings.end(); iter++) {
+ named_in_type *named_in = (named_in_type *)(*iter);
+ recver_type *recver = (recver_type *)named_in;
+
+ if (name_->scope_ == name_base::scope_remote || //for msgs sent to remote, treat it as always_first?
+ named_in->type_ == named_in_type::member_local) {//for pull dispatchers, only send msgs to local receviers
+ recver->notify(msg);
+ if (name_->scope_ == name_base::scope_remote)
+ return;
+ }
+ }
+ }
+ }
+
+ //recvers will call this to retrv/pull data
+ int pull(boost::shared_ptr<msg_type> & msg) {
+ if (!this->empty()) {
+ this->get(msg);
+ return 1;
+ }
+ return 0;
+ }
+
+ //--- for 2 phase msg consumption protocol ---
+
+ //to support 2-phase protocol at recver side
+ bool claim_one(void) {
+ typename synch_policy::scoped_lock lock(this->claim_lock_);
+ if ((int)this->size() > num_claimed_) {
+ num_claimed_++;
+ return true;
+ }
+ return false;
+ }
+
+ void unclaim_one(void) {
+ typename synch_policy::scoped_lock lock(this->claim_lock_);
+ num_claimed_--;
+ if (num_claimed_ < 0) num_claimed_ = 0;
+ }
+ //--- api interface ---
+ //after sending, channel becomes owner
+ template <typename user_msg_type>
+ void send(user_msg_type *msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ notify (m);
+ }
+
+ //after sending: 1> channel becomes owner, if deleter does real deletion
+ // 2> sender still owns msg, if deleter does nothing
+ template <typename user_msg_type, typename deleter>
+ void send(user_msg_type *msg, deleter deler) {
+ boost::shared_ptr<void> m0(msg, deler);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ notify (m);
+ }
+
+ //user_msg is already smarter pointer, channel becomes owner
+ template <typename user_msg_type>
+ void send(boost::shared_ptr<user_msg_type> msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ notify (m);
+ }
+
+ //for channel internal use on wildcard named_out
+ template <typename user_msg_type>
+ void send(id_type id, boost::shared_ptr<user_msg_type> msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(id, m0));
+ notify (m);
+ }
+
+ };
+
+ //pull_recver_base class, base for join/choice pattern
+ template <typename name_space, typename platform, template <class,class,class> class msg_que_type>
+ struct pull_recver_base {
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef name<id_type,executor,synch_policy> name_type;
+ typedef message<id_type> msg_type;
+ typedef typename name_type::binding_set_type binding_set_type;
+ typedef pull_sender_base<name_space, platform, msg_que_type> sender_type;
+ typedef named_out<name_space, sender_type> named_out_type;
+
+ name_type * name_;
+ //msg_handler_base2<id_type> * recver_;
+ msg_handler_base<id_type> * recver_;
+ executor *exec_;
+ sender_type *claimed_sender_;
+
+ template<typename recver_type>
+ pull_recver_base(name_type *n, recver_type rc, executor *e) :
+ name_(n), exec_(e), claimed_sender_(NULL)
+ {
+ //recver_ = new msg_handler2<id_type, recver_type>(rc);
+ recver_ = new msg_handler<id_type, recver_type>(rc);
+ }
+
+ ~pull_recver_base() {
+ if (recver_ != NULL)
+ recver_->destroy();
+ if (claimed_sender_ != NULL)
+ claimed_sender_->unclaim_one();
+ }
+
+ void set_exe(executor *e) {exec_ = e;}
+
+ //senders call this to notify about some data coming
+ //put this recver into activation list
+ bool notify(boost::shared_ptr<msg_type> msg) {
+ /*
+ if (exec_ != NULL) //run recv_handler in executor
+ exec_->execute(boost::bind(&msg_handler_base2<id_type>::invoke, recver_,id));
+ else //run recv_handler in place
+ recver_->invoke(id);
+ */
+ if (exec_ != NULL) //run recv_handler in executor
+ exec_->execute(boost::bind(&msg_handler_base<id_type>::invoke, recver_, msg->id_, msg->data_));
+ else //run recv_handler in place
+ recver_->invoke(msg->id_, msg->data_);
+
+ return true; //always return true to force sender to notify others
+ }
+
+ //claim data at sender
+ bool claim(void) {
+ if (claimed_sender_ != NULL) { //should not happen
+ claimed_sender_->unclaim_one();
+ claimed_sender_ = NULL;
+ }
+ //go-thru binding_set to claim
+ typename synch_policy::scoped_lock lock(name_->bind_lock_);
+ binding_set_type &bindings = name_->bindings_;
+ if (!bindings.empty()) {
+ for(typename binding_set_type::iterator iter = bindings.begin();
+ iter != bindings.end() && claimed_sender_ == NULL; iter++) {
+ named_out_type *named_out = (named_out_type *)(*iter);
+ sender_type *sender = (sender_type *)(named_out);
+ if(sender->claim_one()) claimed_sender_ = sender;
+ }
+ }
+ if (claimed_sender_ != NULL) return true;
+ else return false;
+ }
+
+ //
+ void unclaim(void) {
+ if (claimed_sender_ != NULL) {
+ claimed_sender_->unclaim_one();
+ claimed_sender_ = NULL;
+ }
+ }
+
+ //pull data from sender
+ int pull(boost::shared_ptr<msg_type> & msg) {
+ int sz = 0;
+ if (claimed_sender_ != NULL) {
+ sz = claimed_sender_->pull(msg);
+ claimed_sender_->unclaim_one();
+ claimed_sender_ = NULL;
+ }
+ return sz;
+ }
+ };
+
+}
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/push_dispatcher_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/push_dispatcher_base.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,143 @@
+//
+// pull_dispatcher_base.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+//// push dispatchers:
+//// define push-style message passing process:
+//// including:
+//// . provide both sender/recver sides
+
+#ifndef PUSH_DISPATCHER_BASE_HPP
+#define PUSH_DISPATCHER_BASE_HPP
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ //base sender class, shared by most push dispatchers
+ template<typename name_space, typename platform,
+ template<typename , typename > class sending_algo>
+ struct push_sender_base {
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef name<id_type,executor,synch_policy> name_type;
+ typedef message<id_type> msg_type;
+ typedef typename name_type::binding_set_type binding_set_type;
+
+ name_type * name_;
+ executor *exec_;
+ sending_algo<name_space, platform> algo;
+
+ push_sender_base(name_type * n, executor *e) : name_(n), exec_(e) {}
+
+ //assuming msgs contained inside shared_ptr
+ void push(boost::shared_ptr<msg_type> msg) {
+ typename synch_policy::scoped_lock lock(name_->bind_lock_);
+ typename name_type::binding_set_type &bindings = name_->bindings_;
+ algo(bindings, msg);
+ }
+
+ //after sending, channel becomes owner of msgs
+ template <typename user_msg_type>
+ void send(user_msg_type *msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ push (m);
+ }
+
+ //after sending: 1> channel becomes owner, if deleter does real deletion
+ // 2> sender still owns msg, if deleter does nothing
+ template <typename user_msg_type, typename deleter>
+ void send(user_msg_type *msg, deleter deler) {
+ boost::shared_ptr<void> m0(msg, deler);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ push (m);
+ }
+
+ //user_msg is already smarter pointer, channel becomes owner
+ template <typename user_msg_type>
+ void send(boost::shared_ptr<user_msg_type> msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ push (m);
+ }
+
+ //for channel internal use on wildcard named_out
+ template <typename user_msg_type>
+ void send(id_type id, boost::shared_ptr<user_msg_type> msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(id, m0));
+ push (m);
+ }
+
+ };
+
+ //base recver class, shared by most push dispatchers
+ template <typename name_space, typename platform>
+ struct push_recver_base {
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef message<id_type> msg_type;
+ typedef name<id_type,executor,synch_policy> name_type;
+
+ name_type * name_;
+ executor *exec_;
+ msg_handler_base<id_type> *recver_;
+
+ template<typename recver_type>
+ push_recver_base(name_type * n, recver_type rc, executor *e) :
+ name_(n), exec_(e)
+ {
+ recver_ = new msg_handler<id_type, recver_type>(rc);
+ }
+
+ ~push_recver_base() {
+ if (recver_ != NULL)
+ recver_->destroy();
+ }
+
+ void set_exe(executor *e) {exec_ = e;}
+
+ template<typename recver_type>
+ void set_recver(recver_type rc) {
+ if (recver_ != NULL) recver_->destroy();
+ recver_ = new msg_handler<id_type, recver_type>(rc);
+ }
+
+ //senders call this to push into here
+ void push(boost::shared_ptr<msg_type> msg)
+ {
+ if (exec_ != NULL) //run recv_handler in executor
+ exec_->execute(boost::bind(&msg_handler_base<id_type>::invoke,
+ recver_,msg->id_, msg->data_));
+ else //run recv_handler in place
+ recver_->invoke(msg->id_, msg->data_);
+ }
+
+ };
+
+ }
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/dispatchers/round_robin_dispatcher.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/dispatchers/round_robin_dispatcher.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,77 @@
+//
+// round_robin_dispatcher.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+//// pull dispatchers:
+//// define the whole message passing process:
+//// including:
+//// . sending, buffering, recving
+//// . provide both sender/recver sides
+
+#ifndef ROUND_ROBIN_DISPATCHER_HPP
+#define ROUND_ROBIN_DISPATCHER_HPP
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/dispatcher_base.hpp>
+#include <boost/channel/dispatchers/push_dispatcher_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ //we need random-access iterator for roundrobin?
+ //here a temp fix: convert set<name*> to vector<name*>
+ //for a name_space targeted for round_robin dispatching app,
+ //we should change name_space container type to vector instead of set
+ //or make name_space container type configurable?
+ template<typename name_space, typename platform>
+ class round_robin_algo {
+ public:
+ typedef typename name_space::id_type id_type;
+ typedef message<id_type> msg_type;
+ typedef push_recver_base<name_space,platform> recver_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+
+ round_robin_algo(): last_(-1) {}
+ template<typename bindings_type>
+ void operator() (bindings_type &bindings,
+ boost::shared_ptr<msg_type> msg) {
+ if (!bindings.empty()) {
+ std::vector<typename bindings_type::value_type> v(bindings.begin(), bindings.end());
+ int sz = v.size();
+ last_ = (last_+1) % sz;
+ named_in_type *named_in = (named_in_type *)(v[last_]);
+ recver_type *recver = (recver_type *)named_in;
+ recver->push(msg);
+ }
+ }
+ private:
+ int last_;
+ };
+
+ }
+
+ template <typename name_space, typename platform>
+ struct round_robin_dispatcher {
+ typedef detail::push_sender_base<name_space,platform,detail::round_robin_algo> sender;
+ typedef detail::push_recver_base<name_space,platform> recver;
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/executors/asio_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/executors/asio_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,36 @@
+//
+// asio_executor.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_EXECUTOR_HPP
+#define ASIO_EXECUTOR_HPP
+
+#include <boost/asio.hpp>
+
+namespace boost {
+ namespace channel {
+
+ //integration with Boost.Asio
+ //submit async tasks to asio's completion_event queue to be executed by main thread
+ class asio_executor {
+ public:
+ boost::asio::io_service& io_service_;
+ asio_executor(boost::asio::io_service& io_service) :
+ io_service_(io_service) {
+ }
+ template<typename task_type>
+ void execute(task_type task) {
+ io_service_.post(task);
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/executors/delayed_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/executors/delayed_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,71 @@
+//
+// delayed_executor.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef DELAYED_EXECUTOR_HPP
+#define DELAYED_EXECUTOR_HPP
+
+#include <deque>
+#include <algorithm>
+#include <boost/bind.hpp>
+#include <boost/channel/executors/executor_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ //in single-thread async app: operations can be delayed:
+ //executed later by the same (single) thread, the original calling context is gone
+ template<typename synch_policy>
+ class delayed_executor {
+ public:
+ std::deque<async_task_base *> tasks_;
+ typename synch_policy::mutex mutex_;
+
+ delayed_executor() {
+ }
+ ~delayed_executor() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<async_task_base *>::iterator iter;
+ for (iter = tasks_.begin(); iter != tasks_.end(); iter++)
+ (*iter)->destroy();
+ }
+ template<typename task_type>
+ async_task_base * execute(task_type task) {
+ async_task_base *t = new async_task<task_type> (task);
+ typename synch_policy::scoped_lock lock(mutex_);
+ tasks_.push_back(t);
+ return t;
+ }
+ bool cancel(async_task_base *task) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<async_task_base *>::iterator iter;
+ iter = std::find(tasks_.begin(), tasks_.end(), task);
+ if (iter != tasks_.end()) {
+ (*iter)->destroy();
+ tasks_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+ //complete scheduled tasks
+ void run(void) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ typename std::deque<async_task_base *>::iterator iter;
+ for (iter = tasks_.begin(); iter != tasks_.end(); iter++) {
+ (*iter)->execute();
+ (*iter)->destroy();
+ }
+ tasks_.clear();
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/executors/executor_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/executors/executor_base.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,99 @@
+//
+// executor_base.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef EXECUTOR_BASE_HPP
+#define EXECUTOR_BASE_HPP
+
+namespace boost {
+ namespace channel {
+
+ //async tasks: to be later executed in executor:
+ //1. although in same thread, not in orginal calling context
+ //2. in diff thread
+ class async_task_base {
+ public:
+ enum state {
+ waiting, running, completed
+ };
+
+ // Perform the task.
+ void execute() {
+ st_ = running;
+ exec_func_(this);
+ st_ = completed;
+ }
+
+ // Destroy the task.
+ void destroy() {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*exec_func_type)(async_task_base*);
+ typedef void (*destroy_func_type)(async_task_base*);
+
+ // Construct an task
+ async_task_base(exec_func_type exec_func, destroy_func_type destroy_func) :
+ exec_func_(exec_func), destroy_func_(destroy_func), st_(waiting) {
+ }
+
+ // Prevent deletion through this type.
+ ~async_task_base() {
+ }
+
+ private:
+ exec_func_type exec_func_;
+ destroy_func_type destroy_func_;
+ state st_;
+ };
+
+ //
+ template<typename task_type>
+ class async_task: public async_task_base {
+ public:
+ // Constructor.
+ async_task(task_type task) :
+ async_task_base(&async_task<task_type>::exec_task, &async_task<
+ task_type>::destroy_task), task_(task) {
+ }
+
+ // Invoke the task.
+ static void exec_task(async_task_base* base) {
+ static_cast<async_task<task_type>*> (base)->task_();
+ }
+
+ // Delete the task.
+ static void destroy_task(async_task_base* base) {
+ delete static_cast<async_task<task_type>*> (base);
+ }
+
+ private:
+ task_type task_;
+ };
+
+ //define an abstract class, so that it cannt be
+ //instantiated and execution must be in-line;
+ //or it can provide a base class for dynamic
+ //polymorphism of executors;
+ class abstract_executor {
+ public:
+ template<typename task_type>
+ async_task_base * execute(task_type task) {
+ return NULL;
+ }
+ virtual bool cancel(async_task_base *task) = 0;
+ virtual ~abstract_executor() {
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/executors/in_place_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/executors/in_place_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,31 @@
+//
+// in_place_executor.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef IN_PLACE_EXECUTOR_HPP
+#define IN_PLACE_EXECUTOR_HPP
+
+#include <boost/channel/executors/executor_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ //the simplest: execute async_task in place: ie. in current thread & calling context
+ class in_place_executor {
+ public:
+ template<typename task_type>
+ void execute(task_type task) {
+ task();
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/executors/thread_pool_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/executors/thread_pool_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,144 @@
+//
+// thread_pool_executor.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef THREAD_POOL_EXECUTOR_HPP
+#define THREAD_POOL_EXECUTOR_HPP
+
+#include <deque>
+#include <algorithm>
+#include <boost/thread.hpp>
+#include <boost/bind.hpp>
+#include <boost/channel/executors/executor_base.hpp>
+
+namespace boost {
+ namespace channel {
+
+ //a dedicated pool of threads to exec async tasks
+ //a simple thread pool executor with unlimited buffering
+ template<typename synch_policy>
+ class thread_pool_executor {
+ public:
+ enum state {
+ running, stop
+ };
+
+ thread_pool_executor(int num_thr) :
+ num_thr_(num_thr) {
+ st_ = running;
+ for (int i = 0; i < num_thr; i++)
+ threads_.create_thread(
+ boost::bind(&thread_pool_executor::run, this));
+ }
+
+ ~thread_pool_executor() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (st_ == running) {
+ lock.unlock();
+ shut_down_wait();
+ }
+ }
+
+ ///executor life cycle
+ state get_state(void) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ return st_;
+ }
+
+ //gracefully shut down
+ void shut_down_wait() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (st_ == running) {
+ st_ = stop;
+ lock.unlock();
+ cond_.notify_all();
+ //waiting for the threads to exit
+ threads_.join_all();
+ }
+ }
+
+ void wait() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ while (st_ == running && !tasks_.empty()) {
+ cond_wait_.wait(lock);
+ }
+ }
+
+ //abruptively shut down
+ void shut_down_now() {
+ typename synch_policy::scoped_lock lock(mutex_);
+ st_ = stop;
+ //kill threads
+ }
+
+ ///submit a task
+ template<typename task_type>
+ async_task_base * execute(task_type task) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (st_ == running) {
+ async_task_base * t = new async_task<task_type> (task);
+ tasks_.push_back(t);
+ cond_.notify_one();
+ return t;
+ }
+ return NULL;
+ }
+
+ ///scancel a task
+ bool cancel(async_task_base *task) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (st_ == running) {
+ typename std::deque<async_task_base *>::iterator iter;
+ iter = std::find(tasks_.begin(), tasks_.end(), task);
+ if (iter != tasks_.end()) {
+ (*iter)->destroy();
+ tasks_.erase(iter);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ async_task_base * next_task(void) {
+ async_task_base * t = NULL;
+ typename synch_policy::scoped_lock lock(mutex_);
+ while (tasks_.empty() && st_ != stop) {
+ cond_wait_.notify_one();
+ cond_.wait(lock);
+ }
+ if (st_ == stop)
+ return NULL;
+ t = tasks_.front();
+ tasks_.pop_front();
+ return t;
+ }
+
+ void run(void) {
+ while (st_ != stop) {
+ async_task_base * t = next_task();
+ if (st_ != stop && t != NULL)
+ t->execute();
+ }
+ }
+
+ private:
+ std::deque<async_task_base *> tasks_;
+ boost::thread_group threads_;
+ typename synch_policy::mutex mutex_;
+ typename synch_policy::condition cond_;
+ typename synch_policy::condition cond_wait_;
+ state st_;
+ int num_thr_;
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/executors/threadpool_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/executors/threadpool_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,72 @@
+//
+// threadpool_executor.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef THREADPOOL_EXECUTOR_HPP
+#define THREADPOOL_EXECUTOR_HPP
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/threadpool/threadpool.hpp>
+
+namespace boost {
+ namespace channel {
+
+ //a wrapper over Philipp Henkel's threadpool library
+ template<typename pool_type = boost::threadpool::pool<boost::function0<void>,
+ boost::threadpool::fifo_scheduler<boost::function0<void> > > >
+ class threadpool_executor {
+ public:
+ threadpool_executor(int num_thr) :
+ num_thr_(num_thr) {
+ pool_ = pool_type::create_pool(num_thr_);
+ }
+
+ ~threadpool_executor() {
+ shut_down_wait();
+ }
+
+ //gracefully shut down
+ void shut_down_wait() {
+ pool_->clear();
+ pool_->resize(0);
+ pool_->wait();
+ }
+
+ //gracefully shut down
+ void wait() {
+ pool_->wait();
+ }
+
+ //abruptively shut down
+ void shut_down_now() {
+ //how ?
+ }
+
+ ///submit a task
+ template<typename task_type>
+ bool execute(task_type task) {
+ return pool_->schedule(task);
+ }
+
+ ///cancel a task.
+ ///will implement it on top of "future" when it becomes available soon
+ bool cancel(async_task_base *task) {
+ return true;
+ }
+
+ private:
+ int num_thr_;
+ boost::shared_ptr<pool_type> pool_;
+ };
+
+}
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/interface.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/interface.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,513 @@
+//
+// interface.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef INTERFACE_HPP
+#define INTERFACE_HPP
+
+#include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/channel/binder.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/broadcast_dispatcher.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/peer.hpp>
+#include <boost/channel/name.hpp>
+
+namespace boost {
+ namespace channel {
+
+ //interface to other channels or streams
+ template<typename channel>
+ class interface: public peer_type<typename channel::id_type> {
+ public:
+ enum state_type {
+ intf_init = 0, intf_active
+ };
+
+ typedef typename channel::platform platform;
+ typedef typename channel::name_space_type name_space;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename channel::id_type id_type;
+ typedef typename channel::id_trait id_trait;
+ typedef typename name_space::name name;
+ typedef named_out<name_space, typename broadcast_dispatcher<name_space,platform>::sender > ns_named_out;
+ typedef typename channel::out named_out;
+ typedef typename channel::in named_in;
+ typedef peer_type<id_type> peer_type;
+ typedef message<id_type> message_type;
+ // typedef connection<id_type> connection_type;
+ typedef typename channel::connection connection_type;
+ typedef typename channel::executor executor;
+ typedef named_out_bundle<name_space, typename broadcast_dispatcher<name_space,platform>::sender> ns_named_out_bundle;
+ typedef named_in_bundle<name_space, typename broadcast_dispatcher<name_space,platform>::recver> ns_named_in_bundle;
+ typedef named_out_bundle<name_space, typename channel::dispatch_policy::sender> named_out_bundle;
+ typedef named_in_bundle<name_space, typename channel::dispatch_policy::recver> named_in_bundle;
+ typedef binder_type<id_type> binder_type;
+ typedef translator_type<id_type> translator_type;
+ typedef filter_type<id_type> filter_type;
+ typedef pubsub_info_msg_t<id_type> pubsub_info_msg_t;
+
+ typedef interface<channel> interface_type;
+
+ private:
+ ///
+ channel &ch_;
+ state_type state_;
+
+ //ids bound at local channel
+ //for namespace change, using broadcast dispatching
+ ns_named_in_bundle ns_named_ins_;
+ ns_named_out_bundle ns_named_outs_;
+ //for application messages, using channel specific dispatching
+ named_in_bundle named_ins_;
+ named_out_bundle named_outs_;
+
+ ///outgoing-msg buffering when connection to remote peer is not ready yet
+ std::vector<boost::shared_ptr<message_type> > pending_msgs_;
+ typename synch_policy::mutex lock_;///lock to maintain interface internal state
+
+ ///filter & translators: policies for remote connections
+ filter_type *filter_;
+ translator_type *translator_;
+
+ public:
+ interface (channel &chan, binder_type *binder) :
+ ch_(chan),
+ ns_named_ins_(chan, boost::bind(&interface::recv,this, _1,_2), name_base::member_remote),
+ ns_named_outs_(chan, name_base::member_remote),
+ named_ins_(chan, boost::bind(&interface::recv,this, _1,_2),name_base::member_remote),
+ named_outs_(chan, name_base::member_remote)
+ {
+ state_ = intf_init;
+ ch_.add_intf(this);
+ if (binder == NULL) {
+ filter_ = NULL;
+ translator_ = NULL;
+ } else {
+ filter_ = binder->filter;
+ translator_ = binder->translator;
+ }
+ //subscribe to system msgs from local channel on behalf of the remote side
+ //since channel_(DIS)CONN_msg and init_SUB/PUB_info_msg
+ //are generated inside interface, no need to subscribe to them in channels
+ ns_named_ins_.bind(channel::subscription_info_msg, name_base::scope_local);
+ ns_named_ins_.bind(channel::unsubscription_info_msg, name_base::scope_local);
+ ns_named_ins_.bind(channel::publication_info_msg, name_base::scope_local);
+ ns_named_ins_.bind(channel::unpublication_info_msg, name_base::scope_local);
+ //publish system msgs at local channel on behalf of the remote side
+ ns_named_outs_.bind(channel::channel_conn_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::channel_disconn_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::init_subscription_info_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::connection_ready_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::subscription_info_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::unsubscription_info_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::publication_info_msg, name_base::scope_local);
+ ns_named_outs_.bind(channel::unpublication_info_msg, name_base::scope_local);
+ }
+
+ ~interface ()
+ {
+ //destructors of named_in/out_bundles will unbind and destroy
+ //all named_in_out objects; so we dont need to explicitly unbind/delete
+ //named_ins_,named_outs_,ns_named_ins_,ns_named_outs_
+ ch_.del_intf(this);
+ platform::log("... interface destructor called ...");
+ }
+
+ /*
+ void unbind() {
+ //unbind app ids at remote end
+ platform::log("... interface unbind enter ...");
+ std::vector<id_type> ids;
+ typename std::vector<id_type>::iterator iter;
+ if (named_ins_.get_ids(ids)) {
+ for(iter = ids.begin(); iter != ids.end(); iter++)
+ send2remote_pubsub_msg (name_base::unbind_in_ev, *iter);
+ }
+ ids.clear();
+ if (named_outs_.get_ids(ids)) {
+ for(iter = ids.begin(); iter != ids.end(); iter++)
+ send2remote_pubsub_msg (name_base::unbind_out_ev, *iter);
+ }
+ peer_type::unbind();
+ platform::log("... interface unbind exit ...");
+ }
+ */
+
+ bool sys_msg(id_type id) {
+ if(id == channel::channel_conn_msg ||
+ id == channel::channel_disconn_msg ||
+ id == channel::init_subscription_info_msg ||
+ id == channel::connection_ready_msg ||
+ id == channel::subscription_info_msg ||
+ id == channel::unsubscription_info_msg ||
+ id == channel::publication_info_msg ||
+ id == channel::unpublication_info_msg)
+ return true;
+ return false;
+ }
+
+ ///called from inside channel, forward msgs from inside channel to peers
+ void recv(id_type id, boost::shared_ptr<void> msg)
+ {
+ platform::log("interface::recv ["+id_trait::id_to_string(id)+"]");
+ if(state_ != intf_active) {
+ boost::shared_ptr<message_type> m(new message_type(id,msg));
+ add_pending_msg(m);
+ platform::log("... msgs["+id_trait::id_to_string(id)+"] buffered ");
+ } else {
+ bool need_send = false;
+
+ if (sys_msg(id)) {
+ //check pub/unpub, sub/unsub msgs
+ pubsub_info_msg_t *info = (pubsub_info_msg_t *)msg.get();
+ if (id == channel::subscription_info_msg) {
+ for(size_t i=0; i<info->msg_types.size() && !need_send; i++) {
+ if (filter_ != NULL && filter_->block_inward(info->msg_types[i]))
+ continue;
+ if (!sys_msg(info->msg_types[i]) && named_outs_.find(info->msg_types[i]) == NULL) {
+ if (translator_ != NULL)
+ translator_->translate_outward(info->msg_types[i]);
+ need_send = true;
+ }
+ }
+ }
+ else if (id == channel::unsubscription_info_msg) {
+ for(size_t i=0; i<info->msg_types.size() && !need_send; i++) {
+ named_out *no;
+ if (!sys_msg(info->msg_types[i]) && (no = named_outs_.find(info->msg_types[i])) != NULL) {
+ if (no->num_bindings() == 0) {
+ if (translator_ != NULL)
+ translator_->translate_outward(info->msg_types[i]);
+ need_send = true;
+ }
+ }
+ }
+ }
+ else if (id == channel::publication_info_msg) {
+ for(size_t i=0; i<info->msg_types.size() && !need_send; i++) {
+ if (filter_ != NULL && filter_->block_outward(info->msg_types[i]))
+ continue;
+ if (!sys_msg(info->msg_types[i]) && named_ins_.find(info->msg_types[i]) == NULL) {
+ if (translator_ != NULL)
+ translator_->translate_outward(info->msg_types[i]);
+ need_send = true;
+ }
+ }
+ }
+ else if (id == channel::unpublication_info_msg) {
+ for(size_t i=0; i<info->msg_types.size() && !need_send; i++) {
+ named_in *ni;
+ if (!sys_msg(info->msg_types[i]) && (ni = named_ins_.find(info->msg_types[i])) != NULL) {
+ if (ni->num_bindings() == 0) {
+ if (translator_ != NULL)
+ translator_->translate_outward(info->msg_types[i]);
+ need_send = true;
+ }
+ }
+ }
+ }
+ } else { //applicaion msgs
+ //translate application msgs if set
+ if (translator_ != NULL) {
+ translator_->translate_outward(id);
+ }
+ need_send = true;
+ }
+
+ if(need_send)
+ peer_send(id, msg);
+ }
+ }
+
+ ///called by peers, forward msgs from outside peer to channel
+ void send(id_type id, boost::shared_ptr<void> msg)
+ {
+ platform::log("interface::send_msg: recv MSG ["+id_trait::id_to_string(id)+"]...");
+ pubsub_info_msg_t *subinfo;
+
+ /// --- connection setup hand-shaking ----
+ if (id == channel::channel_conn_msg) {
+ //connector or stream should already intercept this msg for its own internal
+ //processing, such as connection management; here we forward it to subscribed
+ //user code
+ switch(this->role_) {
+ case peer_type::active_role:
+ platform::log("active end recv channel_info_msg ...");
+ send2remote_init_subscribe_msg();
+ break;
+ case peer_type::passive_role:
+ platform::log("passive end recv channel_info_msg ...");
+ ///send my chan info
+ send2remote_channel_info_msg();
+ break;
+ default:
+ break;
+ }
+ }
+ else if(id == channel::channel_disconn_msg) {
+ //connector or stream should already intercept this msg for its own internal
+ //processing, such as connection management; here we forward it to subscribed
+ //user code
+ }
+ else if (id == channel::init_subscription_info_msg) {
+ platform::log("recv init_subscription_info_msg...");
+ subinfo = (pubsub_info_msg_t *)msg.get();
+ std::vector<id_type> pub_msgs;
+ ch_.bound_ids_for_out(name::exported_name, pub_msgs);
+ for(size_t i=0; i<subinfo->msg_types.size(); i++) {
+ if (translator_ != NULL)
+ translator_->translate_inward(subinfo->msg_types[i]);
+ if (filter_ != NULL && filter_->block_outward(subinfo->msg_types[i]))
+ continue;
+ if(std::find_if(pub_msgs.begin(), pub_msgs.end(),
+ boost::bind(&id_trait::match, _1, subinfo->msg_types[i])) !=
+ pub_msgs.end()) {
+ platform::log("remote subsc to ["+id_trait::id_to_string(subinfo->msg_types[i])+"]");
+ named_ins_.bind(subinfo->msg_types[i], name_base::scope_local);
+ send2remote_pubsub_msg (name_base::bind_out_ev, subinfo->msg_types[i]);
+ }
+ }
+ if(this->role_ == peer_type::passive_role) {
+ ///send my subscription info
+ send2remote_init_subscribe_msg();
+ } else if(this->role_ == peer_type::active_role) {
+ send2remote_conn_ready_msg();
+ }
+ } else if (id == channel::connection_ready_msg) {
+ platform::log("recv conn_ready...");
+ platform::log((this->role_ == peer_type::active_role)?"i am active":"i am passive");
+ state_ = intf_active;
+ platform::log("conn active now...");
+ resend_pending_msgs();
+ if (this->role_ == peer_type::passive_role) {
+ send2remote_conn_ready_msg();
+ }
+ }
+ /// --- name_space change msgs during normal operations ---
+ ///init_sub_msgs
+ else if (id == channel::subscription_info_msg) {
+ platform::log("recv subscription_info_msg ...");
+ subinfo = (pubsub_info_msg_t *)msg.get();
+ std::vector<id_type> global_msgs;
+ ch_.bound_ids_for_out(name::exported_name, global_msgs);
+ for(size_t i=0; i<subinfo->msg_types.size(); i++) {
+ if (translator_ != NULL)
+ translator_->translate_inward(subinfo->msg_types[i]);
+ if (filter_ != NULL && filter_->block_outward(subinfo->msg_types[i]))
+ continue;
+ if (named_ins_.find(subinfo->msg_types[i]) == NULL) {
+ if(std::find_if(global_msgs.begin(), global_msgs.end(),
+ boost::bind(&id_trait::match, _1, subinfo->msg_types[i])) !=
+ global_msgs.end()) {
+ platform::log("remote subsc to ["+id_trait::id_to_string(subinfo->msg_types[i])+"]");
+ if(named_ins_.bind(subinfo->msg_types[i], name_base::scope_local))
+ send2remote_pubsub_msg (name_base::bind_out_ev, subinfo->msg_types[i]);
+ }
+ }
+ }
+ }
+ else if (id == channel::unsubscription_info_msg) {
+ platform::log("recv unsubscription_info_msg...");
+ subinfo = (pubsub_info_msg_t *)msg.get();
+ for(size_t i=0; i<subinfo->msg_types.size(); i++) {
+ if (translator_ != NULL)
+ translator_->translate_inward(subinfo->msg_types[i]);
+ if(named_ins_.unbind(subinfo->msg_types[i]))
+ send2remote_pubsub_msg (name_base::unbind_out_ev, subinfo->msg_types[i]);
+ }
+ }
+ else if (id == channel::publication_info_msg) {
+ platform::log("recv publication_info_msg...");
+ pubsub_info_msg_t *pubinfo = (pubsub_info_msg_t *)msg.get();
+ std::vector<id_type> mtypes;
+ ch_.bound_ids_for_in(name::exported_name, mtypes);
+ for(size_t i=0; i<pubinfo->msg_types.size(); i++) {
+ if (translator_ != NULL)
+ translator_->translate_inward(pubinfo->msg_types[i]);
+ if (filter_ != NULL && filter_->block_inward(pubinfo->msg_types[i]))
+ continue;
+ if (named_outs_.find (pubinfo->msg_types[i]) == NULL) {
+ //platform::log("remote pub msg, try to match ["+id_trait::id_to_string(pubinfo->msg_types[i])+"]");
+ if(std::find_if(mtypes.begin(), mtypes.end(),
+ boost::bind(&id_trait::match, _1, pubinfo->msg_types[i])) !=
+ mtypes.end()) {
+ platform::log("remote pub msg ["+id_trait::id_to_string(pubinfo->msg_types[i])+"]");
+ ///remote msgs only for local destinations
+ if(named_outs_.bind (pubinfo->msg_types[i], name_base::scope_local))
+ send2remote_pubsub_msg(name_base::bind_in_ev, pubinfo->msg_types[i]);
+ }
+ }
+ }
+ }
+ else if (id == channel::unpublication_info_msg) {
+ platform::log("recv unpublication_info_msg...");
+ subinfo = (pubsub_info_msg_t *)msg.get();
+ for(size_t i=0; i<subinfo->msg_types.size(); i++) {
+ if (translator_ != NULL)
+ translator_->translate_inward(subinfo->msg_types[i]);
+ if(named_outs_.unbind(subinfo->msg_types[i]))
+ send2remote_pubsub_msg (name_base::unbind_in_ev, subinfo->msg_types[i]);
+ }
+ }
+ /// --- application msgs ----
+ else {
+ //application msgs go to channel
+ //translate it if set
+ if (translator_ != NULL) {
+ translator_->translate_inward(id);
+ }
+ //platform::log("recv an application msg ["+id_trait::id_to_string(id)+"]");
+ }
+
+ ///forward all msgs to local channel
+ if(sys_msg(id)) { //forward system msgs
+ ns_named_out *no = ns_named_outs_.find(id);
+ if (no != NULL)
+ no->send (msg);
+ }
+ else { //forward application msgs
+ typename channel::out *no = named_outs_.find(id); //find exact match
+ if (no != NULL) { //exact match found
+ no->send (msg);
+ } else {
+ //platform::log("interface::send try to match a local wildcard with name: "+id_trait::id_to_string(id));
+ no = named_outs_.find_match(id);
+ if (no != NULL) { //assoc/fuzzy match found
+ if (id_trait::wildcard_name(no->id_)) {
+ platform::log("interface::send match a local wildcard name: "+id_trait::id_to_string(no->id_));
+ no->send (id,msg);
+ } else
+ no->send (msg);
+ }
+ }
+ }
+ }
+
+ ///send owner channel info to remote
+ void send2remote_channel_info_msg(void)
+ {
+ platform::log("send_chan_info_to_remote...");
+ std::pair<typename peer_type::type, std::string> info = this->peer_get_info();
+ boost::shared_ptr<channel_info_msg_t> msg(new channel_info_msg_t());
+ msg->intf = this;
+ msg->is_local = true;
+ if (info.first == peer_type::remote_peer)
+ {
+ msg->is_local = false;
+ msg->host_addr = info.second;
+ }
+ peer_send(channel::channel_conn_msg,msg);
+ }
+
+ private:
+
+ /**
+ * methods handling msg buffering before remote connection is ready
+ */
+ void add_pending_msg(boost::shared_ptr<message_type> m) {
+ typename synch_policy::scoped_lock lock(lock_);
+ pending_msgs_.push_back(m);
+ }
+ void resend_pending_msgs(void)
+ {
+ if(this->peer_ != NULL) {
+ typename synch_policy::scoped_lock lock(lock_);
+ for(size_t i=0; i<pending_msgs_.size();i++) {
+ boost::shared_ptr<message_type> m = pending_msgs_[i];
+ peer_send(m->id_,m->data_);
+ platform::log("...resend 1 msg");
+ }
+ pending_msgs_.clear();
+ }
+ }
+
+ /* ----- */
+
+ ///send channel conn ready msg to remote
+ void send2remote_conn_ready_msg(void)
+ {
+ platform::log("send_conn_ready_to_remote...");
+ std::pair<typename peer_type::type, std::string> info = this->peer_get_info();
+ boost::shared_ptr<channel_info_msg_t> msg(new channel_info_msg_t());
+ msg->intf = this;
+ msg->is_local = true;
+ if (info.first == peer_type::remote_peer)
+ {
+ msg->is_local = false;
+ msg->host_addr = info.second;
+ }
+ peer_send(channel::connection_ready_msg,msg);
+ }
+
+ ///when 2 channels just connected, send all current sub info
+ ///to remote
+ void send2remote_init_subscribe_msg(void)
+ {
+ ///send subscription msg
+ boost::shared_ptr<pubsub_info_msg_t> sub(new pubsub_info_msg_t());
+ std::vector<id_type> mtypes;
+ ch_.bound_ids_for_in(name::exported_name, mtypes);
+ for(size_t i=0; i<mtypes.size(); i++) {
+ if (sys_msg(mtypes[i]) || (filter_ != NULL && filter_->block_inward(mtypes[i])))
+ continue;
+ if (translator_ != NULL)
+ translator_->translate_outward(mtypes[i]);
+ sub->msg_types.push_back(mtypes[i]);
+ }
+ platform::log("send init_subscription info...");
+ peer_send(channel::init_subscription_info_msg, sub);
+ }
+
+ ///forward local/owner channel memebers' pub/sub operations to remote
+ void send2remote_pubsub_msg(typename name_base::binding_event op, id_type t)
+ {
+ boost::shared_ptr<pubsub_info_msg_t> sub(new pubsub_info_msg_t());
+ id_type mt;
+ switch(op) {
+ case name_base::bind_out_ev:
+ if (filter_ != NULL && filter_->block_outward(t)) {
+ return;
+ }
+ mt = channel::publication_info_msg;
+ platform::log("interface::send2remote_pubsub_msg publish ");
+ break;
+ case name_base::unbind_out_ev:
+ mt = channel::unpublication_info_msg;
+ platform::log("interface::send2remote_pubsub_msg unpublish ");
+ break;
+ case name_base::bind_in_ev:
+ if (filter_ != NULL && filter_->block_inward(t)) {
+ return;
+ }
+ mt = channel::subscription_info_msg;
+ platform::log("interface::send2remote_pubsub_msg subscribe ");
+ break;
+ case name_base::unbind_in_ev:
+ mt = channel::unsubscription_info_msg;
+ platform::log("interface::send2remote_pubsub_msg unsubscribe ");
+ break;
+ default:
+ platform::log("interface::send2remote_pubsub_msg invalid id_type ");
+ return;
+ }
+ if (translator_ != NULL)
+ translator_->translate_outward(t);
+ sub->msg_types.push_back(t);
+ peer_send(mt, sub);
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/marshaler.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/marshaler.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,254 @@
+//
+// marshaler.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef MARSHALER_HPP
+#define MARSHALER_HPP
+
+#include <vector>
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/xml_iarchive.hpp>
+#include <boost/archive/xml_oarchive.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/binary_object.hpp>
+#include <boost/serialization/vector.hpp>
+
+/**
+ * marshaling & demarshaling : msg converting : typed info <-> untyped stream
+ * here we use Boost.Serialization text_archive for conversion.
+ * other choices: binary archive or xml archives
+ *
+ * 2 steps to enable marshaling for a message type:
+ * 1> define a free serialize function for it (non-intrusive)
+ * 2> register the type with marshaler_registry:
+ * marshaler_registry.register<msg_type>(id);
+ *
+ * for msg types using PODS: struct without virtual methods, dont
+ * need define any serialization methods or register marshalers, the
+ * default marshaler<void_type> does byte-copy and will be enough
+ */
+
+namespace boost {
+ namespace channel {
+
+ ///interface of all message marshalers
+ class msg_marshaler {
+ public:
+ virtual void marshal(boost::shared_ptr<void> &msg, std::string &buf) = 0;
+ virtual void demarshal(std::string &buf, boost::shared_ptr<void> &msg) = 0;
+ virtual ~msg_marshaler() {
+ }
+ };
+
+ ///interface of all id marshalers
+ template<typename id_type>
+ class id_marshaler {
+ public:
+ virtual void marshal(const id_type &id, std::string &buf) = 0;
+ virtual void demarshal(std::string &buf, id_type &id) = 0;
+ virtual ~id_marshaler() {
+ }
+ };
+
+ ///grouping of archives
+ enum marshaling_archive_type {
+ text_archive, binary_archive, xml_archive
+ };
+
+ template<int> class marshaling_archives;
+
+ template<>
+ struct marshaling_archives<text_archive> {
+ typedef boost::archive::text_oarchive oarchive;
+ typedef boost::archive::text_iarchive iarchive;
+ };
+
+ template<>
+ struct marshaling_archives<binary_archive> {
+ typedef boost::archive::binary_oarchive oarchive;
+ typedef boost::archive::binary_iarchive iarchive;
+ };
+
+ template<>
+ struct marshaling_archives<xml_archive> {
+ typedef boost::archive::xml_oarchive oarchive;
+ typedef boost::archive::xml_iarchive iarchive;
+ };
+
+ /**
+ * --------- id marshaler types --------------
+ */
+ template<typename id_type, int archive_type>
+ class id_marshaler_impl: public id_marshaler<id_type> {
+ void marshal(const id_type &id, std::string &buf) {
+ std::ostringstream archive_stream;
+ typename marshaling_archives<archive_type>::oarchive archive(archive_stream);
+ archive << id;
+ buf = archive_stream.str();
+ }
+ void demarshal(std::string &buf, id_type &id) {
+ std::istringstream archive_stream(buf);
+ typename marshaling_archives<archive_type>::iarchive archive(archive_stream);
+ archive >> id;
+ }
+ };
+
+ /**
+ * --------- message marshaler types --------------
+ */
+ //struct void_type {};
+
+ ///---- text_marshaler: marshal typed message using text_archive ----
+ template<typename msg_type, int archive_type>
+ class msg_marshaler_impl: public msg_marshaler {
+ public:
+ void marshal(boost::shared_ptr<void> &msg, std::string &buf) {
+ /// must be const pointer, otherwise marshaling will fail
+ msg_type * const data = (msg_type *) msg.get();
+ std::ostringstream archive_stream;
+ typename marshaling_archives<archive_type>::oarchive archive(archive_stream);
+ archive << data;
+ buf = archive_stream.str();
+ }
+ void demarshal(std::string &buf, boost::shared_ptr<void> &msg) {
+ msg_type * data; ///to support marshaling, msg_type need support default constructor
+ std::istringstream archive_stream(buf);
+ typename marshaling_archives<archive_type>::iarchive archive(archive_stream);
+ archive >> data;
+ msg.reset(data);
+ }
+ };
+
+ /*
+ /// binary copy text_marshaler, used as default
+ template <int archive_type>
+ struct msg_marshaler_impl<void_type, archive_type> : public msg_marshaler {
+ void marshal(boost::shared_ptr<void> &msg, int sz, std::string &buf)
+ {
+ std::ostringstream archive_stream;
+ typename marshaling_archives<archive_type>::oarchive archive(archive_stream);
+ archive << boost::serialization::make_binary_object(msg.get(), sz);
+ buf = archive_stream.str();
+ }
+ void demarshal(std::string &buf, boost::shared_ptr<void> &msg, int &sz)
+ {
+ sz = buf.size();
+ char *data = new char[sz]; //for binary obj, we have to alloc space
+ std::istringstream archive_stream(buf);
+ typename marshaling_archives<archive_type>::iarchive archive(archive_stream);
+ archive >> boost::serialization::make_binary_object(data, sz);
+ msg.reset(data);
+ }
+ };
+ */
+
+ /**
+ * -------------- xml_marshaler -----------
+ */
+
+ /**
+ * marshaler registration map:
+ * for simple application, all remote connections can share a marshaler_registry
+ * for applications involving diff marshaling strategies for diff remote
+ * connections, several marshaler_registries can be used; each stream object
+ * will use its own marshaler_registry
+ */
+
+ template<typename id_type, typename id_trait, typename synch_policy, int archive_type = text_archive>
+ class marshaler_registry {
+ private:
+ //marshaler registration
+ std::map<id_type, boost::shared_ptr<msg_marshaler> > mar_tbl_;
+ //msg_marshaler_impl<void_type, archive_type> bin_mar_;
+ id_marshaler_impl<id_type, archive_type> id_mar_;
+ msg_marshaler *default_mar_;
+ typename synch_policy::mutex mar_tbl_lock_;
+ public:
+ typedef id_marshaler<id_type> id_marshaler;
+ marshaler_registry() :
+ default_mar_(NULL) {
+ //register marshaler for system internal msgs
+ std::vector<id_type> ids;
+ ids.push_back(id_trait::channel_conn_msg);
+ ids.push_back(id_trait::channel_disconn_msg);
+ ids.push_back(id_trait::connection_ready_msg);
+ register_msg_marshaler<channel_info_msg_t> (ids);
+
+ ids.clear();
+ ids.push_back(id_trait::init_subscription_info_msg);
+ ids.push_back(id_trait::subscription_info_msg);
+ ids.push_back(id_trait::unsubscription_info_msg);
+ ids.push_back(id_trait::publication_info_msg);
+ ids.push_back(id_trait::unpublication_info_msg);
+ register_msg_marshaler<pubsub_info_msg_t<id_type> > (ids);
+ }
+
+ ~marshaler_registry() {
+ if (default_mar_ != NULL)
+ delete default_mar_;
+ }
+
+ template<typename msg_type>
+ void register_default_msg_marshaler(void) {
+ typename synch_policy::scoped_lock lock(mar_tbl_lock_);
+ if (default_mar_ != NULL)
+ delete default_mar_;
+ default_mar_ = new msg_marshaler_impl<msg_type, archive_type> ();
+ }
+
+ template<typename msg_type>
+ void register_msg_marshaler(id_type id) {
+ typename synch_policy::scoped_lock lock(mar_tbl_lock_);
+ boost::shared_ptr<msg_marshaler> mar(new msg_marshaler_impl<msg_type, archive_type> ());
+ mar_tbl_[id] = mar;
+ }
+
+ template<typename msg_type>
+ void register_msg_marshaler(std::vector<id_type> &ids) {
+ typename synch_policy::scoped_lock lock(mar_tbl_lock_);
+ boost::shared_ptr<msg_marshaler> mar(new msg_marshaler_impl<msg_type, archive_type> ());
+ for (typename std::vector<id_type>::iterator iter = ids.begin(); iter != ids.end(); iter++) {
+ mar_tbl_[*iter] = mar;
+ }
+ }
+
+ msg_marshaler * get_msg_marshaler(id_type id) {
+ typename synch_policy::scoped_lock lock(mar_tbl_lock_);
+ if (mar_tbl_.find(id) != mar_tbl_.end())
+ return mar_tbl_[id].get();
+ else
+ //if(default_mar_ != NULL)
+ return default_mar_;
+ /*
+ else
+ return &bin_mar_; //default byte-copy
+ */
+ }
+
+ //return default marshaler
+ msg_marshaler * get_msg_marshaler(void) {
+ //if(default_mar_ != NULL)
+ return default_mar_;
+ //return &bin_mar_;
+ }
+
+ id_marshaler * get_id_marshaler(void) {
+ return &id_mar_;
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/message.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/message.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,135 @@
+//
+// message.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef MESSAGE_HPP
+#define MESSAGE_HPP
+
+#include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/split_member.hpp>
+#include <boost/serialization/binary_object.hpp>
+#include <boost/serialization/array.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<typename id_type>
+ struct message {
+ id_type id_;
+ boost::shared_ptr<void> data_;
+ message(id_type id, boost::shared_ptr<void> d) :
+ id_(id), data_(d) {
+ }
+ message() {
+ }
+ };
+
+ /**
+ * block messages: for passing a continuous memory blocks as messages, such as
+ * data classes marshaled as bindary objects (void *) and arrays
+ */
+ template<typename T>
+ struct binary_message {
+ size_t size_;
+ boost::shared_ptr<void> data_;
+ binary_message() :
+ size_(0), data_() {
+ }
+ binary_message(T *d, size_t s) :
+ size_(s), data_(d) {
+ }
+ binary_message(boost::shared_ptr<void> d, size_t s) :
+ size_(s), data_(d) {
+ }
+ ~binary_message() {
+ } //shared_ptr should clean up data_
+ template<class Archive>
+ void save(Archive & ar, const unsigned int version) const {
+ ar & size_;
+ ar & boost::serialization::make_binary_object(data_.get(), size_);
+ }
+ template<class Archive>
+ void load(Archive & ar, const unsigned int version) {
+ ar & size_;
+ data_ = new char[size_];
+ ar & boost::serialization::make_binary_object(data_.get(), size_);
+ }
+ };
+
+ template<typename T>
+ struct array_message {
+ size_t size_;
+ boost::shared_array<T> data_;
+ array_message() :
+ size_(0), data_() {
+ }
+ array_message(T *d, size_t s) :
+ size_(s), data_(d) {
+ }
+ array_message(boost::shared_array<T> d, size_t s) :
+ size_(s), data_(d) {
+ }
+ ~array_message() {
+ } //shared_ptr should clean up data_
+ template<class Archive>
+ void save(Archive & ar, const unsigned int version) const {
+ ar & size_;
+ ar & boost::serialization::make_array<T>(data_.get(), size_);
+ }
+ template<class Archive>
+ void load(Archive & ar, const unsigned int version) {
+ ar & size_;
+ data_ = new T[size_];
+ ar & boost::serialization::make_array<T>(data_.get(), size_);
+ }
+ };
+
+ /**
+ * Channel Management Msg types
+ */
+ ///when 2 channels connects, channel_info_msg is sent to tell
+ ///peers about the channel info
+ struct channel_info_msg_t {
+ std::string host_addr;
+ void *intf; ///the interface connect to peer
+ bool is_local;
+ channel_info_msg_t() {
+ intf = NULL;
+ is_local = false;
+ }
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar & host_addr;
+ }
+
+ };
+
+ ///pubsub_info_msg is used to notify peer channels about
+ ///publish/subscribe events
+ template<class id_type>
+ struct pubsub_info_msg_t {
+ std::vector<id_type> msg_types;
+ pubsub_info_msg_t() {
+ }
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar & msg_types;
+ }
+
+ };
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/name.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,273 @@
+//
+// name.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef NAME_HPP
+#define NAME_HPP
+
+#include <list>
+#include <map>
+#include <algorithm>
+#include <boost/utility.hpp>
+#include <boost/bind.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/config.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ //name binding callback; should i use boost::function?
+ template<typename name>
+ class binding_callback_base {
+ public:
+ void invoke(name *n, typename name::binding_event e) {
+ invoke_func_(this, n, e);
+ }
+
+ void destroy() {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void
+ (*invoke_func_type)(binding_callback_base*, name *n, typename name::binding_event e);
+ typedef void (*destroy_func_type)(binding_callback_base*);
+
+ binding_callback_base(invoke_func_type invoke_func, destroy_func_type destroy_func) :
+ invoke_func_(invoke_func), destroy_func_(destroy_func) {
+ }
+
+ ~binding_callback_base() {
+ }
+
+ private:
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ template<typename name, typename handler_type>
+ class binding_callback: public binding_callback_base<name> {
+ public:
+ binding_callback(handler_type handler) :
+ binding_callback_base<name> (&binding_callback<name, handler_type>::invoke_handler,
+ &binding_callback<name, handler_type>::destroy_handler), handler_(handler) {
+ }
+
+ static void invoke_handler(binding_callback_base<name>* base, name *n,
+ typename name::binding_event e) {
+ static_cast<binding_callback<name, handler_type>*> (base)->handler_(n, e);
+ }
+
+ static void destroy_handler(binding_callback_base<name>* base) {
+ delete static_cast<binding_callback<name, handler_type>*> (base);
+ }
+
+ private:
+ handler_type handler_;
+ };
+
+ }
+
+ class BOOST_CHANNEL_DECL name_base {
+ public:
+ enum scope_type {
+ scope_local = 0, scope_remote, scope_global, scope_number
+ };
+
+ enum member_type {
+ member_all = -1, member_local = 0,//local queues and callbacks
+ member_remote, //interfaces to remote/local name_spaces
+ member_number
+ };
+
+ enum binding_event {
+ bind_out_ev = 0, unbind_out_ev, bind_in_ev, unbind_in_ev, bind_ev, unbind_ev
+ };
+
+ ///binding scope checking table:
+ ///row: publish_member_type * scope_number + publish_scope
+ ///col: subscribe_member_type * scope_number + subscribe_scope
+ ///since "remote" members can only send_to/recv_from "local"
+ ///members, only the upper-left 4x4 sub-matrix have value
+ ///value "1" marks a valid combo of publisher(row) sending to subscriber(col)
+ ///value "0" marks invalid
+ static short scope_checking_tbl_[][name_base::scope_number * name_base::member_number];
+ };
+
+ /// "name" should be noncopyable; otherwise the connection between
+ /// named_in and named_out will be messed up
+ template<typename id_type, typename executor, typename synch_policy>
+ class BOOST_CHANNEL_DECL name: public name_base, private boost::noncopyable {
+ public:
+
+ typedef std::list<name *> binding_set_type;
+
+ id_type id_;
+ typename name_base::scope_type scope_;
+ typename name_base::member_type type_;
+ executor *exec_;
+
+ typename synch_policy::mutex bind_lock_;
+ std::list<name *> bindings_;
+ detail::binding_callback_base<name> *binding_cb_;
+
+ /*
+ template <typename id_type, typename synch_policy>
+ friend bool operator< (const name<id_type,synch_policy> &left,
+ const name<id_type,synch_policy> &right);
+ */
+ protected:
+ //make constructor protected, so only children can be created
+ template<typename binding_cb_type>
+ name(id_type id, scope_type scope, member_type type, binding_cb_type cb, executor *e) :
+ id_(id), scope_(scope), type_(type), exec_(e), binding_cb_(new detail::binding_callback<name,
+ binding_cb_type>(cb)) {
+ }
+
+ name(id_type id, scope_type scope, member_type type) :
+ id_(id), scope_(scope), type_(type), exec_(NULL), binding_cb_(NULL) {
+ }
+
+ name() :
+ id_(), scope_(scope_local), type_(member_local), exec_(NULL), binding_cb_(NULL) {
+ }
+
+ ~name() {
+ unbind_all(); //detach all peers
+ if (binding_cb_ != NULL)
+ binding_cb_->destroy();
+ }
+
+ template<typename binding_cb_type>
+ void set_name(id_type id, scope_type scope, member_type type, binding_cb_type cb, executor *e) {
+ id_ = id;
+ scope_ = scope;
+ type_ = type;
+ exec_ = e;
+ binding_cb_ = new detail::binding_callback<name, binding_cb_type>(cb);
+ }
+
+ void set_name(id_type id, scope_type scope, member_type type) {
+ id_ = id;
+ scope_ = scope;
+ type_ = type;
+ }
+
+ void binding_callback(name *n, binding_event e) {
+ if (binding_cb_ != NULL) {
+ if (exec_ != NULL) //execute binding callback in executor
+ exec_->execute(boost::bind(&detail::binding_callback_base<name>::invoke, binding_cb_,
+ n, e));
+ else
+ //execute in place
+ binding_cb_->invoke(n, e);
+ }
+ }
+
+ public:
+ int num_bindings(void) {
+ return bindings_.size();
+ }
+ std::list<name *> & bindings(void) {
+ return bindings_;
+ }
+
+ //validate the src and dest scope matches
+ static bool scope_checking(name *src, name *dst) {
+ short src_row = src->type_ * name_base::scope_number + src->scope_;
+ short dst_col = dst->type_ * name_base::scope_number + dst->scope_;
+ return name_base::scope_checking_tbl_[src_row][dst_col] == 1;
+ }
+
+ //the following 2 callbacks invoked by name_space to notify binding changes
+ void bind(name *n) {
+ typename synch_policy::scoped_lock lock(bind_lock_);
+ //add n to bindings_
+ if (std::find(bindings_.begin(), bindings_.end(), n) == bindings_.end()) {
+ bindings_.push_front(n);
+ //callback
+ binding_callback(n, bind_ev);
+ }
+ }
+ void unbind(name *n) {
+ typename std::list<name *>::iterator iter;
+ typename synch_policy::scoped_lock lock(bind_lock_);
+ if ((iter = std::find(bindings_.begin(), bindings_.end(), n)) != bindings_.end()) {
+ //remove n from bindings_
+ //bindings_.remove(n);
+ bindings_.erase(iter);
+ //callback
+ binding_callback(n, unbind_ev);
+ }
+ }
+
+ //during name-destruction, disconn all
+ void unbind_all(void) {
+ typename synch_policy::scoped_lock lock(bind_lock_);
+ //unbind_all
+ for (typename std::list<name *>::iterator iter = bindings_.begin(); iter != bindings_.end();) {
+ //remove n from bindings_
+ typename std::list<name *>::iterator cur = iter;
+ name *n = *cur;
+ n->unbind(this); //remove reference to me at remote
+ iter++;
+ bindings_.erase(cur);
+ }
+ }
+
+ //unbind all external bindings; this must be a member_local
+ void unbind_all_external(void) {
+ typename synch_policy::scoped_lock lock(bind_lock_);
+ //unbind_all_external
+ for (typename std::list<name *>::iterator iter = bindings_.begin(); iter != bindings_.end();)
+ if ((*iter)->type_ == member_remote) {
+ //remove n from bindings_
+ typename std::list<name *>::iterator cur = iter;
+ name *n = *cur;
+ n->unbind(this); //remove reference to me at remote
+ iter++;
+ bindings_.erase(cur);
+ }
+ }
+
+ //predicates used for name space queries
+ ///names from internal and visible at interfaces to external channels
+ static bool exported_name(name *n) {
+ if (n->type_ == member_local && (n->scope_ == scope_remote || n->scope_ == scope_global))
+ return true;
+ return false;
+ }
+
+ ///names from internal and visible to internal peers
+ static bool internal_name(name *n) {
+ if (n->type_ == member_local && (n->scope_ == scope_local || n->scope_ == scope_global))
+ return true;
+ return false;
+ }
+
+ ///all/any names in name_space
+ static bool any_name(name *n) {
+ return true;
+ }
+
+ };
+
+ /*
+ template <typename id_type, typename synch_policy>
+ friend bool operator< (const name<id_type,synch_policy> &left,
+ const name<id_type,synch_policy> &right) {
+ return left.id_ < right.id_;
+ }
+ */
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/name_spaces/assoc_id_trait.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/assoc_id_trait.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,370 @@
+//
+// assoc_id_trait.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASSOC_ID_TRAIT_HPP
+#define ASSOC_ID_TRAIT_HPP
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <boost/regex.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/split_member.hpp>
+#include <boost/channel/config.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/tuple/tuple_io.hpp>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * regex_id type class
+ * using strings/regex as id and use regex-matching for id matching
+ */
+ struct BOOST_CHANNEL_DECL regex_id {
+ bool is_regex_;
+ std::string text_;
+ boost::shared_ptr<boost::regex> re_;
+ regex_id() :
+ is_regex_(false), text_(""), re_() {
+ }
+ regex_id(const char * id_text) :
+ is_regex_(false), text_(id_text), re_() {
+ }
+ regex_id(boost::regex *reg) :
+ is_regex_(true), text_(""), re_(reg) {
+ }
+ bool operator<(const regex_id &id) const {
+ if (!is_regex_ && id.is_regex_)
+ return true;
+ else if (!is_regex_ && !id.is_regex_ && text_ < id.text_)
+ return true;
+ else if (is_regex_ && id.is_regex_ && (*re_) < (*id.re_))
+ return true;
+ return false;
+ }
+ bool operator==(const regex_id &id) const {
+ if (!is_regex_ && !id.is_regex_ && text_ == id.text_)
+ return true;
+ else if (is_regex_ && id.is_regex_ && (*re_) == (*id.re_))
+ return true;
+ return false;
+ }
+ bool operator!=(const regex_id &id) const {
+ return !operator==(id);
+ }
+ template<class Archive>
+ void save(Archive & ar, const unsigned int version) const {
+ ar & is_regex_;
+ if (!is_regex_) {
+ ar & text_;
+ //std::cout << "save id: " << text_ << std::endl;
+ } else {
+ typename boost::regex::flag_type f = re_->flags();
+ std::string str = re_->str();
+ ar & f;
+ ar & str;
+ //std::cout << "save id: " << *re_ << std::endl;
+ }
+ }
+ template<class Archive>
+ void load(Archive & ar, const unsigned int version) {
+ ar & is_regex_;
+ if (!is_regex_) {
+ ar & text_;
+ //std::cout << "load id: " << text_ << std::endl;
+ } else {
+ typename boost::regex::flag_type f;
+ std::string str;
+ ar & f;
+ ar & str;
+ re_.reset(new boost::regex(str, f));
+ //std::cout << "load id: " <<* re_ << std::endl;
+ }
+ }
+ BOOST_SERIALIZATION_SPLIT_MEMBER()
+ };
+
+ /**
+ * regex_id_trait class
+ */
+ template<class id_type> class id_trait;
+
+ template <>
+ class BOOST_CHANNEL_DECL id_trait<regex_id> {
+ public:
+ ///define system msgs
+ static regex_id channel_conn_msg;
+ static regex_id channel_disconn_msg;
+ static regex_id init_subscription_info_msg;
+ static regex_id connection_ready_msg;
+ static regex_id subscription_info_msg;
+ static regex_id unsubscription_info_msg;
+ static regex_id publication_info_msg;
+ static regex_id unpublication_info_msg;
+
+ typedef regex_id id_type;
+
+ static bool match(regex_id id1, regex_id id2)
+ {
+ //std::cout << "try to match : " << id_to_string(id1) << "; " << id_to_string(id2) << std::endl;
+ if (!id1.is_regex_ && !id2.is_regex_)
+ return id1.text_ == id2.text_;
+ else if (id1.is_regex_ && !id2.is_regex_)
+ return boost::regex_match(id2.text_, *(id1.re_));
+ else if (id2.is_regex_ && !id1.is_regex_)
+ return boost::regex_match(id1.text_, *(id2.re_));
+ else if (id1.is_regex_ && id2.is_regex_)
+ return (*id1.re_) == (*id2.re_);
+ return false;
+ }
+
+ //are we using assoc/fuzzy matching here
+ static bool wildcard_name(const regex_id &id) {
+ return id.is_regex_;
+ }
+
+ static std::string id_to_string(const regex_id &id) {
+ std::ostringstream os;
+ if (id.is_regex_)
+ os << "regex_id " << "[regex_pattern]: " << *(id.re_);
+ else
+ os << "regex_id " << "[plain_text]: " << id.text_;
+ return os.str();
+ }
+ };
+
+ /**
+ * tuple_id : use linda style tuple as id and associative lookup for matching
+ * a tuple_id consist of multiple fields
+ * we should just define field_trait for primitive types here
+ * user should define field_traits for user-defined types
+ */
+ /**
+ * basic field_trait
+ */
+ template<typename field_type> class field_trait;
+
+ template <>
+ class BOOST_CHANNEL_DECL field_trait<int> {
+ public:
+ typedef int field_type;
+ static int wildcard;
+ static bool wildcard_field(int f) {
+ if (f == wildcard)
+ return true;
+ return false;
+ }
+ static bool match(int f1, int f2) {
+ if (f1 == wildcard || f2 == wildcard)
+ return true;
+ return f1 == f2;
+ }
+ };
+
+ template <>
+ class BOOST_CHANNEL_DECL field_trait<float> {
+ public:
+ typedef float field_type;
+ static float wildcard;
+ static bool wildcard_field(float f) {
+ if (f == wildcard)
+ return true;
+ return false;
+ }
+ static bool match(float f1, float f2) {
+ if (f1 == wildcard || f2 == wildcard)
+ return true;
+ return f1 == f2;
+ }
+ };
+
+ template <>
+ class BOOST_CHANNEL_DECL field_trait<std::string> {
+ public:
+ typedef std::string field_type;
+ static const char * wildcard;
+ static bool wildcard_field(std::string f) {
+ if (f == wildcard)
+ return true;
+ return false;
+ }
+ static bool match(std::string f1, std::string f2) {
+ if (f1 == wildcard || f2 == wildcard)
+ return true;
+ return f1 == f2;
+ }
+ };
+
+ /* --- we should add field_trait for other primitive types here --- */
+
+ /**
+ * use boost::tuple as tuple_id
+ */
+ template<typename Tuple_Type>
+ class tuple_id {
+ public:
+ typedef Tuple_Type tuple_type;
+ enum sys_ids {
+ app_type = 0,
+ channel_conn_type,
+ channel_disconn_type,
+ init_subscription_info_type,
+ connection_ready_type,
+ subscription_info_type,
+ unsubscription_info_type,
+ publication_info_type,
+ unpublication_info_type
+ };
+ int type_;
+ tuple_type tuple_;
+ tuple_id() :
+ type_(app_type), tuple_() {
+ }
+ tuple_id(int type) :
+ type_(type), tuple_() {
+ }
+ tuple_id(tuple_type tt) :
+ type_(app_type), tuple_(tt) {
+ }
+ tuple_id(const tuple_id &id) :
+ type_(id.type_), tuple_(id.tuple_) {
+ }
+ bool operator<(const tuple_id &id) const {
+ if (type_ < id.type_)
+ return true;
+ else if (type_ == id.type_ && type_ == app_type && tuple_ < id.tuple_)
+ return true;
+ return false;
+ }
+ bool operator==(const tuple_id &id) const {
+ if (type_ == id.type_) {
+ if (type_ != app_type)
+ return true;
+ else
+ return tuple_ == id.tuple_;
+ }
+ return false;
+ }
+ bool operator!=(const tuple_id &id) const {
+ return !operator==(id);
+ }
+ template<class Archive>
+ inline void serialize_priv(Archive & ar, const boost::tuples::null_type&,
+ const unsigned int version) {
+ }
+ template<class Archive, typename H, typename T>
+ inline void serialize_priv(Archive & ar, boost::tuples::cons<H, T> &t,
+ const unsigned int version) {
+ ar & t.get_head();
+ serialize_priv(ar, t.get_tail(), version);
+ }
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar & type_;
+ if (type_ == app_type) {
+ ar & tuple_.get_head();
+ serialize_priv(ar, tuple_.get_tail(), version);
+ }
+ //std::cout << "serialize tuple_id : type[" << type_ << "] tuple[" << tuple_ << "]" << std::endl;
+ }
+ };
+
+ /**
+ * tuple id trait
+ */
+ template<typename Tuple_Type>
+ class BOOST_CHANNEL_DECL id_trait<tuple_id<Tuple_Type> > {
+ public:
+
+ typedef Tuple_Type tuple_type;
+ typedef tuple_id<tuple_type> id_type;
+
+ ///define system msgs
+ static id_type channel_conn_msg;
+ static id_type channel_disconn_msg;
+ static id_type init_subscription_info_msg;
+ static id_type connection_ready_msg;
+ static id_type subscription_info_msg;
+ static id_type unsubscription_info_msg;
+ static id_type publication_info_msg;
+ static id_type unpublication_info_msg;
+
+ static bool match_tuple(const boost::tuples::null_type&, const boost::tuples::null_type&)
+ {
+ //std::cout << "match_tuple(const boost::tuples::null_type matched tuple \n";
+ return true;
+ }
+
+ template <typename H, typename T>
+ static bool match_tuple(const boost::tuples::cons<H,T> &t1, const boost::tuples::cons<H,T> &t2)
+ {
+ if(!field_trait<H>::match(t1.get_head(), t2.get_head()))
+ return false;
+ return match_tuple(t1.get_tail(), t2.get_tail());
+ }
+
+ static bool match(id_type id1, id_type id2)
+ {
+ if (id1.type_ != id2.type_)
+ return false;
+ if (id1.type_ == id_type::app_type) {
+ if (wildcard_tuple(id1.tuple_) && wildcard_tuple(id2.tuple_) && (id1.tuple_ != id2.tuple_))
+ return false;
+ if (id1.tuple_ == id2.tuple_)
+ return true;
+ return match_tuple(id1.tuple_, id2.tuple_);
+ }
+ return true;
+ }
+
+ //are we using assoc/fuzzy matching here
+ static bool wildcard_tuple(const boost::tuples::null_type&)
+ {
+ return false;
+ }
+
+ template <typename H, typename T>
+ static bool wildcard_tuple(const boost::tuples::cons<H,T> &t1)
+ {
+ if(field_trait<H>::wildcard_field(t1.get_head()))
+ return true;
+ return wildcard_tuple(t1.get_tail());
+ }
+
+ static bool wildcard_name(const id_type &id) {
+ if (id.type_ != id_type::app_type)
+ return false;
+ return wildcard_tuple(id.tuple_);
+ }
+
+ static std::string id_to_string(const id_type &id) {
+ std::ostringstream os;
+ os << "tuple_id : type[" << id.type_ << "] tuple[" << id.tuple_ << "]";
+ return os.str();
+ }
+ };
+
+ }
+}
+
+#define DEFINE_ASSOC_SYS_IDS( tuple_type ) \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::channel_conn_msg(boost::channel::tuple_id<tuple_type>::channel_conn_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::channel_disconn_msg(boost::channel::tuple_id<tuple_type>::channel_disconn_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::init_subscription_info_msg(boost::channel::tuple_id<tuple_type>::init_subscription_info_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::connection_ready_msg(boost::channel::tuple_id<tuple_type>::connection_ready_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::subscription_info_msg(boost::channel::tuple_id<tuple_type>::subscription_info_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::unsubscription_info_msg(boost::channel::tuple_id<tuple_type>::unsubscription_info_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::publication_info_msg(boost::channel::tuple_id<tuple_type>::publication_info_type); \
+ template <> boost::channel::tuple_id<tuple_type> boost::channel::id_trait<boost::channel::tuple_id<tuple_type> >::unpublication_info_msg(boost::channel::tuple_id<tuple_type>::unpublication_info_type);
+
+#endif
+

Added: sandbox/channel/boost/channel/name_spaces/hierarchical_id_trait.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/hierarchical_id_trait.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,197 @@
+//
+// hierarchical_id_trait.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HIERARCHICAL_ID_TRAIT_HPP
+#define HIERARCHICAL_ID_TRAIT_HPP
+
+#include <vector>
+#include <string>
+#include <sstream>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/channel/config.hpp>
+
+namespace boost {
+ namespace channel {
+ /**
+ * hierarchical id types:
+ * each id/name in hierarchical name_space is a "path name" of sub-ids/tokens
+ * denoting the "branches" of tree you traverse thru before reaching
+ * the tree-node which represents the id; these sub-ids called tokens
+ * 1. if token_type is "char", HierarchicalId will be strings
+ * 2. if token_type is "string", HierarichalId is unix style pathnames
+ *
+ * vector<token_type> is used as the base class for all hierarchical id
+ * to store the elements of hierarchical ids
+ * real applications' hierarchial ids should inherit vector class and
+ * add :
+ * 1. convenience constructors
+ * 2. marshal/demarshal methods
+ * 3. other convenience methods
+ */
+
+ template<class id_type> class id_trait;
+
+ /**
+ * str_path_id - a hierarchical id type using unix path names
+ * element_type = string
+ * in channel, only absolute pathnames are used: ie. must start with "/"
+ * add convenience constructors and methods for decoding the names
+ */
+ template<char sep = '/'>
+ struct BOOST_CHANNEL_DECL str_path_id: public std::vector<std::string> {
+ enum {
+ separator = sep
+ };
+ bool valid_;
+ str_path_id() {
+ valid_ = true;
+ }
+ str_path_id(const char * pathname) {
+ std::string name(pathname);
+ valid_ = true;
+ size_type pos1 = std::string::npos, pos2 = std::string::npos;
+ pos1 = name.find(separator);
+ if (pos1 == std::string::npos) {
+ valid_ = false;
+ } else {
+ while (true) {
+ pos2 = name.find(separator, pos1 + 1);
+ if (pos2 != std::string::npos)
+ push_back(name.substr(pos1 + 1, pos2 - pos1 - 1));
+ else {
+ std::string s = name.substr(pos1 + 1);
+ pos2 = s.find_last_not_of(' ');
+ if (pos2 != std::string::npos)
+ push_back(s.substr(0, pos2 + 1));
+ break;
+ }
+ pos1 = pos2;
+ }
+ }
+ }
+ std::string get_str_name(void) {
+ std::string name;
+ for (size_t i = 0; i < size(); i++) {
+ name.push_back(sep);
+ name.append(operator[](i));
+ }
+ return name;
+ }
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar
+ & boost::serialization::base_object<std::vector<std::string> >(
+ *this);
+ }
+ };
+
+ ///trait class for string pathname id type
+ template<char sep>
+ class BOOST_CHANNEL_DECL id_trait<str_path_id<sep> > {
+ public:
+
+ typedef str_path_id<sep> id_type;
+ enum {separator = id_type::separator};
+
+ typedef typename id_type::value_type token_type;
+
+ ///define system msgs
+ static id_type channel_conn_msg;
+ static id_type channel_disconn_msg;
+ static id_type init_subscription_info_msg;
+ static id_type connection_ready_msg;
+ static id_type subscription_info_msg;
+ static id_type unsubscription_info_msg;
+ static id_type publication_info_msg;
+ static id_type unpublication_info_msg;
+
+ static token_type root_token; //just a name for root trie node, not in name_space
+ static token_type wildcard_token;
+
+ ///need the comparisons for msg matching and map
+ static bool eq(const id_type &id1, const id_type &id2)
+ { return id1 == id2;}
+ static bool lt(const id_type &id1, const id_type &id2)
+ { return id1 < id2;}
+
+ static std::string id_to_string(const id_type &id) {
+ std::ostringstream os;
+ for(size_t i=0; i<id.size(); i++)
+ os << (char)separator << id[i];
+ return os.str();
+ }
+
+ static bool wildcard_name(const id_type &id) {
+ return (*id.rbegin()) == wildcard_token;
+ }
+
+ static bool valid(const id_type &id) {
+ if (!id.valid_) return false;
+ size_t sz = id.size();
+ for (size_t i=0; i<sz; i++)
+ if (id[i] == id_trait::wildcard_token && i != (sz-1))
+ return false;
+ return true;
+ }
+
+ enum id_compare_result {
+ id_match,
+ id_1_contains_2,
+ id_2_contains_1,
+ id_mismatch
+ };
+
+ static id_compare_result compare(id_type &id1, id_type &id2)
+ {
+ int sz1 = id1.size();
+ int sz2 = id2.size();
+ int sz = (sz1 < sz2)?sz1:sz2;
+ for(int i=0; i<sz; i++) {
+ if (id1[i] != id2[i]) {
+ if (id1[i] == id_trait::wildcard_token)
+ return id_1_contains_2;
+ else if (id2[i] == id_trait::wildcard_token)
+ return id_2_contains_1;
+ else return id_mismatch;
+ }
+ }
+ if (sz1 == sz2)
+ return id_match;
+ else if(sz1 < sz2 && (sz1+1) == sz2 && id2[sz1] == id_trait::wildcard_token)
+ return id_2_contains_1;
+ else if(sz2 < sz1 && (sz2+1) == sz1 && id1[sz2] == id_trait::wildcard_token)
+ return id_1_contains_2;
+ return id_mismatch;
+ }
+
+ //compiler doesnt allow references here
+ //static bool match(const id_type &id1, const id_type &id2)
+ static bool match(id_type id1, id_type id2)
+ {
+ return compare(id1,id2) != id_mismatch;
+ }
+
+ //compiler doesnt allow references here
+ //static bool id1contains2(const id_type &id1, const id_type &id2)
+ static bool id1contains2(id_type id1, id_type id2)
+ {
+ id_compare_result res = compare(id1,id2);
+ return res == id_match || res == id_1_contains_2;
+ }
+
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/name_spaces/hierarchical_name_space.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/hierarchical_name_space.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,824 @@
+//
+// hierarchical_name_space.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HIERARCHICAL_NAME_SPACE_HPP
+#define HIERARCHICAL_NAME_SPACE_HPP
+
+#include <map>
+#include <list>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/name_spaces/hierarchical_id_trait.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/name_spaces/name_space_change_notify.hpp>
+
+namespace boost {
+ namespace channel {
+ /**
+ * hierarchical_name_space:
+ * using trie as routing data structure
+ * using pathname matching
+ */
+ template<class idtype, class executor_type, class synchpolicy>
+ class hierarchical_name_space {
+ public:
+ typedef idtype id_type;
+ typedef id_trait<id_type> id_trait;
+ typedef synchpolicy synch_policy;
+ typedef executor_type executor;
+ typedef typename id_trait::token_type token_type;
+ typedef typename synch_policy::platform platform;
+ //we dont care about In/Out operations here, just names and bindings
+ typedef name<id_type,executor_type,synch_policy> name;
+
+ private:
+ typedef hierarchical_name_space<idtype,executor_type,synchpolicy> ns_type;
+
+ struct trie_node {
+ token_type token; //name of this node
+ /// -- trie data structure --
+ trie_node *parent;
+ std::map<token_type, trie_node *> children;
+ typename synch_policy::mutex trie_lock_; //to protect trie structure
+ /// -- bindings --
+ // normal name binding
+ std::list<name *> outs_;
+ std::list<name *> ins_;
+ // wildcard name binding
+ std::list<name *> outs_w_;
+ std::list<name *> ins_w_;
+ typename synch_policy::mutex bind_lock_; //to protect binding structure
+ trie_node(token_type e, trie_node *p) : token(e), parent(p) {
+ }
+ ~trie_node() {
+ typename synch_policy::scoped_lock lock(trie_lock_);
+ for(typename std::map<token_type, trie_node *>::iterator iter = children.begin();
+ iter != children.end(); iter++) {
+ if (iter->second != NULL)
+ delete iter->second;
+ }
+ }
+ };
+
+ //name_space
+ boost::shared_ptr<trie_node> ns_root_; //root of name_space tree
+ //no need for a global name_space lock, since each node has its own lock
+ //may be too much protection, in future we can swtch back to a global lock
+
+ executor_type *exec_; //default executor_type for all async_opers/callbacks in channel
+ //for sending out local name_space change events
+ detail::name_space_change_notify<ns_type> ns_notifier_;
+
+ public:
+
+ hierarchical_name_space(executor_type *e) :
+ ns_root_(new trie_node(id_trait::root_token, NULL)),
+ exec_(e),
+ ns_notifier_(*this) {
+ }
+
+ ~hierarchical_name_space() {
+ //shared_ptr make sure delete notifier (so its named_in/outs are deleted)
+ //before deleting name space
+ }
+
+ executor_type * get_exec(void) {
+ return exec_;
+ }
+
+ /**
+ * Local operations on name_space:
+ * bind/unbind named_in/out
+ * for each bind/unbind, 3 kinds of changes made:
+ * 1. binding to the trie data structure
+ * 2. binding between named_out and named_in
+ * 3. exported ids/names exposed to external channels
+ *
+ * specialty with hierarchical name_space because of wildcard in names/ids:
+ * 1> bindings (out<->in):
+ * . bind with all "opposite" names/wildcards in trie at the node with this id
+ * . bind with all upper level "opposite" wildcards, no matter this is wildcard or not
+ * . if this is wildcard, bind with all lower level "opposite" names
+ * 2> external ids (exposed): wildcard names do hide/unhide :
+ * . a wildcard name will hide/unhide all "same-side" names in trie at lower levels
+ * . any names can be hiden by a "same-side" wildcard at upper level
+ *
+ * normal algorithms:
+ * 1. traverse the trie to the destination node:
+ * . if some path or node do not exist, create them
+ * . check if it is hidden by a upper level wildcard at the same side
+ * . check if it can bind to upper level wildcards at opposite, add bindings
+ * 2. at the destination node:
+ * . check if it can bind to opposite names and wildcards at this node, add bindings
+ * . if it is not a wildcard, and not hidden, simply check if it should be "notify"ed
+ * . if this is a wildcard:
+ * . check if it can bind to all lower level "opposite" names, add bindings
+ * . check if it is not hidden, it hide/unhide all "same-side" names at lower level;
+ * call notify_external to hide hidden names.
+ * . if is not hidden call notify on it; if hidden, call notify_internal
+ */
+ ///
+ void bind_named_out(name *n)
+ {
+ bool wildcard = id_trait::wildcard_name(n->id_);
+ bool hidden = false;
+
+ /**
+ * traverse from root to node designated by n->id_
+ */
+ trie_node *node = ns_root_.get();
+ for (size_t i=0; i<n->id_.size(); i++) {
+ if (n->id_[i] == id_trait::wildcard_token && i == (n->id_.size()-1))
+ break;
+ ///check if it is hidden by a upper level wildcard at the same side
+ if (!hidden && name::exported_name(n)) {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->outs_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end() && !hidden; iter++) {
+ name *m = (*iter);
+ if (name::exported_name(m))
+ hidden = true;
+ }
+ }
+ }
+ ///check if it can bind to upper level wildcards at opposite, add bindings
+ {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->ins_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(n,m)) {
+ n->bind(m);
+ m->bind(n);
+ platform::log("bind_named_out/bind : "+id_trait::id_to_string(n->id_)+"->"+id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ }
+ ///if some path or node do not exist, create them
+ {
+ typename synch_policy::scoped_lock lock(node->trie_lock_);
+ typename std::map<token_type, trie_node *>::iterator iter = node->children.find(n->id_[i]);
+ if (iter == node->children.end()) {
+ trie_node *cnd = new trie_node (n->id_[i], node);
+ node->children[n->id_[i]] = cnd;
+ node = cnd;
+ }
+ else
+ node = iter->second;
+ }
+ }
+
+ /// now we have reached the node for this n->id_ (without trailing wildcard)
+ //
+ ///check if it can bind to opposite names , add bindings
+ ///binding to opposite wildcard at this node already handled during traverse
+ {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->ins_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_.begin();
+ iter != node->ins_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(n,m)) {
+ n->bind(m);
+ m->bind(n);
+ platform::log("bind_named_out/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+
+ if (!node->ins_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(n,m)) {
+ n->bind(m);
+ m->bind(n);
+ platform::log("bind_named_out/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ }
+
+ if (!wildcard) {
+ /// for normal names
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->outs_.push_front(n);
+ lock.unlock();
+
+ ///notify
+ if(name::exported_name(n) && hidden)
+ ///if hidden, just notify internal peers
+ ns_notifier_.notify_internal(name::bind_out_ev, n);
+ else if(n->type_ == name::member_local)
+ ///notify all
+ ns_notifier_.notify(name::bind_out_ev, n);
+ }
+ else {
+ ///for wildcards
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->outs_w_.push_front(n);
+ lock.unlock();
+
+ /// bind to lower level opposite names
+ {
+ typename synch_policy::scoped_lock lock(node->trie_lock_);
+ for(typename std::map<token_type, trie_node *>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++)
+ bind_out_to_lower_ins(n, iter->second);
+ }
+
+ /// notify, and possibly hide lower level names
+ if (name::exported_name(n)) {
+ if(hidden)
+ ns_notifier_.notify_internal(name::bind_out_ev, n);
+ else {
+ ///at external interface, hide all "same-side" names at lower level,
+ ///starting from this node
+ update_children_out_exports (node, name::unbind_out_ev, false);
+ ns_notifier_.notify(name::bind_out_ev, n);
+ }
+ }
+ else if(n->type_ == name::member_local) {
+ ns_notifier_.notify(name::bind_out_ev, n);
+ }
+ }
+ }
+
+ ///
+ void unbind_named_out(name *n)
+ {
+ bool wildcard = id_trait::wildcard_name(n->id_);
+ bool hidden = false;
+
+ /**
+ * traverse from root to node designated by n->id_
+ */
+ trie_node *node = ns_root_.get();
+ for (size_t i=0; i<n->id_.size(); i++) {
+ if (n->id_[i] == id_trait::wildcard_token && i == (n->id_.size()-1))
+ break;
+ ///check if it is hidden by a upper level wildcard at the same side
+ if (!hidden && name::exported_name(n)) {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->outs_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end() && !hidden; iter++) {
+ name *m = (*iter);
+ if (name::exported_name(m) && n != m)
+ hidden = true;
+ }
+ }
+ }
+ {
+ typename synch_policy::scoped_lock lock(node->trie_lock_);
+ typename std::map<token_type, trie_node *>::iterator iter = node->children.find(n->id_[i]);
+ if (iter == node->children.end()) {
+ platform::log("unbind_named_in: branch disappeared");
+ return;
+ }
+ node = iter->second;
+ }
+ }
+
+ /// now we have reached the node for this n->id_ (without trailing wildcard)
+
+ ///unbind all Out->In
+ //n->unbind_all();
+
+ ///del binding from name_space
+ if (!wildcard) {
+ /// for normal names
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->outs_.remove(n);
+ lock.unlock();
+
+ ///notify
+ if(name::exported_name(n) && hidden)
+ ///if hidden, just notify internal peers
+ ns_notifier_.notify_internal(name::unbind_out_ev, n);
+ else if(n->type_ == name::member_local)
+ ///notify all
+ ns_notifier_.notify(name::unbind_out_ev, n);
+ }
+ else {
+ ///for wildcards
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->outs_w_.remove(n);
+ lock.unlock();
+
+ /// notify, and possibly hide lower level names
+ if (name::exported_name(n)) {
+ if(hidden)
+ ns_notifier_.notify_internal(name::unbind_out_ev, n);
+ else {
+ ///at external interface, unhide all "same-side" names at lower level,
+ ///starting from this node
+ update_children_in_exports (node, name::bind_out_ev, false);
+ ns_notifier_.notify(name::unbind_out_ev, n);
+ }
+ }
+ else if(n->type_ == name::member_local) {
+ ns_notifier_.notify(name::unbind_out_ev, n);
+ }
+ }
+ }
+
+ ///
+ void bind_named_in(name *n)
+ {
+ bool wildcard = id_trait::wildcard_name(n->id_);
+ bool hidden = false;
+
+ /**
+ * traverse from root to node designated by n->id_
+ */
+ trie_node *node = ns_root_.get();
+ for (size_t i=0; i<n->id_.size(); i++) {
+ if (n->id_[i] == id_trait::wildcard_token && i == (n->id_.size()-1))
+ break;
+ ///check if it is hidden by a upper level wildcard at the same side
+ if (!hidden && name::exported_name(n)) {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->ins_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end() && !hidden; iter++) {
+ name *m = (*iter);
+ if (name::exported_name(m))
+ hidden = true;
+ }
+ }
+ }
+ ///check if it can bind to upper level wildcards at opposite, add bindings
+ {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->outs_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_named_in/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ }
+ ///if some path or node do not exist, create them
+ {
+ typename synch_policy::scoped_lock lock(node->trie_lock_);
+ typename std::map<token_type, trie_node *>::iterator iter = node->children.find(n->id_[i]);
+ if (iter == node->children.end()) {
+ trie_node *cnd = new trie_node (n->id_[i], node);
+ node->children[n->id_[i]] = cnd;
+ node = cnd;
+ }
+ else
+ node = iter->second;
+ }
+ }
+
+ /// now we have reached the node for this n->id_ (without trailing wildcard)
+ //
+ ///check if it can bind to opposite names , add bindings
+ ///binding to opposite wildcards at this node already done during traverse
+ {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->outs_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_.begin();
+ iter != node->outs_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_named_in/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ if (!node->outs_w_.empty()) { //if this is wildcard, this step alrady done during traverse
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_named_in/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ }
+
+ if (!wildcard) {
+ /// for normal names
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->ins_.push_front(n);
+ lock.unlock();
+
+ ///notify
+ if(name::exported_name(n) && hidden)
+ ///if hidden, just notify internal peers
+ ns_notifier_.notify_internal(name::bind_in_ev, n);
+ else if(n->type_ == name::member_local)
+ ///notify all
+ ns_notifier_.notify(name::bind_in_ev, n);
+ }
+ else {
+ ///for wildcards
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->ins_w_.push_front(n);
+ lock.unlock();
+
+ /// bind to lower level opposite names
+ {
+ typename synch_policy::scoped_lock lock(node->trie_lock_);
+ for(typename std::map<token_type, trie_node *>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++)
+ bind_in_to_lower_outs(n, iter->second);
+ }
+
+ /// notify, and possibly hide lower level names
+ if (name::exported_name(n)) {
+ if(hidden)
+ ns_notifier_.notify_internal(name::bind_in_ev, n);
+ else {
+ ///at external interface, hide all "same-side" names at lower level,
+ ///starting from this node
+ update_children_in_exports (node, name::unbind_in_ev, false);
+ ns_notifier_.notify(name::bind_in_ev, n);
+ }
+ }
+ else if(n->type_ == name::member_local) {
+ ns_notifier_.notify(name::bind_in_ev, n);
+ }
+ }
+ }
+
+ ///
+ void unbind_named_in(name *n)
+ {
+ bool wildcard = id_trait::wildcard_name(n->id_);
+ bool hidden = false;
+
+ /**
+ * traverse from root to node designated by n->id_
+ */
+ trie_node *node = ns_root_.get();
+ for (size_t i=0; i<n->id_.size(); i++) {
+ if (n->id_[i] == id_trait::wildcard_token && i == (n->id_.size()-1))
+ break;
+ ///check if it is hidden by a upper level wildcard at the same side
+ if (!hidden && name::exported_name(n)) {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->ins_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end() && !hidden; iter++) {
+ name *m = (*iter);
+ if (name::exported_name(m) && n != m)
+ hidden = true;
+ }
+ }
+ }
+ {
+ typename synch_policy::scoped_lock lock(node->trie_lock_);
+ typename std::map<token_type, trie_node *>::iterator iter = node->children.find(n->id_[i]);
+ if (iter == node->children.end()) {
+ platform::log("unbind_named_in: branch disappeared");
+ return;
+ }
+ node = iter->second;
+ }
+ }
+
+ /// now we have reached the node for this n->id_ (without trailing wildcard)
+
+ ///unbind all Out->In
+ //n->unbind_all();
+
+ ///del binding from name_space
+ if (!wildcard) {
+ /// for normal names
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->ins_.remove(n);
+ lock.unlock();
+
+ ///notify
+ if(name::exported_name(n) && hidden)
+ ///if hidden, just notify internal peers
+ ns_notifier_.notify_internal(name::unbind_in_ev, n);
+ else if(n->type_ == name::member_local)
+ ///notify all
+ ns_notifier_.notify(name::unbind_in_ev, n);
+ }
+ else {
+ ///for wildcards
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ ///store in name_space
+ node->ins_w_.remove(n);
+ lock.unlock();
+
+ /// notify, and possibly hide lower level names
+ if (name::exported_name(n)) {
+ if(hidden)
+ ns_notifier_.notify_internal(name::unbind_in_ev, n);
+ else {
+ ///at external interface, unhide all "same-side" names at lower level,
+ ///starting from this node
+ id_type id = n->id_;
+ update_children_in_exports (node, name::bind_in_ev, false);
+ ns_notifier_.notify(name::unbind_in_ev, n);
+ }
+ }
+ else if(n->type_ == name::member_local) {
+ ns_notifier_.notify(name::unbind_in_ev, n);
+ }
+ }
+ }
+
+ void bind_in_to_lower_outs(name *n, trie_node *node) {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->outs_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_.begin();
+ iter != node->outs_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_in_to_lower_outs/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ if (!node->outs_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end(); iter++) {
+ name *m = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_in_to_lower_outs/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ lock.unlock();
+ //recursively update children
+ typename synch_policy::scoped_lock lock2(node->trie_lock_);
+ for(typename std::map<token_type, trie_node*>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++) {
+ bind_in_to_lower_outs (n, iter->second);
+ }
+ }
+
+ void bind_out_to_lower_ins(name *m, trie_node *node) {
+ typename synch_policy::scoped_lock lock(node->bind_lock_);
+ if (!node->ins_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_.begin();
+ iter != node->ins_.end(); iter++) {
+ name *n = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_out_to_lower_ins/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ if (!node->ins_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end(); iter++) {
+ name *n = (*iter);
+ ///setup bindings
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ platform::log("bind_out_to_lower_ins/bind : "+id_trait::id_to_string(n->id_)+"->"+
+ id_trait::id_to_string(m->id_));
+ }
+ }
+ }
+ lock.unlock();
+ //recursively update children
+ typename synch_policy::scoped_lock lock2(node->trie_lock_);
+ for(typename std::map<token_type, trie_node*>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++) {
+ bind_out_to_lower_ins (m, iter->second);
+ }
+ }
+
+ void update_children_out_exports (trie_node *node,
+ typename name::binding_event oper, bool update_wildcard) {
+ bool send2remote = false;
+
+ typename synch_policy::scoped_lock lock1(node->bind_lock_);
+ ///if encounter wildcard, stop going deeper
+ if (update_wildcard && !node->outs_w_.empty()) {
+ name *m;
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end(); iter++) {
+ m = *iter;
+ if (name::exported_name(m)) {
+ send2remote = true;
+ if (oper == name::unbind_out_ev)
+ m->unbind_all_external();
+ }
+ }
+ if (send2remote) {
+ ns_notifier_.notify_external(oper, m);
+ return;
+ }
+ }
+ if (!node->outs_.empty()) {
+ name *m;
+ for(typename std::list<name *>::iterator iter = node->outs_.begin();
+ iter != node->outs_.end(); iter++) {
+ m = *iter;
+ if (name::exported_name(m)) {
+ send2remote = true;
+ if (oper == name::unbind_out_ev)
+ m->unbind_all_external();
+ }
+ }
+ if (send2remote) {
+ ns_notifier_.notify_external(oper, m);
+ }
+ }
+ lock1.unlock();
+
+ //recursively update children
+ typename synch_policy::scoped_lock lock2(node->trie_lock_);
+ for(typename std::map<token_type, trie_node*>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++) {
+ update_children_out_exports (iter->second, oper, true);
+ }
+ }
+
+ void update_children_in_exports (trie_node *node,
+ typename name::binding_event oper, bool update_wildcard) {
+ bool send2remote = false;
+
+ typename synch_policy::scoped_lock lock1(node->bind_lock_);
+ ///if encounter wildcard, stop going deeper
+ if (update_wildcard && !node->ins_w_.empty()) {
+ name *m;
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end(); iter++) {
+ m = *iter;
+ if (name::exported_name(m)) {
+ send2remote = true;
+ if (oper == name::unbind_in_ev)
+ m->unbind_all_external();
+ }
+ }
+ if (send2remote) {
+ ns_notifier_.notify_external(oper, m);
+ return;
+ }
+ }
+ if (!node->ins_.empty()) {
+ name *m;
+ for(typename std::list<name *>::iterator iter = node->ins_.begin();
+ iter != node->ins_.end(); iter++) {
+ m = *iter;
+ if (name::exported_name(m)) {
+ send2remote = true;
+ if (oper == name::unbind_in_ev)
+ m->unbind_all_external();
+ }
+ }
+ if (send2remote) {
+ ns_notifier_.notify_external(oper, m);
+ }
+ }
+ lock1.unlock();
+
+ //recursively update children
+ typename synch_policy::scoped_lock lock2(node->trie_lock_);
+ for(typename std::map<token_type, trie_node*>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++) {
+ update_children_in_exports (iter->second, oper, true);
+ }
+ }
+
+ /**
+ * 3. name_space queries
+ */
+
+ template <typename Predicate>
+ void bound_ids_for_in(Predicate p, std::vector<id_type> &ids)
+ {
+ bound_ids_for_in_recursive(p, ids, ns_root_.get());
+ }
+
+ template <typename Predicate>
+ void bound_ids_for_in_recursive(Predicate p, std::vector<id_type> &ids, trie_node *node)
+ {
+ name *m;
+ typename synch_policy::scoped_lock lock1(node->bind_lock_);
+ ///if encounter wildcard, stop going deeper
+ if (!node->ins_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_w_.begin();
+ iter != node->ins_w_.end(); iter++) {
+ m = *iter;
+ if (p(m)) {
+ ids.push_back(m->id_);
+ return;
+ }
+ }
+ }
+ if (!node->ins_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->ins_.begin();
+ iter != node->ins_.end(); iter++) {
+ m = *iter;
+ if (p(m)) {
+ ids.push_back(m->id_);
+ break;
+ }
+ }
+ }
+ lock1.unlock();
+
+ //recursively update children
+ typename synch_policy::scoped_lock lock2(node->trie_lock_);
+ for(typename std::map<token_type, trie_node*>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++) {
+ bound_ids_for_in_recursive(p, ids, iter->second);
+ }
+ }
+
+ template <typename Predicate>
+ void bound_ids_for_out(Predicate p, std::vector<id_type> &ids)
+ {
+ bound_ids_for_out_recursive(p, ids, ns_root_.get());
+ }
+
+ template <typename Predicate>
+ void bound_ids_for_out_recursive(Predicate p, std::vector<id_type> &ids, trie_node *node)
+ {
+ name *m;
+ typename synch_policy::scoped_lock lock1(node->bind_lock_);
+ ///if encounter wildcard, stop going deeper
+ if (!node->outs_w_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_w_.begin();
+ iter != node->outs_w_.end(); iter++) {
+ m = *iter;
+ if (p(m)) {
+ ids.push_back(m->id_);
+ return;
+ }
+ }
+ }
+ if (!node->outs_.empty()) {
+ for(typename std::list<name *>::iterator iter = node->outs_.begin();
+ iter != node->outs_.end(); iter++) {
+ m = *iter;
+ if (p(m)) {
+ ids.push_back(m->id_);
+ break;
+ }
+ }
+ }
+ lock1.unlock();
+
+ //recursively update children
+ typename synch_policy::scoped_lock lock2(node->trie_lock_);
+ for(typename std::map<token_type, trie_node*>::iterator iter = node->children.begin();
+ iter != node->children.end(); iter++) {
+ bound_ids_for_out_recursive(p, ids, iter->second);
+ }
+ }
+ };
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/name_spaces/linear_id_trait.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/linear_id_trait.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,258 @@
+//
+// linear_id_trait.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef LINEAR_ID_TRAIT_HPP
+#define LINEAR_ID_TRAIT_HPP
+
+#include <sstream>
+#include <string>
+#include <boost/channel/config.hpp>
+
+/**
+ * Here are the definitions related to linear name_space ids:
+ * 1> trait class for primitive id types: int, string,...
+ * 2> definitions of non-primitive id types: struct id,... and their traits
+ */
+
+namespace boost {
+ namespace channel {
+
+ ///no default definition for id trait; must explicitly define it for each id type
+ template<class id_type> class id_trait;
+
+ /**
+ * define null_id to avoid overhead for local port and signal
+ */
+ class null_id {
+ public:
+ bool operator==(const null_id &) const {
+ return false;
+ }
+ bool operator<(const null_id &) const {
+ return false;
+ }
+ bool operator!=(const null_id &) const {
+ return false;
+ }
+ };
+
+ /// trait class for null ids
+ template <>
+ class BOOST_CHANNEL_DECL id_trait<null_id> {
+ public:
+ ///define system msgs
+ static null_id channel_conn_msg;
+ static null_id channel_disconn_msg;
+ static null_id init_subscription_info_msg;
+ static null_id connection_ready_msg;
+ static null_id subscription_info_msg;
+ static null_id unsubscription_info_msg;
+ static null_id publication_info_msg;
+ static null_id unpublication_info_msg;
+ static null_id app_msg_begin;
+
+ typedef null_id id_type;
+
+ ///need the comparisons for msg matching and map
+ static bool eq(const id_type &id1, const id_type &id2)
+ { return false;}
+ static bool lt(const id_type &id1, const id_type &id2)
+ { return false;}
+
+ //compiler doesnt allow references here
+ //static bool match(const id_type &id1, const id_type &id2)
+ static bool match(id_type id1, id_type id2)
+ { return false;}
+
+ //linear name_space dont support wildcard yet
+ static bool wildcard_name(const id_type &id) {
+ return false;
+ }
+
+ ///string representation of ids, for debugging
+ static std::string id_to_string(const id_type &id) {
+ return "null_id";
+ }
+
+ };
+
+ /// trait class for integer ids
+ template <>
+ class BOOST_CHANNEL_DECL id_trait<int> {
+ public:
+ ///define system msgs
+ /*
+ enum sys_ids {
+ ///--- sys msg starts at 1000 ---
+ channel_conn_msg=1000,
+ channel_disconn_msg,
+ init_subscription_info_msg,
+ connection_ready_msg,
+ subscription_info_msg,
+ unsubscription_info_msg,
+ publication_info_msg,
+ unpublication_info_msg,
+ ///--- app msg starts at 2000 ---
+ app_msg_begin=2000
+ };
+ */
+ static int channel_conn_msg;
+ static int channel_disconn_msg;
+ static int init_subscription_info_msg;
+ static int connection_ready_msg;
+ static int subscription_info_msg;
+ static int unsubscription_info_msg;
+ static int publication_info_msg;
+ static int unpublication_info_msg;
+ static int app_msg_begin;
+
+ typedef int id_type;
+
+ ///need the comparisons for msg matching and map
+ static bool eq(const id_type &id1, const id_type &id2)
+ { return id1 == id2;}
+ static bool lt(const id_type &id1, const id_type &id2)
+ { return id1 < id2;}
+
+ //compiler doesnt allow references here
+ //static bool match(const id_type &id1, const id_type &id2)
+ static bool match(id_type id1, id_type id2)
+ { return id1 == id2;}
+
+ //linear name_space dont support wildcard yet
+ static bool wildcard_name(const id_type &id) {
+ return false;
+ }
+
+ ///string representation of ids, for debugging
+ static std::string id_to_string(const id_type &id) {
+ std::ostringstream os;
+ os << id;
+ return os.str();
+ }
+
+ };
+
+ /// trait class for string ids
+ template <>
+ class BOOST_CHANNEL_DECL id_trait<std::string> {
+ public:
+ ///define system msgs
+
+ static std::string channel_conn_msg;
+ static std::string channel_disconn_msg;
+ static std::string init_subscription_info_msg;
+ static std::string connection_ready_msg;
+ static std::string subscription_info_msg;
+ static std::string unsubscription_info_msg;
+ static std::string publication_info_msg;
+ static std::string unpublication_info_msg;
+
+ typedef std::string id_type;
+
+ ///need the comparisons for msg matching and map
+ static bool eq(const std::string &id1, const std::string &id2)
+ { return id1 == id2;}
+ static bool lt(const std::string &id1, const std::string &id2)
+ { return id1 < id2;}
+
+ //compiler doesnt allow references here
+ //static bool match(const std::string &id1, const std::string &id2)
+ static bool match(std::string id1, std::string id2)
+ { return id1 == id2;}
+
+ //linear name_space dont support wildcard yet
+ static bool wildcard_name(const id_type &id) {
+ return false;
+ }
+
+ static std::string id_to_string(const std::string &id) {
+ return id;
+ }
+
+ };
+
+ /**
+ * definition of sample POD struct ids
+ */
+ ///ids have 2 fields: family and type
+ enum message_family {
+ system_message, application_message
+ };
+
+ struct BOOST_CHANNEL_DECL struct_id {
+ message_family family;
+ int type;
+ bool operator<(const struct_id &id) const {
+ if (family < id.family || (family == id.family && type < id.type))
+ return true;
+ return false;
+ }
+ bool operator==(const struct_id &id) const {
+ if (family == id.family && type == id.type)
+ return true;
+ return false;
+ }
+ bool operator!=(const struct_id &id) const {
+ if (family != id.family || type != id.type)
+ return true;
+ return false;
+ }
+ ///serializer for struct_id as id_type
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version) {
+ ar & family & type;
+ }
+
+ };
+
+ /// trait class for sample POD struct ids
+ template<>
+ class BOOST_CHANNEL_DECL id_trait<struct_id> {
+ public:
+ ///define system msgs
+
+ static struct_id channel_conn_msg;
+ static struct_id channel_disconn_msg;
+ static struct_id init_subscription_info_msg;
+ static struct_id connection_ready_msg;
+ static struct_id subscription_info_msg;
+ static struct_id unsubscription_info_msg;
+ static struct_id publication_info_msg;
+ static struct_id unpublication_info_msg;
+
+ typedef struct_id id_type;
+
+ ///need the comparisons for msg matching and map
+ static bool eq(const struct_id &id1, const struct_id &id2)
+ { return id1 == id2;}
+ static bool lt(const struct_id &id1, const struct_id &id2)
+ { return id1 < id2;}
+
+ //compiler doesnt allow references here
+ //static bool match(const struct_id &id1, const struct_id &id2)
+ static bool match(struct_id id1, struct_id id2)
+ { return id1 == id2;}
+
+ //linear name_space dont support wildcard yet
+ static bool wildcard_name(const id_type &id) {
+ return false;
+ }
+
+ static std::string id_to_string(const struct_id &id) {
+ std::ostringstream os;
+ os << "[Family:" << id.family << ", Type:" << id.type <<"]";
+ return os.str();
+ }
+ };
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/name_spaces/linear_name_space.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/linear_name_space.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,284 @@
+//
+// linear_name_space.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef LINEAR_NAME_SPACE_HPP
+#define LINEAR_NAME_SPACE_HPP
+
+#include <map>
+#include <list>
+#include <algorithm>
+#include <boost/channel/name_spaces/linear_id_trait.hpp>
+#include <boost/channel/platforms/synch_policy.hpp>
+#include <boost/channel/name.hpp>
+#include <boost/channel/name_spaces/name_space_change_notify.hpp>
+
+namespace boost {
+ namespace channel {
+ /**
+ * linear_name_space: combo of simple linear space and associative space
+ * . simple linear space: name_matching = exact_match
+ * . assoc name space: name_matching = assoc/fuzzy/regex-based matching
+ * using stl map for linear name_space
+ */
+ template<typename idtype, typename executor_type, typename synchpolicy,
+ bool exact_match = true>
+ class linear_name_space {
+ public:
+ typedef idtype id_type;
+ typedef id_trait<id_type> id_trait;
+ typedef synchpolicy synch_policy;
+ typedef executor_type executor;
+ typedef typename synch_policy::platform platform;
+ //we dont care about In/Out operations here, just names and bindings
+ typedef name<id_type,executor_type,synch_policy> name;
+
+ private:
+ typedef linear_name_space<idtype,executor_type,synchpolicy,exact_match> ns_type;
+
+ struct ns_entry {
+ std::list<name *> outs_;
+ std::list<name *> ins_;
+ };
+
+ //name_space - pubsub table
+ std::map<id_type, ns_entry> ns_;
+ typename synch_policy::mutex ns_lock_;
+
+ executor_type *exec_; //default executor_type for all async_opers/callbacks in channel
+ //for sending out local name_space change events
+ detail::name_space_change_notify<ns_type> ns_notifier_;
+
+ public:
+
+ linear_name_space(executor_type *e) : exec_(e), ns_notifier_(*this) {
+ }
+
+ ~linear_name_space() {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+ //clean up name_space structures
+ ns_.clear();
+ }
+
+ executor_type * get_exec(void) {
+ return exec_;
+ }
+
+ /**
+ * Local operations on Channel/Router name_space:
+ * bind/unbind named_in/out
+ * for each bind/unbind, 3 kinds of changes made:
+ * 1. binding to the name_space data structure
+ * 2. binding between named_out and named_in
+ * 3. exported ids exposed to external channels
+ */
+ ///
+ void bind_named_out(name *n)
+ {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+
+ //add new binding to name_space
+ ns_entry &entry = ns_[n->id_]; //if first time, the entry will be added
+ if (std::find(entry.outs_.begin(), entry.outs_.end(), n) != entry.outs_.end())
+ return;
+
+ entry.outs_.push_front(n);
+
+ //platform::log("ns::bind_named_out name: "+id_trait::id_to_string(n->id_));
+
+ //bind Out->In
+ //using reverse_iterator, so that later-added names will be pushed to
+ //the front of bindings
+ if (exact_match) {
+ for(typename std::list<name *>::reverse_iterator iter=entry.ins_.rbegin();
+ iter != entry.ins_.rend(); iter++) {
+ name *m = (*iter);
+ if (name::scope_checking(n,m)) {
+ n->bind(m);
+ m->bind(n);
+ }
+ }
+ }
+ else { //assoc match
+ typename std::map<id_type, ns_entry>::iterator it = ns_.begin();
+ for (; it != ns_.end(); it++) {
+ //platform::log("ns::bind_named_in compare: "+id_trait::id_to_string(it->first));
+ if (id_trait::match(it->first, n->id_)) {
+ ns_entry &ent = it->second;
+ //bind Out->In
+ //using reverse_iterator, so that later-added names will be pushed to
+ //the front of bindings
+ for(typename std::list<name *>::reverse_iterator iter=ent.ins_.rbegin();
+ iter != ent.ins_.rend(); iter++) {
+ name *m = (*iter);
+ if (name::scope_checking(n,m)) {
+ n->bind(m);
+ m->bind(n);
+ }
+ }
+ }
+ }
+ }
+
+ //propagate name_space changes
+ lock.unlock();
+ if(n->type_ == name_base::member_local)
+ ns_notifier_.notify(name_base::bind_out_ev, n);
+ }
+
+ ///
+ void unbind_named_out(name *n)
+ {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+
+ //del binding from name_space
+ ns_entry &entry = ns_[n->id_];
+ entry.outs_.remove(n);
+ //clean up
+ if (entry.outs_.empty() && entry.ins_.empty())
+ ns_.erase(n->id_);
+
+ //unbind all Out->In
+ //n->unbind_all();
+
+ //propagate name_space changes
+ lock.unlock();
+ if(n->type_ == name_base::member_local)
+ ns_notifier_.notify(name_base::unbind_out_ev, n);
+ }
+
+ ///
+ void bind_named_in(name *n)
+ {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+
+ //add new binding to name_space
+ ns_entry &entry = ns_[n->id_]; //if first time, the entry will be added
+ if (std::find(entry.ins_.begin(), entry.ins_.end(), n) != entry.ins_.end())
+ return;
+
+ entry.ins_.push_front(n);
+
+ //platform::log("ns::bind_named_in name: "+id_trait::id_to_string(n->id_));
+
+ //bind Out->In
+ //using reverse_iterator, so that later-added names will be pushed to
+ //the front of bindings
+ if (exact_match) {
+ for(typename std::list<name *>::reverse_iterator iter=entry.outs_.rbegin();
+ iter != entry.outs_.rend(); iter++) {
+ name *m = (*iter);
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ }
+ }
+ }
+ else {
+ typename std::map<id_type, ns_entry>::iterator it = ns_.begin();
+ for (; it != ns_.end(); it++) {
+ //platform::log("ns::bind_named_in compare: "+id_trait::id_to_string(it->first));
+ if (id_trait::match(it->first, n->id_)) {
+ ns_entry &ent = it->second;
+ //bind Out->In
+ //using reverse_iterator, so that later-added names will be pushed to
+ //the front of bindings
+ for(typename std::list<name *>::reverse_iterator iter=ent.outs_.rbegin();
+ iter != ent.outs_.rend(); iter++) {
+ name *m = (*iter);
+ if (name::scope_checking(m,n)) {
+ m->bind(n);
+ n->bind(m);
+ }
+ }
+ }
+ }
+ }
+
+ //propagate name_space changes
+ lock.unlock();
+ if(n->type_ == name_base::member_local)
+ ns_notifier_.notify(name_base::bind_in_ev, n);
+ }
+
+ ///
+ void unbind_named_in(name *n)
+ {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+
+ //del binding from name_space
+ ns_entry &entry = ns_[n->id_];
+ entry.ins_.remove(n);
+ //clean up
+ if (entry.outs_.empty() && entry.ins_.empty())
+ ns_.erase(n->id_);
+
+ //unbind all Out->In
+ //n->unbind_all();
+
+ //propagate name_space changes
+ lock.unlock();
+ if(n->type_ == name_base::member_local)
+ ns_notifier_.notify(name_base::unbind_in_ev, n);
+ }
+
+ /**
+ * 3. name_space queries
+ */
+ template <typename Predicate>
+ void bound_ids_for_in(Predicate p, std::vector<id_type> &ids)
+ {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+ for(typename std::map<id_type, ns_entry>::iterator iter = ns_.begin();
+ iter != ns_.end(); iter++) {
+ ns_entry &entry = iter->second;
+ if (entry.ins_.empty())
+ continue;
+
+ bool found = false;
+ for(typename std::list<name*>::iterator iter2 = entry.ins_.begin();
+ iter2 != entry.ins_.end() && !found; iter2++) {
+ name *n = (*iter2);
+ if (p(n)) {
+ found = true;
+ }
+ }
+ if (found)
+ ids.push_back(iter->first);
+ }
+ }
+
+ template <typename Predicate>
+ void bound_ids_for_out(Predicate p, std::vector<id_type> &ids)
+ {
+ typename synch_policy::scoped_lock lock(ns_lock_);
+ for(typename std::map<id_type, ns_entry>::iterator iter = ns_.begin();
+ iter != ns_.end(); iter++) {
+ ns_entry &entry = iter->second;
+ if (entry.outs_.empty())
+ continue;
+
+ bool found = false;
+ for(typename std::list<name*>::iterator iter2 = entry.outs_.begin();
+ iter2 != entry.outs_.end() && !found; iter2++) {
+ name *n = (*iter2);
+ if (p(n)) {
+ found = true;
+ }
+ }
+ if (found)
+ ids.push_back(iter->first);
+ }
+ }
+
+ };
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/name_spaces/name_space_change_notify.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/name_space_change_notify.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,161 @@
+//
+// name_space_change_notify.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef NAME_SPACE_CHANGE_NOTIFY_HPP
+#define NAME_SPACE_CHANGE_NOTIFY_HPP
+
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/named_in_out.hpp>
+#include <boost/channel/dispatchers/broadcast_dispatcher.hpp>
+#include <boost/channel/message.hpp>
+
+namespace boost {
+ namespace channel {
+ namespace detail {
+
+ template<typename name_space_type>
+ class name_space_change_notify {
+ typedef typename name_space_type::id_type id_type;
+ typedef typename name_space_type::id_trait id_trait;
+ typedef typename name_space_type::name name;
+ typedef named_out<name_space_type,
+ typename broadcast_dispatcher<name_space_type,
+ typename name_space_type::platform>::sender> named_out;
+ struct binding_notify {
+ named_out *bind_out, *unbind_out, *bind_in, *unbind_in;
+ };
+ binding_notify notify_[name_base::scope_number];
+ bool silent;
+ public:
+ name_space_change_notify(name_space_type & ns) {
+ silent = true;
+ for(int i=0;i<name_base::scope_number;i++) {
+ notify_[i].bind_out = new named_out(ns, (id_type)id_trait::publication_info_msg,(typename name::scope_type)i);
+ notify_[i].unbind_out = new named_out(ns, (id_type)id_trait::unpublication_info_msg,(typename name::scope_type)i);
+ notify_[i].bind_in = new named_out(ns, (id_type)id_trait::subscription_info_msg,(typename name::scope_type)i);
+ notify_[i].unbind_in = new named_out(ns, (id_type)id_trait::unsubscription_info_msg,(typename name::scope_type)i);
+ }
+ silent = false;
+ }
+
+ ~name_space_change_notify() {
+ silent = true;
+ for(int i=0;i<name::scope_number;i++) {
+ delete notify_[i].bind_out;
+ delete notify_[i].unbind_out;
+ delete notify_[i].bind_in;
+ delete notify_[i].unbind_in;
+ }
+ silent = false;
+ }
+
+ ///notify all related (local/remote/global) named_ins/outs about changes
+ void notify(typename name::binding_event op, name *n)
+ {
+ typename name_base::scope_type scope = n->scope_;
+ if(n->id_ == id_trait::publication_info_msg ||
+ n->id_ == id_trait::unpublication_info_msg ||
+ n->id_ == id_trait::subscription_info_msg ||
+ n->id_ == id_trait::unsubscription_info_msg) {
+ if(silent)
+ return;
+ scope = name::scope_local;
+ }
+ boost::shared_ptr<pubsub_info_msg_t<id_type> > sub(new pubsub_info_msg_t<id_type>());
+ sub->msg_types.push_back(n->id_);
+ named_out *no;
+ switch(op) {
+ case name::bind_out_ev:
+ no = notify_[scope].bind_out;
+ break;
+ case name::unbind_out_ev:
+ no = notify_[scope].unbind_out;
+ break;
+ case name::bind_in_ev:
+ no = notify_[scope].bind_in;
+ break;
+ case name::unbind_in_ev:
+ no = notify_[scope].unbind_in;
+ break;
+ default:
+ break;
+ }
+ no->send(sub);
+ }
+
+ ///just notify external (remote) named_ins/outs (at interface) about changes
+ void notify_external(typename name::binding_event op, name *n)
+ {
+ if (n->scope_ == name::scope_local) return;
+ //dont need to send sys_msgs pub/subs, interface has done all
+ if(n->id_ == id_trait::publication_info_msg ||
+ n->id_ == id_trait::unpublication_info_msg ||
+ n->id_ == id_trait::subscription_info_msg ||
+ n->id_ == id_trait::unsubscription_info_msg)
+ return;
+ boost::shared_ptr<pubsub_info_msg_t<id_type> > sub(new pubsub_info_msg_t<id_type>());
+ sub->msg_types.push_back(n->id_);
+ named_out *no;
+ switch(op) {
+ case name::bind_out_ev:
+ no = notify_[name::scope_remote].bind_out;
+ break;
+ case name::unbind_out_ev:
+ no = notify_[name::scope_remote].unbind_out;
+ break;
+ case name::bind_in_ev:
+ no = notify_[name::scope_remote].bind_in;
+ break;
+ case name::unbind_in_ev:
+ no = notify_[name::scope_remote].unbind_in;
+ break;
+ default:
+ break;
+ }
+ no->send(sub);
+ }
+
+ ///just notify internal (local) named_ins/outs about changes
+ void notify_internal(typename name::binding_event op, name *n)
+ {
+ if (n->scope_ == name::scope_remote) return;
+ if(silent) {
+ if(n->id_ == id_trait::publication_info_msg ||
+ n->id_ == id_trait::unpublication_info_msg ||
+ n->id_ == id_trait::subscription_info_msg ||
+ n->id_ == id_trait::unsubscription_info_msg)
+ return;
+ }
+ boost::shared_ptr<pubsub_info_msg_t<id_type> > sub(new pubsub_info_msg_t<id_type>());
+ sub->msg_types.push_back(n->id_);
+ named_out *no;
+ switch(op) {
+ case name::bind_out_ev:
+ no = notify_[name::scope_local].bind_out;
+ break;
+ case name::unbind_out_ev:
+ no = notify_[name::scope_local].unbind_out;
+ break;
+ case name::bind_in_ev:
+ no = notify_[name::scope_local].bind_in;
+ break;
+ case name::unbind_in_ev:
+ no = notify_[name::scope_local].unbind_in;
+ break;
+ default:
+ break;
+ }
+ no->send(sub);
+ }
+ };
+ }
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/name_spaces/null_name_space.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/name_spaces/null_name_space.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,41 @@
+//
+// null_name_space.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+
+#ifndef NULL_NAME_SPACE_HPP
+#define NULL_NAME_SPACE_HPP
+
+#include <boost/channel/name.hpp>
+
+namespace boost {
+ namespace channel {
+ /**
+ * null_name_space:
+ * convenience class for "unnamed" entities;
+ * no real functionalities; just for transferring type info
+ */
+ template<typename idtype, typename executor_type, typename synchpolicy,
+ bool exact_match = true>
+ class null_name_space {
+ public:
+ typedef idtype id_type;
+ typedef id_trait<id_type> id_trait;
+ typedef synchpolicy synch_policy;
+ typedef executor_type executor;
+ typedef typename synch_policy::platform platform;
+ //we dont care about In/Out operations here, just names and bindings
+ typedef name<id_type,executor_type,synch_policy> name;
+
+ void unbind_named_out(name *) {}
+ void unbind_named_in(name *) {}
+ };
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/named_in_out.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/named_in_out.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,370 @@
+//
+// named_in_out.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef NAMED_IN_OUT_HPP
+#define NAMED_IN_OUT_HPP
+
+#include <vector>
+#include <map>
+#include <iostream>
+
+namespace boost {
+ namespace channel {
+ /**
+ * named_out/named_in provides the basic functionality of out/in
+ * for use inside name_space, always use broadcast_dispatcher
+ */
+ template<typename name_space, typename dispatcher_sender_type>
+ class named_out: public name_space::name, public dispatcher_sender_type {
+ public:
+ typedef typename name_space::executor executor_type;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::name name_type;
+ name_space * ch_;
+ executor_type *exe_;
+ named_out (name_space & ch,
+ id_type id,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local,
+ executor_type *e = NULL
+ ) :
+ name_space::name (id,scope,type),
+ dispatcher_sender_type(this,e!=NULL?e:ch.get_exec()),
+ ch_(&ch), exe_(e!=NULL?e:ch.get_exec()) {
+ ch_->bind_named_out(this);
+ }
+ template <typename binding_cb_type>
+ named_out (name_space & ch,
+ id_type id,
+ binding_cb_type cb,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local,
+ executor_type *e = NULL
+ ) :
+ name_space::name (id, scope, type, cb, e!=NULL?e:ch.get_exec()),
+ dispatcher_sender_type(this,e!=NULL?e:ch.get_exec()),
+ ch_(&ch), exe_(e!=NULL?e:ch.get_exec()) {
+ ch_->bind_named_out(this);
+ }
+ //unnamed named_out
+ named_out (executor_type *e = NULL) :
+ name_space::name (),
+ dispatcher_sender_type(this,e),
+ ch_(NULL), exe_(e) {
+ }
+ ~named_out () {
+ if (ch_ != NULL)
+ ch_->unbind_named_out(this);
+ }
+
+ //attach unnamed named_out to name space
+ void attach_name_space (name_space & ch,
+ id_type id,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local) {
+ this->set_name (id,scope,type);
+ ch_ = &ch;
+ ch_->bind_named_out(this);
+ }
+ template <typename binding_cb_type>
+ void attach_name_space (name_space & ch,
+ id_type id,
+ binding_cb_type cb,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local) {
+ this->set_name (id, scope, type, cb, exe_!=NULL?exe_:ch.get_exec()),
+ ch_ = &ch;
+ ch_->bind_named_out(this);
+ }
+ };
+
+ template <
+ typename name_space,
+ typename dispatcher_recver_type
+ >
+ class named_in : public name_space::name,
+ public dispatcher_recver_type {
+ public:
+ typedef typename name_space::executor executor_type;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::name name_type;
+ name_space * ch_;
+ executor_type *exe_;
+ //asynch recvers constructor
+ template <typename recver_type,typename binding_cb_type>
+ named_in (name_space & ch,
+ id_type id,
+ recver_type rc,
+ binding_cb_type bc,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local,
+ executor_type *e = NULL
+ ) :
+ name_space::name (id,scope,type,bc, e!=NULL?e:ch.get_exec()),
+ dispatcher_recver_type(this, rc, e!=NULL?e:ch.get_exec()), ch_(&ch),
+ exe_(e!=NULL?e:ch.get_exec()) {
+ ch_->bind_named_in(this);
+ }
+ //asynch recvers constructor
+ template <typename recver_type>
+ named_in (name_space & ch,
+ id_type id,
+ recver_type rc,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local,
+ executor_type *e = NULL
+ ) :
+ name_space::name (id,scope,type),
+ dispatcher_recver_type(this, rc, e!=NULL?e:ch.get_exec()), ch_(&ch),
+ exe_(e!=NULL?e:ch.get_exec()) {
+ ch_->bind_named_in(this);
+ }
+ //synch/active recvers constructor
+ named_in (name_space & ch,
+ id_type id,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local,
+ executor_type *e = NULL
+ ) :
+ name_space::name (id,scope,type),
+ dispatcher_recver_type(this), ch_(&ch), exe_(e!=NULL?e:ch.get_exec()) {
+ ch_->bind_named_in(this);
+ }
+ //unnamed named_in
+ template <typename recver_type>
+ named_in (recver_type rc,
+ executor_type *e = NULL
+ ) :
+ name_space::name (),
+ dispatcher_recver_type(this, rc, e),
+ ch_(NULL), exe_(e) {
+ }
+ ~named_in () {
+ if (ch_ != NULL)
+ ch_->unbind_named_in(this);
+ }
+ //
+ template <typename binding_cb_type>
+ void attach_name_space (name_space & ch,
+ id_type id,
+ binding_cb_type bc,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local
+ ) {
+ if (exe_ == NULL) exe_ = ch.get_exec();
+ this->set_name (id,scope,type,bc, exe_),
+ ch_ = &ch;
+ ch_->bind_named_in(this);
+ (dispatcher_recver_type*) this->set_exe(exe_);
+ }
+ //
+ void attach_name_space (name_space & ch,
+ id_type id,
+ typename name_type::scope_type scope = name_type::scope_global,
+ typename name_type::member_type type = name_type::member_local
+ ) {
+ if (exe_ == NULL) exe_ = ch.get_exec();
+ this->set_name (id,scope,type);
+ ch_ = &ch;
+ ch_->bind_named_in(this);
+ (dispatcher_recver_type*) this->set_exe(exe_);
+ }
+ };
+
+ /**
+ * named_out_bundle/named_in_bundle or named_pub/named_sub
+ * no binding callbacks installed
+ */
+ template <
+ typename name_space,
+ typename dispatcher_sender_type
+ >
+ class named_out_bundle {
+ public:
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::id_trait id_trait;
+ typedef typename name_space::executor executor_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef named_out<name_space,dispatcher_sender_type> named_out;
+ public:
+ named_out_bundle(name_space & ch,
+ typename named_out::member_type type = named_out::member_local,
+ executor_type *e = NULL) :
+ ch_(ch), type_(type), exec_(e!=NULL?e:ch.get_exec()) {
+ }
+ ~named_out_bundle() {
+ for(typename std::map<id_type, named_out*>::iterator iter=named_outs_.begin();
+ iter != named_outs_.end(); iter++)
+ delete iter->second;
+ }
+ int get_ids(std::vector<id_type> &ids) {
+ for(typename std::map<id_type, named_out*>::iterator iter=named_outs_.begin();
+ iter != named_outs_.end(); iter++)
+ ids.push_back(iter->first);
+ return ids.size();
+ }
+ bool bound(id_type & id) {
+ typename std::map<id_type, named_out*>::iterator iter = named_outs_.find(id);
+ if (iter != named_outs_.end()) {
+ return iter->second->num_bindings() > 0;
+ }
+ return false;
+ }
+ named_out * find(id_type & id) {
+ typename std::map<id_type, named_out*>::iterator iter = named_outs_.find(id);
+ if (iter != named_outs_.end()) {
+ return iter->second;
+ }
+ return NULL;
+ }
+ named_out * find_match(id_type & id) {
+ for(typename std::map<id_type, named_out*>::iterator iter = named_outs_.begin();
+ iter != named_outs_.end(); iter++)
+ if(id_trait::match(iter->first, id)) {
+ return iter->second;
+ }
+ return NULL;
+ }
+ void bind(std::vector<std::pair<id_type,typename named_out::scope_type> > & ids) {
+ for(typename std::vector<id_type>::iterator iter=ids.begin();iter != ids.end(); iter++) {
+ bind(iter->first, iter->second);
+ }
+ }
+ bool bind(id_type & id, typename named_out::scope_type scope = named_out::scope_global) {
+ if (named_outs_.find(id) == named_outs_.end()) {
+ named_outs_[id] = new named_out(ch_, id, scope, type_, exec_);
+ return true;
+ }
+ return false;
+ }
+ bool unbind(id_type & id) {
+ typename std::map<id_type, named_out*>::iterator iter = named_outs_.find(id);
+ if (iter != named_outs_.end()) {
+ delete iter->second;
+ named_outs_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+ void unbind_all(void) {
+ for(typename std::map<id_type, named_out*>::iterator iter=named_outs_.begin();
+ iter != named_outs_.end(); iter++)
+ delete iter->second;
+ named_outs_.clear();
+ }
+ private:
+ name_space & ch_;
+ typename named_out::member_type type_;
+ executor_type *exec_;
+ std::map<id_type, named_out*> named_outs_;
+ };
+
+ template <
+ typename name_space,
+ typename dispatcher_recver_type
+ >
+ class named_in_bundle {
+ public:
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::id_trait id_trait;
+ typedef typename name_space::executor executor_type;
+ typedef named_in<name_space,dispatcher_recver_type> named_in;
+ private:
+ struct named_in_creator_base {
+ virtual named_in* create(name_space & ch, id_type &id,
+ typename named_in::scope_type scope,
+ typename named_in::member_type t,
+ executor_type *e) = 0;
+ virtual ~named_in_creator_base() {}
+ };
+ template <typename recver_type>
+ struct named_in_creator: public named_in_creator_base {
+ recver_type recver_;
+ named_in_creator(recver_type rc): recver_(rc) {}
+ named_in* create(name_space & ch, id_type &id,
+ typename named_in::scope_type scope,
+ typename named_in::member_type t,
+ executor_type *e) {
+ return new named_in(ch,id,recver_,scope,t,e);
+ }
+ };
+ name_space & ch_;
+ typename named_in::member_type type_;
+ executor_type *exec_;
+ std::map<id_type, named_in*> named_ins_;
+ named_in_creator_base *creator_;
+ public:
+ template <typename recver_type>
+ named_in_bundle(name_space & ch, recver_type rc,
+ typename named_in::member_type type = named_in::member_local,
+ executor_type *e = NULL) :
+ ch_(ch), type_(type), exec_(e!=NULL?e:ch.get_exec()), creator_(new named_in_creator<recver_type>(rc)) {
+ }
+ ~named_in_bundle() {
+ for(typename std::map<id_type, named_in*>::iterator iter=named_ins_.begin();
+ iter != named_ins_.end(); iter++)
+ delete iter->second;
+ delete creator_;
+ }
+ int get_ids(std::vector<id_type> &ids) {
+ for(typename std::map<id_type, named_in*>::iterator iter=named_ins_.begin();
+ iter != named_ins_.end(); iter++)
+ ids.push_back(iter->first);
+ return ids.size();
+ }
+ named_in * find(id_type & id) {
+ typename std::map<id_type, named_in*>::iterator iter = named_ins_.find(id);
+ if (iter != named_ins_.end()) {
+ return iter->second;
+ }
+ return NULL;
+ }
+ named_in * find_match(id_type & id) {
+ for(typename std::map<id_type, named_in*>::iterator iter = named_ins_.begin();
+ iter != named_ins_.end(); iter++)
+ if(id_trait::match(iter->first, id)) {
+ return iter->second;
+ }
+ return NULL;
+ }
+ void bind(std::vector<std::pair<id_type,typename named_in::scope_type> > & ids) {
+ for(typename std::vector<std::pair<id_type,typename named_in::scope_type> >::iterator iter=ids.begin();
+ iter != ids.end(); iter++) {
+ bind(iter->first, iter->second);
+ }
+ }
+ bool bind(id_type & id, typename named_in::scope_type scope = named_in::scope_global) {
+ if (named_ins_.find(id) == named_ins_.end()) {
+ named_ins_[id] = creator_->create(ch_, id, scope, type_, exec_);
+ return true;
+ }
+ return false;
+ }
+ bool unbind(id_type & id) {
+ typename std::map<id_type, named_in*>::iterator iter = named_ins_.find(id);
+ if (iter != named_ins_.end()) {
+ delete iter->second;
+ named_ins_.erase(iter);
+ return true;
+ }
+ return false;
+ }
+ void unbind_all(void) {
+ for(typename std::map<id_type, named_in*>::iterator iter=named_ins_.begin();
+ iter != named_ins_.end(); iter++)
+ delete iter->second;
+ named_ins_.clear();
+ }
+ };
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/peer.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/peer.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,82 @@
+//
+// peer.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef PEER_HPP
+#define PEER_HPP
+
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<typename > class connection;
+
+ template<typename id_type>
+ class peer_type {
+ public:
+ typedef connection<id_type> connection;
+ enum type {
+ local_peer = 0, remote_peer
+ };
+ enum role {
+ undefined_role, active_role, //i start connection setup process
+ passive_role,
+ //i wait for others to connect
+ };
+
+ void bind_peer(peer_type *p, role r, connection *c) {
+ peer_ = p;
+ role_ = r;
+ conn_ = c;
+ }
+ virtual void unbind() {
+ peer_ = 0;
+ role_ = undefined_role;
+ conn_ = 0;
+ }
+ //channel or stream should call release to disconn and cleanup
+ void release(void) {
+ if (conn_ != NULL)
+ delete conn_; //connection destructor responsible for deleting all
+ }
+
+ peer_type() :
+ peer_(0), role_(undefined_role), conn_(0) {
+ }
+ virtual ~peer_type() {
+ }
+
+ std::pair<type, std::string> peer_get_info(void) {
+ return peer_->get_info();
+ }
+ void peer_send(id_type id, shared_ptr<void> msg) {
+ peer_->send(id, msg);
+ }
+
+ //stream should override get_info to provide transport info (e.g. host/port..)
+ virtual std::pair<type, std::string> get_info(void) {
+ std::pair<type, std::string> info;
+ info.first = local_peer;
+ info.second = "";
+ return info;
+ }
+
+ //concrete peer types (streams, interface) should override this
+ virtual void send(id_type id, shared_ptr<void> msg) = 0;
+
+ peer_type *peer_;
+ role role_;
+ connection *conn_;
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/platforms/boost_platform.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/platforms/boost_platform.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,43 @@
+//
+// boost_platform.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_PLATFORM_HPP
+#define BOOST_PLATFORM_HPP
+
+#include <iostream>
+#include <string>
+#include <boost/thread.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/channel/platforms/null_mutex.hpp>
+#include <boost/channel/platforms/null_condition.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+namespace boost {
+ namespace channel {
+
+ class boost_platform {
+ public:
+ //synch primitive
+ typedef detail::null_mutex null_mutex;
+ typedef detail::null_condition null_condition;
+ //typedef boost::mutex mutex;
+ typedef boost::recursive_mutex mutex;
+ typedef boost::condition condition;
+ //timeout
+ typedef boost::posix_time::time_duration timeout_type;
+ //log
+ static void log(std::string info) {
+ std::cout << "log << " << info << " >>" << std::endl;
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/platforms/null_condition.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/platforms/null_condition.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,59 @@
+//
+// null_condition.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_CHANNEL_NULL_CONDITION_HPP
+#define BOOST_CHANNEL_NULL_CONDITION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+#include <boost/thread.hpp>
+#include <boost/utility.hpp>
+
+namespace boost {
+ namespace channel {
+ namespace detail {
+
+ class null_condition: private boost::noncopyable {
+ public:
+ null_condition() {
+ }
+ ~null_condition() {
+ }
+
+ void notify_one() {
+ }
+ void notify_all() {
+ }
+
+ template<typename L>
+ void wait(L& lock) {
+ }
+
+ template<typename L, typename Pr>
+ void wait(L& lock, Pr pred) {
+ }
+
+ template<typename L>
+ bool timed_wait(L& lock, const xtime& xt) {
+ return false;
+ }
+
+ template<typename L, typename Pr>
+ bool timed_wait(L& lock, const xtime& xt, Pr pred) {
+ return false;
+ }
+
+ };
+
+ } // namespace detail
+ } // namespace channel
+} // namespace boost
+
+#endif

Added: sandbox/channel/boost/channel/platforms/null_mutex.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/platforms/null_mutex.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,71 @@
+//
+// null_mutex.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_CHANNEL_NULL_MUTEX_HPP
+#define BOOST_CHANNEL_NULL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/utility.hpp>
+
+namespace boost {
+ namespace channel {
+ namespace detail {
+
+ template <typename Mutex>
+ class null_scoped_lock : private noncopyable
+ {
+ public:
+ typedef Mutex mutex_type;
+
+ explicit null_scoped_lock(Mutex& mx, bool initially_locked=true)
+ {
+ }
+ ~null_scoped_lock()
+ {
+ }
+
+ void lock()
+ {
+ }
+ void unlock()
+ {
+ }
+
+ bool locked() const { return false; }
+ operator const void*() const { return 0; }
+
+ private:
+ };
+
+ class null_mutex
+ : private boost::noncopyable
+ {
+ public:
+ typedef null_scoped_lock<null_mutex> scoped_lock;
+
+ // Constructor.
+ null_mutex()
+ {
+ }
+
+ // Destructor.
+ ~null_mutex()
+ {
+ }
+
+ };
+
+ } // namespace detail
+ } // namespace channel
+} // namespace boost
+
+#endif

Added: sandbox/channel/boost/channel/platforms/synch_policy.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/platforms/synch_policy.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,40 @@
+//
+// synch_policy.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef SYNCH_POLICY_HPP
+#define SYNCH_POLICY_HPP
+
+#include <boost/channel/platforms/boost_platform.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<typename platform_t>
+ class null_synch {
+ public:
+ typedef platform_t platform;
+ typedef typename platform_t::null_mutex mutex;
+ typedef typename platform_t::null_condition condition;
+ typedef typename mutex::scoped_lock scoped_lock;
+ };
+
+ template <typename platform_t>
+ class mt_synch {
+ public:
+ typedef platform_t platform;
+ typedef typename platform_t::mutex mutex;
+ typedef typename platform_t::condition condition;
+ typedef typename mutex::scoped_lock scoped_lock;
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/pub_sub.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/pub_sub.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,92 @@
+//
+// pub_sub.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef PUB_SUB_HPP
+#define PUB_SUB_HPP
+
+#include <vector>
+//#include <boost/channel/named_in_out.hpp>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * the following 2 classes are convenience high level API classes
+ * for end uers to use; to support publish/subscribe model
+ */
+ template<typename name_space, typename dispatcher_sender_type>
+ class publisher: public named_out_bundle<name_space, dispatcher_sender_type> {
+ typedef named_out_bundle<name_space, dispatcher_sender_type> named_out_bundle;
+ typedef typename name_space::id_type id_type;
+ typedef typename named_out_bundle::named_out named_out;
+ public:
+ publisher(name_space & ch,
+ typename named_out::member_type type = named_out::member_local) :
+ named_out_bundle(ch, type) {
+ }
+ void publish(std::vector<std::pair<id_type,typename named_out::scope_type> > & ids) {
+ this->bind(ids);
+ }
+ bool publish(id_type & id, typename named_out::scope_type scope = named_out::scope_global) {
+ return this->bind(id, scope);
+ }
+ bool unpublish(id_type & id) {
+ return this->unbind(id);
+ }
+
+ //-- the following are API borrowed from dispatcher --
+ template <typename user_msg_type>
+ void send(id_type & id, user_msg_type *msg) {
+ named_out *no = find(id);
+ if (no != NULL)
+ no->send(msg);
+ }
+ template <typename user_msg_type, typename deleter>
+ void send(id_type & id, user_msg_type *msg, deleter deler) {
+ named_out *no = find(id);
+ if (no != NULL)
+ no->send(msg,deler);
+ }
+ template <typename user_msg_type>
+ void send(id_type & id, boost::shared_ptr<user_msg_type> msg) {
+ named_out *no = find(id);
+ if (no != NULL)
+ no->send(msg);
+ }
+ };
+
+ template <
+ typename name_space,
+ typename dispatcher_recver_type
+ >
+ class subscriber: public named_in_bundle<name_space,dispatcher_recver_type> {
+ typedef typename name_space::id_type id_type;
+ typedef named_in_bundle<name_space,dispatcher_recver_type> named_in_bundle;
+ typedef typename named_in_bundle::named_in named_in;
+ public:
+ template <typename recver_type>
+ subscriber(name_space & ch, recver_type rc,
+ typename named_in::member_type type = named_in::member_local) :
+ named_in_bundle(ch, rc, type) {
+ }
+ void subscribe(std::vector<std::pair<id_type,typename named_in::scope_type> > & ids) {
+ this->bind(ids);
+ }
+ bool subscribe(id_type & id, typename named_in::scope_type scope = named_in::scope_global) {
+ return this->bind(id,scope);
+ }
+ bool unsubscribe(id_type & id) {
+ return this->unbind(id);
+ }
+ };
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/queues/bounded_queue.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/queues/bounded_queue.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,88 @@
+//
+// bounded_queue.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOUNDED_QUEUE_HPP
+#define BOUNDED_QUEUE_HPP
+
+#include <deque>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * size bounded queue:
+ * . when queue is full, senders will be blocked
+ * . when queue is empty, retrievers will be blocked
+ */
+ template<typename elem_type, typename synch_policy, typename platform>
+ class bounded_que {
+ public:
+ typedef typename platform::timeout_type timeout_type;
+ typename synch_policy::mutex lock_;
+ typename synch_policy::condition not_full_;
+ typename synch_policy::condition not_empty_;
+ int num_blocked_putter;
+ int num_blocked_getter;
+ std::deque<elem_type> data_;
+ size_t max_sz_;
+ timeout_type put_timeout_;
+ timeout_type sett_timeout_;
+ enum def_sz_type {def_sz = 100};
+ bounded_que(int s = def_sz): max_sz_(s) {
+ num_blocked_putter = 0;
+ num_blocked_getter = 0;
+ }
+ void set_max_que_sz(size_t ms) {max_sz_ = ms;}
+ size_t get_max_que_sz(void) {return max_sz_;}
+ /*
+ void set_timeout(timeout_type to);
+ timeout_type get_timeout(void);
+ */
+ bool empty() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.empty();
+ }
+ bool full() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.size() >= max_sz_;
+ }
+ size_t size() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.size();
+ }
+ void put(elem_type & e) {
+ typename synch_policy::scoped_lock lock(lock_);
+ while (data_.size() >= max_sz_) {
+ num_blocked_putter++;
+ not_full_.wait(lock);
+ num_blocked_putter--;
+ }
+ data_.push_back(e);
+ if (num_blocked_getter > 0)
+ not_empty_.notify_one();
+ }
+ void get(elem_type & e) {
+ typename synch_policy::scoped_lock lock(lock_);
+ while (data_.empty()) {
+ num_blocked_getter++;
+ not_empty_.wait(lock);
+ num_blocked_getter--;
+ }
+ e = data_.front();
+ data_.pop_front();
+ if (num_blocked_putter > 0)
+ not_full_.notify_one();
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/queues/dropping_queue.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/queues/dropping_queue.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,67 @@
+//
+// dropping_queue.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef DROPPING_QUEUE_HPP
+#define DROPPING_QUEUE_HPP
+
+#include <deque>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * droppined queue: after reaching que size limit, old msgs will be dropped to give
+ * space to new msgs
+ */
+ template<typename elem_type, typename synch_policy, typename platform>
+ class dropping_que {
+ public:
+ typename synch_policy::mutex lock_;
+ std::deque<elem_type> data_;
+ size_t max_sz_;
+ enum def_sz_type {
+ def_sz = 100
+ };
+ dropping_que(int s = def_sz) :
+ max_sz_(s) {
+ }
+ bool empty() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.empty();
+ }
+ size_t size() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.size();
+ }
+ void set_max_que_sz(size_t ms) {
+ max_sz_ = ms;
+ }
+ size_t get_max_que_sz(void) {
+ return max_sz_;
+ }
+ void put(elem_type & e) {
+ typename synch_policy::scoped_lock lock(lock_);
+ if (data_.size() >= max_sz_)
+ data_.pop_front(); //remove old data
+ data_.push_back(e);
+ }
+ void get(elem_type & e) {
+ typename synch_policy::scoped_lock lock(lock_);
+ if (!data_.empty()) {
+ e = data_.front();
+ data_.pop_front();
+ }
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/queues/flow_controlled_queue.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/queues/flow_controlled_queue.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,31 @@
+//
+// flow_controlled_queue.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef FLOW_CONTROLLED_QUEUE_HPP
+#define FLOW_CONTROLLED_QUEUE_HPP
+
+#include <deque>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * flow controled queue: follow the design of ACE Message_Queue:
+ * 1. flow is controlled thru high/low water marks
+ * 2. support priorities of enque and deque
+ */
+ template<typename elem_type, typename synch_policy, typename timeout_type>
+ class flow_controlled_que {
+ public:
+ };
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/queues/queues.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/queues/queues.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,19 @@
+//
+// queues.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef QUEUES_HPP
+#define QUEUES_HPP
+
+#include <boost/channel/queues/unbounded_queue.hpp>
+#include <boost/channel/queues/bounded_queue.hpp>
+#include <boost/channel/queues/dropping_queue.hpp>
+//#include <boost/channel/queues/timed_queue.hpp>
+//#include <boost/channel/queues/flow_controlled_queue.hpp>
+
+#endif

Added: sandbox/channel/boost/channel/queues/timed_queue.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/queues/timed_queue.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,32 @@
+//
+// timed_queue.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef TIMED_QUEUE_HPP
+#define TIMED_QUEUE_HPP
+
+#include <deque>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * timed queue: msgs will be dropped after waiting in queue for some time
+ * following JavaSpace in its use of "Lease" on entries in space, when
+ * lease expires, the entry is removed
+ */
+ template<typename elem_type, typename synch_policy, typename timeout_type>
+ class timed_que {
+ public:
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/queues/unbounded_queue.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/queues/unbounded_queue.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,51 @@
+//
+// unbounded_queue.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef UNBOUNDED_QUEUE_HPP
+#define UNBOUNDED_QUEUE_HPP
+
+#include <deque>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * the simplest msg_que: unbounded size
+ */
+ template<typename elem_type, typename synch_policy, typename platform>
+ class unbounded_que {
+ public:
+ std::deque<elem_type> data_;
+ typename synch_policy::mutex lock_;
+ bool empty() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.empty();
+ }
+ size_t size() {
+ typename synch_policy::scoped_lock lock(lock_);
+ return data_.size();
+ }
+ void put(elem_type & e) {
+ typename synch_policy::scoped_lock lock(lock_);
+ data_.push_back(e);
+ }
+ void get(elem_type & e) {
+ typename synch_policy::scoped_lock lock(lock_);
+ if (!data_.empty()) {
+ e = data_.front();
+ data_.pop_front();
+ }
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/streams/asio_connector_async.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/streams/asio_connector_async.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,174 @@
+//
+// asio_connector_async.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_CONNECTOR_ASYNC_HPP
+#define ASIO_CONNECTOR_ASYNC_HPP
+
+#include <string>
+#include <list>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/asio.hpp>
+
+using boost::asio::ip::tcp;
+
+namespace boost {
+ namespace channel {
+ class asio_connector_async;
+
+ class conn_handler_base {
+ public:
+ virtual boost::shared_ptr<void> handle(asio_connector_async *conn,
+ boost::shared_ptr<tcp::socket> sock, bool active) = 0;
+ virtual ~conn_handler_base() {
+ }
+ };
+ template<typename conn_handler_type>
+ class conn_handler: public conn_handler_base {
+ public:
+ conn_handler(conn_handler_type h) :
+ handler_(h) {
+ }
+ boost::shared_ptr<void> handle(asio_connector_async *conn,
+ boost::shared_ptr<tcp::socket> sock_conn, bool active) {
+ return handler_(conn, sock_conn, active);
+ }
+ private:
+ conn_handler_type handler_;
+ };
+
+ class asio_connector_async {
+ public:
+ //need add locks to protect these, since they are touched by both
+ //io_service thread (main) and thread calling shutdown
+ std::list<boost::shared_ptr<void> > streams_;
+ std::list<boost::shared_ptr<tcp::acceptor> > acceptors_;
+
+ size_t num_streams(void) {
+ return streams_.size();
+ }
+
+ void close_stream(boost::shared_ptr<void> s) {
+ streams_.remove(s);
+ }
+
+ void shutdown(void) {
+ std::cout << "close acceptors..." << std::endl;
+ for (std::list<boost::shared_ptr<tcp::acceptor> >::iterator iter0 =
+ acceptors_.begin(); iter0 != acceptors_.end(); iter0++) {
+ (*iter0)->close(); //close acceptors
+ }
+ std::cout << "close streams..." << std::endl;
+ for (std::list<boost::shared_ptr<void> >::iterator iter =
+ streams_.begin(); iter != streams_.end(); iter++) {
+ iter->reset(); //delete streams and connections & interfaces
+ }
+ std::cout << "finish shutdown..." << std::endl;
+ }
+
+ asio_connector_async(boost::asio::io_service& io_service) :
+ io_service_(io_service) {
+ }
+ ~asio_connector_async() {
+ std::cout << "~asio_connector_async..." << std::endl;
+ }
+
+ //publish a local channel at specific port and accept remote conn
+ template<typename sock_conn_handler>
+ void async_accept(int port, sock_conn_handler hndl) {
+ boost::shared_ptr<conn_handler_base> handler(new conn_handler<
+ sock_conn_handler> (hndl));
+ tcp::endpoint endpoint(tcp::v4(), port);
+ boost::shared_ptr<tcp::acceptor> acceptor(new tcp::acceptor(
+ io_service_, endpoint));
+ acceptors_.push_back(acceptor);
+ boost::shared_ptr<tcp::socket> sock(new tcp::socket(io_service_));
+ acceptor->async_accept(*sock, boost::bind(
+ &asio_connector_async::handle_accept, this, acceptor, handler,
+ sock, boost::asio::placeholders::error));
+ }
+
+ void handle_accept(boost::shared_ptr<tcp::acceptor> acceptor,
+ boost::shared_ptr<conn_handler_base> handler, boost::shared_ptr<
+ tcp::socket> sock, const boost::system::error_code& error) {
+ if (!error) {
+ boost::shared_ptr<void> stream = handler->handle(this, sock, false);
+ streams_.push_back(stream);
+ boost::shared_ptr<tcp::socket> new_sock(
+ new tcp::socket(io_service_));
+ acceptor->async_accept(*new_sock, boost::bind(
+ &asio_connector_async::handle_accept, this, acceptor,
+ handler, new_sock, boost::asio::placeholders::error));
+ }
+ }
+
+ //asynchronously connect a local channel to a remote channel (at <host, port>)
+ template<typename sock_conn_handler>
+ void async_connect(std::string host, std::string port,
+ sock_conn_handler hndl) {
+ tcp::resolver resolver(io_service_);
+ tcp::resolver::query query(host, port);
+ tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+ tcp::endpoint endpoint = *endpoint_iterator;
+
+ boost::shared_ptr<tcp::socket> sock(new tcp::socket(io_service_));
+ boost::shared_ptr<conn_handler_base> handler(new conn_handler<
+ sock_conn_handler> (hndl));
+ sock->async_connect(endpoint, boost::bind(
+ &asio_connector_async::handle_connect, this, sock, handler,
+ boost::asio::placeholders::error, ++endpoint_iterator));
+ }
+
+ void handle_connect(boost::shared_ptr<tcp::socket> sock, boost::shared_ptr<
+ conn_handler_base> handler, const boost::system::error_code& error,
+ tcp::resolver::iterator endpoint_iterator) {
+ if (!error) {
+ boost::shared_ptr<void> stream = handler->handle(this, sock, true);
+ streams_.push_back(stream);
+ } else if (endpoint_iterator != tcp::resolver::iterator()) {
+ sock->close();
+ tcp::endpoint endpoint = *endpoint_iterator;
+ sock->async_connect(endpoint, boost::bind(
+ &asio_connector_async::handle_connect, this, sock, handler,
+ boost::asio::placeholders::error, ++endpoint_iterator));
+ }
+ }
+
+ //synchronously connect a local channel to a remote channel (at <host, port>)
+ template<typename sock_conn_handler>
+ void sync_connect(std::string host, std::string port,
+ sock_conn_handler hndl) {
+ tcp::resolver resolver(io_service_);
+ tcp::resolver::query query(host, port);
+ tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+ tcp::resolver::iterator end;
+
+ boost::shared_ptr<tcp::socket> sock(new tcp::socket(io_service_));
+ boost::system::error_code error = boost::asio::error::host_not_found;
+ while (error && endpoint_iterator != end) {
+ sock->close();
+ sock->connect(*endpoint_iterator++, error);
+ }
+ if (error)
+ throw error;
+
+ boost::shared_ptr<void> stream = hndl(this, sock, true);
+ streams_.push_back(stream);
+ }
+
+ private:
+ boost::asio::io_service& io_service_;
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/streams/asio_connector_sync.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/streams/asio_connector_sync.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,70 @@
+//
+// asio_connector_sync.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_CONNECTOR_SYNC_HPP
+#define ASIO_CONNECTOR_SYNC_HPP
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/asio.hpp>
+#include <boost/channel/streams/asio_stream_sync.hpp>
+
+using boost::asio::ip::tcp;
+
+namespace boost {
+ namespace channel {
+
+ class asio_connector_sync {
+ private:
+ boost::asio::io_service& io_service_;
+ public:
+ asio_connector_sync(boost::asio::io_service& io_service) :
+ io_service_(io_service) {
+ }
+
+ void shutdown(void) {
+ }
+
+ //synchronously connect a local channel to a remote channel (at <host, port>)
+ asio_stream_sync* connect(std::string host, std::string port) {
+ tcp::resolver resolver(io_service_);
+ tcp::resolver::query query(host, port);
+ tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+ tcp::resolver::iterator end;
+
+ asio_stream_sync *stream = new asio_stream_sync(io_service_, reg);
+ boost::asio::error error = boost::asio::error::host_not_found;
+ while (error && endpoint_iterator != end) {
+ stream->socket().close();
+ stream->socket().connect(*endpoint_iterator++,
+ boost::asio::assign_error(error));
+ }
+ if (error)
+ throw error;
+ stream->start();
+ return stream;
+ }
+
+ //synchronously accept:
+ //? how to continuously wait
+ //? how to wait on multi ports for multi channels
+ asio_stream_sync* accept(int port) {
+ tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
+ asio_stream_sync *stream = new asio_stream_sync(io_service_, reg);
+ a.accept(stream->socket());
+ stream->start();
+ return stream;
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/streams/asio_stream_async.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/streams/asio_stream_async.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,377 @@
+//
+// asio_stream_async.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_STREAM_ASYNC_HPP
+#define ASIO_STREAM_ASYNC_HPP
+
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <deque>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/function.hpp>
+#include <boost/asio.hpp>
+#include <boost/channel/peer.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/marshaler.hpp>
+#include <boost/channel/streams/asio_connector_async.hpp>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * asio_stream_async: a wrapper of socket, implement peer_type interface to be
+ * connected to channels
+ * msg serialization/deserialization is also done here: there are 2 parts:
+ * 1. serialization of ids: in id_trait files, for each id_type,
+ * a serialization function is defined
+ * 2. serialization of msg data: inside channel and among local peers, messages
+ * are passed by pointers; only when writing into and reading from
+ * external connections (such as sockets), serialization/deserialization
+ * is necessary. So all serialization is localized in "streams":
+ * diff ids could have diff msgs data structures, use
+ * marshaler_registry (a map or hash table to map
+ * ids to marshalers (the serialization functions)
+ */
+
+ void asio_stream_async_do_close(boost::shared_ptr<tcp::socket> sock) {
+ //close socket; called from io_service main thread
+ std::cout << "asio_stream_async_do_close enter" << std::endl;
+ sock->close();
+ std::cout << "asio_stream_async_do_close exit" << std::endl;
+ }
+
+ template<typename id_type, typename marshaler_registry>
+ class asio_stream_async: public peer_type<id_type> {
+ typedef peer_type<id_type> peer_type;
+ typedef message<id_type> msg_type;
+ typedef std::deque<msg_type> msg_que_type;
+
+ enum stream_state {
+ connecting, connected, disconnected
+ };
+
+ public:
+ asio_stream_async(asio_connector_async *conn, boost::shared_ptr<
+ boost::asio::ip::tcp::socket> sock, marshaler_registry &reg) :
+ socket_(sock), io_service_(sock->io_service()), mar_reg_(reg), conn_(
+ conn), state_(connected) {
+ }
+
+ ~asio_stream_async() {
+ std::cout << "asio_stream_async destructor enter..." << std::endl;
+ if (state_ == connected) {
+ state_ = disconnected;
+ peer_type::release();
+ io_service_.post(boost::bind(&asio_stream_async_do_close, socket_));
+ }
+ std::cout << "asio_stream_async destructor exit..." << std::endl;
+ }
+
+ //start reading from socket
+ void start() {
+ async_read(read_msg_, boost::bind(&asio_stream_async::handle_read,
+ this, boost::asio::placeholders::error));
+ }
+
+ //send a msg to socket and to remote peer
+ void send(id_type id, shared_ptr<void> msg) {
+ msg_type mdata(id, msg);
+ io_service_.post(boost::bind(&asio_stream_async::do_write, this, mdata));
+ }
+
+ std::pair<typename peer_type::type, std::string> get_info(void) {
+ std::pair<typename peer_type::type, std::string> info;
+ info.first = peer_type::remote_peer;
+ info.second = ""; //should get address info from sock_
+ return info;
+ }
+
+ void close() {
+ if (state_ == connected) {
+ state_ = disconnected;
+ peer_type::release();
+ io_service_.post(boost::bind(&asio_stream_async_do_close, socket_));
+ }
+ }
+
+ private:
+
+ void do_write(msg_type msg) {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress) {
+ async_write(write_msgs_.front(), boost::bind(
+ &asio_stream_async::handle_write, this,
+ boost::asio::placeholders::error));
+ }
+ }
+
+ template<typename handler_type>
+ void async_write(msg_type &m, handler_type handler) {
+ //marshal id
+ id_marshaler<id_type> *id_m = mar_reg_.get_id_marshaler();
+ id_m->marshal(m.id_, id_data_);
+ //marshal msg payload
+ msg_marshaler *m_m = mar_reg_.get_msg_marshaler(m.id_);
+ m_m->marshal(m.data_, msg_data_);
+ // format id length.
+ std::ostringstream id_len_stream;
+ id_len_stream << std::setw(size_length) << std::hex << id_data_.size();
+ if (!id_len_stream || id_len_stream.str().size() != size_length) {
+ // Something went wrong, inform the caller.
+ boost::system::error_code error(
+ boost::asio::error::invalid_argument);
+ io_service_.post(boost::bind(handler, error));
+ return;
+ }
+ id_len_ = id_len_stream.str();
+ // format msg length.
+ std::ostringstream msg_len_stream;
+ msg_len_stream << std::setw(size_length) << std::hex
+ << msg_data_.size();
+ if (!msg_len_stream || msg_len_stream.str().size() != size_length) {
+ // Something went wrong, inform the caller.
+ boost::system::error_code error(
+ boost::asio::error::invalid_argument);
+ io_service_.post(boost::bind(handler, error));
+ return;
+ }
+ msg_len_ = msg_len_stream.str();
+
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.push_back(boost::asio::buffer(id_len_));
+ buffers.push_back(boost::asio::buffer(id_data_));
+ buffers.push_back(boost::asio::buffer(msg_len_));
+ buffers.push_back(boost::asio::buffer(msg_data_));
+ boost::asio::async_write(*socket_, buffers, handler);
+ }
+
+ void handle_write(const boost::system::error_code& error) {
+ if (!error) {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty()) {
+ async_write(write_msgs_.front(), boost::bind(
+ &asio_stream_async::handle_write, this,
+ boost::asio::placeholders::error));
+ }
+ } else {
+ close();
+ //conn_->close_stream(boost::shared_ptr<void>(this));
+ }
+ }
+
+ template<typename handler_type>
+ void async_read(msg_type &read_msg, handler_type handler) {
+ // read id length header.
+ void (asio_stream_async::*f)(const boost::system::error_code&,
+ msg_type&, boost::tuple<handler_type>)
+ = &asio_stream_async::handle_read_id_len;
+ boost::asio::async_read(*socket_, boost::asio::buffer(inbound_header_),
+ boost::bind(f, this, boost::asio::placeholders::error,
+ boost::ref(read_msg), boost::make_tuple(handler)));
+ }
+
+ template<typename handler_type>
+ void handle_read_id_len(const boost::system::error_code& e, msg_type& t,
+ boost::tuple<handler_type> handler) {
+ if (e) {
+ boost::get<0>(handler)(e);
+ } else {
+ // Determine id length
+ std::istringstream is(std::string(inbound_header_, size_length));
+ std::size_t inbound_data_size = 0;
+ if (!(is >> std::hex >> inbound_data_size)) {
+ // Header doesn't seem to be valid. Inform the caller.
+ boost::system::error_code error(
+ boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+
+ // Start an asynchronous call to read id data.
+ inbound_data_.resize(inbound_data_size);
+ void (asio_stream_async::*f)(const boost::system::error_code&,
+ msg_type&, boost::tuple<handler_type>)
+ = &asio_stream_async::handle_read_id_data;
+ boost::asio::async_read(*socket_,
+ boost::asio::buffer(inbound_data_), boost::bind(f, this,
+ boost::asio::placeholders::error, boost::ref(t),
+ handler));
+ }
+ }
+
+ template<typename handler_type>
+ void handle_read_id_data(const boost::system::error_code& e, msg_type& t,
+ boost::tuple<handler_type> handler) {
+ if (e) {
+ boost::get<0>(handler)(e);
+ } else {
+ // Extract the data structure from the data just received.
+ try {
+ std::string archive_data(&inbound_data_[0],
+ inbound_data_.size());
+ id_marshaler<id_type> *id_m = mar_reg_.get_id_marshaler();
+ id_m->demarshal(archive_data, t.id_);
+ } catch (std::exception& e) {
+ // Unable to decode data.
+ boost::system::error_code error(
+ boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+
+ // read msg length header.
+ void (asio_stream_async::*f)(const boost::system::error_code&,
+ msg_type&, boost::tuple<handler_type>)
+ = &asio_stream_async::handle_read_msg_len;
+ boost::asio::async_read(*socket_, boost::asio::buffer(
+ inbound_header_), boost::bind(f, this,
+ boost::asio::placeholders::error, boost::ref(t), handler));
+
+ }
+ }
+
+ template<typename handler_type>
+ void handle_read_msg_len(const boost::system::error_code& e, msg_type& t,
+ boost::tuple<handler_type> handler) {
+ if (e) {
+ boost::get<0>(handler)(e);
+ } else {
+ // Determine id length
+ std::istringstream is(std::string(inbound_header_, size_length));
+ std::size_t inbound_data_size = 0;
+ if (!(is >> std::hex >> inbound_data_size)) {
+ // Header doesn't seem to be valid. Inform the caller.
+ boost::system::error_code error(
+ boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+
+ // Start an asynchronous call to read id data.
+ inbound_data_.resize(inbound_data_size);
+ void (asio_stream_async::*f)(const boost::system::error_code&,
+ msg_type&, boost::tuple<handler_type>)
+ = &asio_stream_async::handle_read_msg_data;
+ boost::asio::async_read(*socket_,
+ boost::asio::buffer(inbound_data_), boost::bind(f, this,
+ boost::asio::placeholders::error, boost::ref(t),
+ handler));
+ }
+ }
+
+ template<typename handler_type>
+ void handle_read_msg_data(const boost::system::error_code& e, msg_type& t,
+ boost::tuple<handler_type> handler) {
+ if (e) {
+ boost::get<0>(handler)(e);
+ } else {
+ // Extract the data structure from the data just received.
+ try {
+ std::string archive_data(&inbound_data_[0],
+ inbound_data_.size());
+ msg_marshaler *m_m = mar_reg_.get_msg_marshaler(t.id_);
+ m_m->demarshal(archive_data, t.data_);
+ } catch (std::exception& e) {
+ // Unable to decode data.
+ boost::system::error_code error(
+ boost::asio::error::invalid_argument);
+ boost::get<0>(handler)(error);
+ return;
+ }
+
+ // Inform caller that data has been received ok.
+ boost::get<0>(handler)(e);
+ }
+ }
+
+ //finish reading a complete msg, forward to peer and read next one
+ void handle_read(const boost::system::error_code& error) {
+ if (!error) {
+ peer_send(read_msg_.id_, read_msg_.data_);
+ async_read(read_msg_, boost::bind(&asio_stream_async::handle_read,
+ this, boost::asio::placeholders::error));
+ } else {
+ close();
+ //conn_->close_stream(boost::shared_ptr<void>(this));
+ }
+ }
+
+ /*
+ void do_close(boost::shared_ptr<tcp::socket> sock)
+ {
+ //close socket; called from io_service main thread
+ sock->close();
+ std::cout << "do_close called" << std::endl;
+ }
+ */
+
+ boost::shared_ptr<boost::asio::ip::tcp::socket> socket(void) {
+ return socket_;
+ }
+
+ private:
+ enum sz_len {
+ size_length = 8
+ };
+ boost::shared_ptr<boost::asio::ip::tcp::socket> socket_;
+ boost::asio::io_service& io_service_;
+ marshaler_registry &mar_reg_;
+ asio_connector_async *conn_;
+ stream_state state_;
+
+ //output data buffers
+ msg_que_type write_msgs_;
+ std::string id_len_;
+ std::string id_data_;
+ std::string msg_len_;
+ std::string msg_data_;
+
+ //input data buffers
+ char inbound_header_[size_length];
+ std::vector<char> inbound_data_;
+ msg_type read_msg_;
+ };
+
+ template<typename channel, typename marshaler_registry>
+ struct asio_bind_sock_chan {
+ typedef boost::shared_ptr<void> result_type;
+ typename channel::binder_type *binder_;
+ typedef boost::function1<typename channel::binder_type *,
+ boost::shared_ptr<tcp::socket> > call_back_t;
+ call_back_t binder_gen_;
+
+ asio_bind_sock_chan(call_back_t cb = 0) :
+ binder_(NULL), binder_gen_(cb) {
+ }
+ boost::shared_ptr<void> operator()(channel &chan, marshaler_registry &reg,
+ asio_connector_async *conn, boost::shared_ptr<tcp::socket> sock,
+ bool active) {
+ typedef typename channel::id_type id_type;
+ typedef asio_stream_async<id_type, marshaler_registry> asio_stream;
+ asio_stream *stream = new asio_stream(conn, sock, reg);
+ if (binder_gen_)
+ binder_ = binder_gen_(sock);
+ //should connect first, so that when stream starts(reading),
+ //peer channel is already connected and ready to forward msgs
+ connect(chan, stream, active,binder_);
+ stream->start(); //start reading from sock
+ return boost::shared_ptr<void>(stream);
+ }
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/streams/asio_stream_sync.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/streams/asio_stream_sync.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,213 @@
+//
+// asio_stream_sync.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ASIO_STREAM_SYNC_HPP
+#define ASIO_STREAM_SYNC_HPP
+
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/channel/peer.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/marshaler.hpp>
+
+namespace boost {
+ namespace channel {
+
+ template<typename id_type, typename marshaler_registry>
+ class asio_stream_sync: public peer_type<id_type> {
+ typedef peer_type<id_type> peer_type;
+ typedef message<id_type> msg_type;
+
+ enum {
+ wait_time = 2
+ };
+
+ enum thr_state {
+ thr_running, thr_stopped
+ };
+
+ private:
+ enum sz_len {
+ size_length = 8
+ };
+ boost::asio::ip::tcp::socket socket_;
+ boost::asio::io_service& io_service_;
+ marshaler_registry &mar_reg_;
+ boost::thread *thr_;
+ thr_state thr_st_;
+
+ //output data buffers
+ std::string id_len_;
+ std::string id_data_;
+ std::string msg_len_;
+ std::string msg_data_;
+
+ //input data buffers
+ char inbound_header_[size_length];
+ std::vector<char> inbound_data_;
+ msg_type read_msg_;
+
+ public:
+ asio_stream_sync(boost::asio::io_service& io, marshaler_registry &reg) :
+ socket_(io), io_service_(io), mar_reg_(reg) {
+ }
+
+ boost::asio::ip::tcp::socket& socket() {
+ return socket_;
+ }
+
+ //start reading from socket
+ void start() {
+ //spawn a thread reading msgs from socket and forward them to local channel
+ thr_st_ = thr_running;
+ thr_ = new thread(boost::bind(&asio_stream_sync::recv, this));
+ }
+
+ //send a msg to socket and to remote peer
+ void send(id_type id, shared_ptr<void> msg) {
+ try {
+ //marshal id
+ id_marshaler<id_type> *id_m = mar_reg_.get_id_marshaler();
+ id_m->marshal(id, id_data_);
+ //marshal msg payload
+ msg_marshaler *m_m = mar_reg_.get_msg_marshaler(id);
+ m_m->marshal(msg, msg_data_);
+ // format id length.
+ std::ostringstream id_len_stream;
+ id_len_stream << std::setw(size_length) << std::hex
+ << id_data_.size();
+ if (!id_len_stream || id_len_stream.str().size() != size_length) {
+ // Something went wrong
+ boost::system::error_code err(
+ boost::asio::error::invalid_argument);
+ boost::system::system_error e(err);
+ boost::throw_exception(e);
+ }
+ id_len_ = id_len_stream.str();
+ // format msg length.
+ std::ostringstream msg_len_stream;
+ msg_len_stream << std::setw(size_length) << std::hex
+ << msg_data_.size();
+ if (!msg_len_stream || msg_len_stream.str().size() != size_length) {
+ // Something went wrong
+ boost::system::error_code err(
+ boost::asio::error::invalid_argument);
+ boost::system::system_error e(err);
+ boost::throw_exception(e);
+ }
+ msg_len_ = msg_len_stream.str();
+
+ std::vector<boost::asio::const_buffer> buffers;
+ buffers.push_back(boost::asio::buffer(id_len_));
+ buffers.push_back(boost::asio::buffer(id_data_));
+ buffers.push_back(boost::asio::buffer(msg_len_));
+ buffers.push_back(boost::asio::buffer(msg_data_));
+ boost::asio::write(socket_, buffers);
+ } catch (boost::system::error_code& e) {
+ std::cerr << e << "\n";
+ shutdown_wait();
+ } catch (std::exception& e) {
+ std::cerr << "Exception: " << e.what() << "\n";
+ shutdown_wait();
+ }
+ }
+
+ void recv(void) {
+ std::cerr << "recver thread active...\n";
+ try {
+ while (thr_st_ == thr_running) {
+ //--- read id ---
+ //1. read id len
+ boost::asio::read(socket_, boost::asio::buffer(inbound_header_));
+ std::istringstream
+ is(std::string(inbound_header_, size_length));
+ std::size_t inbound_data_size = 0;
+ if (!(is >> std::hex >> inbound_data_size)) {
+ // invalid id len
+ boost::system::error_code err(
+ boost::asio::error::invalid_argument);
+ boost::system::system_error e(err);
+ boost::throw_exception(e);
+ }
+ inbound_data_.resize(inbound_data_size);
+ //2. read id data
+ boost::asio::read(socket_, boost::asio::buffer(inbound_data_));
+ std::string archive_data(&inbound_data_[0],
+ inbound_data_.size());
+ id_marshaler<id_type> *id_m = mar_reg_.get_id_marshaler();
+ id_m->demarshal(archive_data, read_msg_.id_);
+ //--- read msg ---
+ //3. read msg len
+ boost::asio::read(socket_, boost::asio::buffer(inbound_header_));
+ std::istringstream
+ is(std::string(inbound_header_, size_length));
+ std::size_t inbound_data_size = 0;
+ if (!(is >> std::hex >> inbound_data_size)) {
+ // invalid msg len
+ boost::system::error_code err(
+ boost::asio::error::invalid_argument);
+ boost::system::system_error e(err);
+ boost::throw_exception(e);
+ }
+ inbound_data_.resize(inbound_data_size);
+ //4. read msg data
+ boost::asio::read(socket_, boost::asio::buffer(inbound_data_));
+ std::string archive_data(&inbound_data_[0],
+ inbound_data_.size());
+ msg_marshaler *m_m = mar_reg_.get_msg_marshaler(t.id_);
+ m_m->demarshal(archive_data, read_msg_.data_);
+
+ //5. forward to local channel
+ peer_send(read_msg_.id_, read_msg_.data_);
+ }
+ } catch (boost::system::error_code& e) {
+ std::cerr << e << "\n";
+ shutdown_wait();
+ } catch (std::exception& e) {
+ std::cerr << "Exception: " << e.what() << "\n";
+ shutdown_wait();
+ }
+
+ std::cerr << "recver thread exit...\n";
+ }
+
+ void shutdown_wait() {
+ if (thr_st_ == thr_running) {
+ //close socket
+ close();
+ }
+ thr_->join();
+ peer_type::release();
+ }
+
+ std::pair<typename peer_type::type, std::string> get_info(void) {
+ std::pair<typename peer_type::type, std::string> info;
+ info.first = peer_type::remote_peer;
+ info.second = ""; //should get address info from sock_
+ return info;
+ }
+
+ void close(void) {
+ //close socket
+ socket_->close();
+ }
+
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/boost/channel/streams/shmem_stream.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/streams/shmem_stream.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,181 @@
+//
+// shmem_stream.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef SHMEM_STREAM_HPP
+#define SHMEM_STREAM_HPP
+
+#include <iomanip>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <deque>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/interprocess/ipc/message_queue.hpp>
+#include <boost/channel/peer.hpp>
+#include <boost/channel/message.hpp>
+#include <boost/channel/marshaler.hpp>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * shmem_stream : a stream based on boost::interprocess shmem message queue
+ * contains a internal thread reading from shmem msg_que and forward to peer
+ */
+ template<typename id_type, typename marshaler_registry>
+ class shmem_stream: public peer_type<id_type> {
+ typedef peer_type<id_type> peer_type;
+ typedef message<id_type> msg_type;
+
+ enum {
+ wait_time = 2
+ };
+
+ enum q_f {
+ quit_flag = 0
+ };
+
+ enum thr_state {
+ thr_running, thr_stopped
+ };
+
+ public:
+ shmem_stream(bool active, const char *name, std::size_t max_num_msg,
+ std::size_t max_msg_size, marshaler_registry &reg) :
+ active_role_(active), q_name_(name), mar_reg_(reg) {
+ if (active) {
+ //active side create msg que in shared mem
+ send_q_name_ = q_name_ + "_a_2_p"; //active_to_passive
+ recv_q_name_ = q_name_ + "_p_2_a"; //passive_to_active
+ boost::interprocess::message_queue::remove(send_q_name_.c_str());
+ boost::interprocess::message_queue::remove(recv_q_name_.c_str());
+ std::cout << "Create mq: " << send_q_name_.c_str() << "\n";
+ std::cout << "Create mq: " << recv_q_name_.c_str() << "\n";
+ send_mq_ = new boost::interprocess::message_queue(
+ boost::interprocess::create_only, send_q_name_.c_str(),
+ max_num_msg, max_msg_size);
+ recv_mq_ = new boost::interprocess::message_queue(
+ boost::interprocess::create_only, recv_q_name_.c_str(),
+ max_num_msg, max_msg_size);
+ } else {
+ //passive side open only
+ send_q_name_ = q_name_ + "_p_2_a"; //active_to_passive
+ recv_q_name_ = q_name_ + "_a_2_p"; //passive_to_active
+ send_mq_ = new boost::interprocess::message_queue(
+ boost::interprocess::open_only, send_q_name_.c_str());
+ recv_mq_ = new boost::interprocess::message_queue(
+ boost::interprocess::open_only, recv_q_name_.c_str());
+ }
+ //spawn a thread reading msgs from msg_que and forward them to peer
+ thr_st_ = thr_running;
+ thr_ = new thread(boost::bind(&shmem_stream::recv, this));
+ }
+
+ ~shmem_stream() {
+ //shutdown thread properly
+ if (thr_st_ == thr_running)
+ shutdown_wait();
+ delete thr_;
+ delete send_mq_;
+ delete recv_mq_;
+ if (active_role_) {
+ boost::interprocess::message_queue::remove(send_q_name_.c_str());
+ boost::interprocess::message_queue::remove(recv_q_name_.c_str());
+ }
+ }
+
+ //send a msg to shmem msg_que and to remote peer
+ void send(id_type id, shared_ptr<void> msg) {
+ id_marshaler<id_type> *id_m = mar_reg_.get_id_marshaler();
+ id_m->marshal(id, id_data_);
+ msg_marshaler *m_m = mar_reg_.get_msg_marshaler(id);
+ m_m->marshal(msg, out_msg_data_);
+ int id_sz = id_data_.size();
+ int msg_sz = out_msg_data_.size();
+ //msg que internal already has lock protection
+ send_mq_->send(id_data_.c_str(), id_sz, 0);
+ send_mq_->send(out_msg_data_.c_str(), msg_sz, 0);
+ std::cerr << "send one msg...\n";
+ }
+
+ void recv(void) {
+ std::cerr << "shmem msg_que recver thread active...\n";
+ size_t recv_sz;
+ unsigned int pri;
+ //have to be max_msg_sz of msg_que; otherwise exception is thrown
+ size_t buf_sz = recv_mq_->get_max_msg_size();
+ boost::shared_ptr<char> buf(new char[buf_sz]);
+ while (thr_st_ == thr_running) {
+ recv_mq_->receive(buf.get(), buf_sz, recv_sz, pri);
+ if (recv_sz == sizeof(size_t) && *((size_t*) buf.get())
+ == quit_flag) {
+ thr_st_ = thr_stopped;
+ break;
+ }
+ std::string id_data(buf.get(), recv_sz);
+ id_marshaler<id_type> *id_m = mar_reg_.get_id_marshaler();
+ id_m->demarshal(id_data, read_msg_.id_);
+ recv_mq_->receive(buf.get(), buf_sz, recv_sz, pri);
+ if (recv_sz == sizeof(size_t) && *((size_t*) buf.get())
+ == quit_flag) {
+ thr_st_ = thr_stopped;
+ break;
+ }
+ std::string msg_data(buf.get(), recv_sz);
+ msg_marshaler *m_m = mar_reg_.get_msg_marshaler(read_msg_.id_);
+ m_m->demarshal(msg_data, read_msg_.data_);
+ peer_send(read_msg_.id_, read_msg_.data_);
+ }
+ std::cerr << "shmem msg_que recver thread exit...\n";
+ }
+
+ std::pair<typename peer_type::type, std::string> get_info(void) {
+ std::pair<typename peer_type::type, std::string> info;
+ info.first = peer_type::remote_peer;
+ info.second = q_name_; //should get address info from sock_
+ return info;
+ }
+
+ void shutdown_wait() {
+ size_t quit_msg = quit_flag;
+ if (thr_st_ == thr_running) {
+ //msg que internal already has lock protection
+ recv_mq_->send(&quit_msg, sizeof(quit_msg), 0);
+ }
+ thr_->join();
+ peer_type::release();
+ }
+
+ private:
+ bool active_role_;
+ std::string q_name_;
+ std::string send_q_name_;
+ std::string recv_q_name_;
+ boost::interprocess::message_queue *send_mq_;
+ boost::interprocess::message_queue *recv_mq_;
+ marshaler_registry &mar_reg_;
+ boost::thread *thr_;
+ thr_state thr_st_;
+
+ //output data buffers
+ std::string id_data_;
+ std::string out_msg_data_;
+
+ //input data buffers
+ std::vector<char> msg_data_;
+ msg_type read_msg_;
+ };
+
+ }
+}
+
+#endif
+

Added: sandbox/channel/boost/channel/unnamed_in_out.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/boost/channel/unnamed_in_out.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,106 @@
+//
+// unnamed_in_out.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef UNNAMED_IN_OUT_HPP
+#define UNNAMED_IN_OUT_HPP
+
+#include <list>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+#include <boost/channel/name_spaces/null_name_space.hpp>
+#include <boost/channel/dispatchers/arbiters_async.hpp>
+#include <boost/channel/dispatchers/arbiters_sync.hpp>
+#include <boost/channel/dispatchers/broadcast_dispatcher.hpp>
+#include <boost/channel/dispatchers/round_robin_dispatcher.hpp>
+#include <boost/channel/dispatchers/always_latest_dispatcher.hpp>
+#include <boost/channel/dispatchers/pull_dispatcher.hpp>
+
+namespace boost {
+ namespace channel {
+
+ /**
+ * port class: "unnamed" named_out with pull_dispatcher
+ * same role as port in CCR and channel in C++CSP or JCSP
+ */
+ template<
+ typename executor_type = abstract_executor, //force in-line execution
+ typename idtype = null_id,
+ typename platform_type = boost_platform,
+ typename synchpolicy = mt_synch<platform_type> ,
+ typename name_space = null_name_space<idtype, executor_type, synchpolicy> ,
+ typename pulldispatcher = pull_dispatcher<name_space, platform_type>
+ >
+ class port: public named_out<name_space, typename pulldispatcher::sender> {
+ public:
+ typedef typename pulldispatcher::choice_async choice_async;
+ typedef typename pulldispatcher::join_async join_async;
+ typedef typename pulldispatcher::choice_sync choice_sync;
+ typedef typename pulldispatcher::join_sync join_sync;
+ typedef named_out<name_space, typename pulldispatcher::sender> named_out_type;
+ typedef named_in<name_space, typename pulldispatcher::recver> named_in_type;
+ port(executor_type *e=NULL) : named_out_type(e) {}
+ };
+
+ /**
+ * signal and slot: for synch event dispatching
+ * signal : "unnamed" named_out with push_dispatchers
+ * when signal(named_out) is destroyed, all its remaining slots(named_ins) are unbound;
+ * their num_bindings() should return 0
+ * when slots(named_in) are destroyed, they are unbound from named_in automatically
+ */
+ template <
+ typename executor_type = abstract_executor, //force in-line execution
+ typename idtype = null_id,
+ typename platform_type = boost_platform,
+ typename synchpolicy = mt_synch<platform_type>,
+ typename name_space = null_name_space<idtype,executor_type,synchpolicy>,
+ typename push_dispatcher = broadcast_dispatcher<name_space,platform_type>
+ >
+ class signal : public named_out<name_space, typename push_dispatcher::sender> {
+ public:
+ typedef named_in<name_space, typename push_dispatcher::recver> slot;
+ typedef named_out<name_space, typename push_dispatcher::sender> named_out_type;
+ typedef name<idtype, executor_type, synchpolicy> name_type;
+ typedef typename name_type::binding_set_type binding_set_type;
+
+ executor_type *exec_;
+ signal(executor_type *e=NULL) : named_out_type(e), exec_(e) {}
+ ~signal() {
+ //signal should be the last to kill after all slots cleanup. do some cleanup ?
+ binding_set_type & bindings0 = ((name_type*) this)->bindings_;
+ //here something wrong with list::iterator!? so copy to a vector
+ std::vector<name_type *> bindings(bindings0.begin(), bindings0.end());
+ typename std::vector<name_type *>::iterator iter;
+ for(iter = bindings.begin(); iter != bindings.end(); iter++) {
+ delete ((slot *) (*iter));
+ }
+ }
+
+ template <typename recver_type>
+ slot * bind(recver_type rc) {
+ slot * ss = new slot(boost::bind(rc, _2), exec_);
+ ((name_type *)this)->bind((name_type *)ss);
+ ((name_type *)ss)->bind((name_type *)this);
+ return ss;
+ }
+
+ //when slots are destroyed, they unbind from signals automatically
+ //here is for the case when we just want unbind, not destroy
+ void unbind(slot *ss) {
+ ((name_type *)this)->unbind((name_type *)ss);
+ ((name_type *)ss)->unbind((name_type *)this);
+ }
+
+ };
+}
+}
+
+#endif
+

Added: sandbox/channel/libs/channel/build/Jamfile
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/build/Jamfile 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,67 @@
+# Boost.Channel Library
+
+# Copyright Yigong Liu 2005-2007. Use, modification and
+# distribution is subject to the Boost Software License, Version
+# 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+# For more information, see http://www.boost.org
+
+# declare the location of this subproject relative to the root
+subproject libs/channel/build ;
+
+#
+# this template defines the options common to
+# all channel builds and tests:
+#
+template channel-options
+ : # sources
+ : # requirements
+ <define>BOOST_ALL_NO_LIB=1
+ <define>BOOST_CHANNEL_NO_LIB=1
+ <sysinclude>$(BOOST_ROOT)
+ ;
+
+#
+# this template defines the options common to
+# all channel dll builds and tests:
+#
+template channel-dll-options
+ : <template>channel-options # sources
+ <lib>@boost/libs/regex/build/boost_regex
+ : # requirements
+ <define>BOOST_ALL_NO_LIB=1
+ <define>BOOST_CHANNEL_DYN_LINK=1
+ <runtime-link>dynamic
+ ;
+
+SOURCES = name linear_id_trait hierarchical_id_trait assoc_id_trait ;
+
+lib boost_channel : ../src/$(SOURCES).cpp <template>channel-options
+ :
+ [ common-names ]
+ :
+ debug release
+ ;
+
+
+dll boost_channel : ../src/$(SOURCES).cpp <template>channel-dll-options
+ :
+ [ common-names ]
+ :
+ debug release
+ ;
+
+stage stage/lib : <lib>boost_channel <dll>boost_channel
+ :
+ <locate>$(BOOST_ROOT)
+ [ common-names ]
+ <target>stage
+ <target>all
+ :
+ debug release
+ ;
+
+install channel lib
+ : <dll>boost_channel <lib>boost_channel
+ ;

Added: sandbox/channel/libs/channel/build/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/build/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,30 @@
+##//////////////////////////////////////////////////////////////////////////////
+##// Copyright (c) 2005, 2007 Yigong Liu
+##// Permission to use, copy, modify, distribute and sell this software for any
+##// purpose is hereby granted without fee, provided that the above copyright
+##// notice appear in all copies and that both that copyright notice and this
+##// permission notice appear in supporting documentation.
+##// The author makes no representations about the
+##// suitability of this software for any purpose. It is provided "as is"
+##// without express or implied warranty.
+##////////////////////////////////////////////////////////////////////////////////
+# Copyright Douglas Gregor 2001-2003. Use, modification and
+# distribution is subject to the Boost Software License, Version
+# 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+project boost/channel
+ : requirements
+ <library>/boost/regex//boost_regex
+ <define>BOOST_ALL_NO_LIB=1
+ : source-location ../src
+ ;
+
+# Base names of the source files for libboost_signals
+SOURCES = name linear_id_trait hierarchical_id_trait assoc_id_trait ;
+
+lib boost_channel : $(SOURCES).cpp
+ :
+ <define>BOOST_CHANNEL_NO_LIB=1
+ <link>shared:<define>BOOST_CHANNEL_DYN_LINK=1
+ ;

Added: sandbox/channel/libs/channel/doc/assoc_id_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/doc/assoc_id_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,380 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>assoc_id_text.html</title>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Design of Associative Name Space, Id and Id_Trait</h2>
+<br>
+There are 2 stimulis for the design of associative name space:<br>
+<ul>
+ <li>Control flow branching based on pattern matching. <br>
+ </li>
+</ul>
+<div style="margin-left: 40px;">Many shells (e.g. rc, bash) support the
+following control flow structure:<br>
+</div>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; case <span
+ style="font-style: italic; font-weight: bold;">expression</span> in<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; <span
+ style="font-weight: bold; font-style: italic;">pattern1</span> )<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; &nbsp;&nbsp; statements ;;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; <span
+ style="font-weight: bold; font-style: italic;">pattern2</span> )<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; &nbsp;&nbsp; statements ;;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+......<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; esac<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; In shells, patterns are
+created by using wildcard characters (*,?...). Ruby provides a stronger
+"case" structure using regex to define patterns.<br>
+<ul>
+ <li>Linda Tuple Space. <br>
+ </li>
+</ul>
+<div style="margin-left: 40px;">In a brief summary, in a Linda system,
+distributed processes communicate thru shared associative "address
+space" - tuple space which consist of tuples. Each tuple consists of
+fields. Tuples are written
+("out") to tuple space, read and taken ("in", "read") from tuple space.
+Tuples are identified thru associative
+lookup: two tuples match if all their corresponding fields match while
+two fields match if they are of the same type and either of the same
+value or one of them is wildcard.<br>
+<br>
+</div>
+<div style="text-align: left;">Channel supports message passing and
+name-matching based on regex pattern matching and Linda associative
+lookup. Regex name-matching is implemented using Boost.Regex and the
+code is relative straightforward. Please refer to <a
+ href="sample9_text.html">sample 9</a>
+for the usage of regex based name-matching. Here we focus on the <a
+ href="../../../boost/channel/name_spaces/assoc_id_trait.hpp">detailed
+implemenation</a> of names-matching
+using Linda lookup. Please refer to <a href="sample10_text.html">sample
+10</a> for the usage of associative lookup based name-matching.<br>
+<br>
+In Linda style associative name space, a message names/ids is "a
+tuple" consisting of a set of fields. We use Boost.Tuple&nbsp; for
+defining these ids and names. To support associative lookup, we define
+field_trait template classes for each data type of the tuple fields.
+Each field_trait class will define wildcard and match operation for its
+data type. The following is a sample:<br>
+<div style="margin-left: 40px; background-color: rgb(255, 255, 255);"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+template &lt;&gt;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+class
+BOOST_CHANNEL_DECL field_trait&lt;int&gt; {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+public:</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef int field_type;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static int wildcard;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool wildcard_field(int f) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if (f == wildcard) </span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp; return true;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return false;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool match(int f1, int f2) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if (f1 == wildcard || f2 == wildcard)</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp; return true;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return f1 == f2;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+};</span><br>
+</div>
+In assoc_id_trait.hpp, we define the field_trait template classes for
+all the primitive data types. If user defined types (classes or
+structs) are to be used as tuple field type, user code should provide
+field_trait classes for these types.<br>
+<br>
+We define the following template class as associative name space id:<br>
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+template &lt;typename Tuple_Type&gt;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+class tuple_id {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; ......<br>
+&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);">We need define copy constructor and
+standard relational operators for tuple_id to work with std::map
+container.</span><br style="color: rgb(153, 0, 0);">
+</span><span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; tuple_id(const tuple_id &amp;id) : type_(id.type_),
+tuple_(id.tuple_) {}</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; bool operator&lt; (const tuple_id &amp;id) const {......}</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; bool operator== (const tuple_id &amp;id) const
+{......}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; bool operator!= (const tuple_id &amp;id) const
+{......}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; ......<br>
+&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);">Then we define serialize() method to
+marshal/demarshal tuple_id using Boost.Serialization</span><br
+ style="color: rgb(153, 0, 0);">
+</span><span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; template&lt;class Archive&gt;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; void serialize(Archive &amp; ar, const unsigned int
+version) {......}</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+};<br>
+<br>
+</span><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);">Next, we define id_trait class for
+tuple_id:<br>
+<br>
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+template&lt;typename Tuple_Type&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+class BOOST_CHANNEL_DECL id_trait&lt;tuple_id&lt;Tuple_Type&gt; &gt; {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+public:</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+&nbsp;&nbsp;&nbsp; we define some associated types.<br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef Tuple_Type tuple_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef tuple_id&lt;tuple_type&gt; id_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+&nbsp;&nbsp;&nbsp; and define system internal messages<br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);"></span><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type channel_conn_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type channel_disconn_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type init_subscription_info_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type connection_ready_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type subscription_info_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type unsubscription_info_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type publication_info_msg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static id_type unpublication_info_msg;<br>
+&nbsp;&nbsp;&nbsp; </span><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);">Since internally Boost.Tuple is
+represented as recursive cons list, the following match operation is
+defined as recursive methods:</span></span><span
+ style="color: rgb(153, 0, 0); font-style: italic;"><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static bool match_tuple(const
+boost::tuples::null_type&amp;, const boost::tuples::null_type&amp;)</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;"></span><span
+ style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return true;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename H, typename T&gt;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool match_tuple(const boost::tuples::cons&lt;H,T&gt; &amp;t1,
+const boost::tuples::cons&lt;H,T&gt; &amp;t2)</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if(!field_trait&lt;H&gt;::match(t1.get_head(),
+t2.get_head()))</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return match_tuple(t1.get_tail(), t2.get_tail());</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br>
+<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);"></span><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool match(id_type id1, id_type id2)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{ </span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if (id1.type_ != id2.type_)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; return false;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if (id1.type_ == id_type::app_type) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; if (wildcard_tuple(id1.tuple_) &amp;&amp;
+wildcard_tuple(id2.tuple_) &amp;&amp; (id1.tuple_ != id2.tuple_))</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return false;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; if (id1.tuple_ == id2.tuple_)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return true;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; return match_tuple(id1.tuple_, id2.tuple_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return true;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+Similarly, we define recursive methods to find if a tuple_id contains
+wildcard:<span style="font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool wildcard_tuple(const boost::tuples::null_type&amp;)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return false;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename H, typename T&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool wildcard_tuple(const boost::tuples::cons&lt;H,T&gt; &amp;t1)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+{</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+if(field_trait&lt;H&gt;::wildcard_field(t1.get_head()))</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; return true;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return wildcard_tuple(t1.get_tail());</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static bool wildcard_name(const id_type &amp;id) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if (id.type_ != id_type::app_type)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; return false;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return wildcard_tuple(id.tuple_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+Finally we define a method to display id content as string for
+debugging purpose:<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+static std::string id_to_string(const id_type &amp;id) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; std::ostringstream os;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; os &lt;&lt; "tuple_id : type[" &lt;&lt; id.type_
+&lt;&lt; "] tuple[" &lt;&lt; id.tuple_ &lt;&lt; "]";</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return os.str();</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+};</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<br>
+Since the type of tuple (how many fields and what fields types) are
+decided by application code of Channel and can be different for
+different applications, the pre-defined system internal messages can
+only be defined thru the following macro. Application code should
+include this macro somewhere so that its system internal messages are
+defined:<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">#define
+DEFINE_ASSOC_SYS_IDS( tuple_type ) \</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">template
+&lt;&gt; boost::channel::tuple_id&lt;tuple_type&gt;
+boost::channel::id_trait&lt;boost::channel::tuple_id&lt;tuple_type&gt;
+&gt;::channel_conn_msg(boost::channel::tuple_id&lt;tuple_type&gt;::channel_conn_type);
+\<br>
+......<br style="font-style: italic; color: rgb(153, 0, 0);">
+</span><span style="font-style: italic; color: rgb(153, 0, 0);"></span><span
+ style="font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<br>
+</span></span><span style="color: rgb(153, 0, 0); font-style: italic;"></span></div>
+</body>
+</html>

Added: sandbox/channel/libs/channel/doc/design.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/doc/design.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,1865 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body>
+<h2 style="text-align: center;">Channel - A Name Space Based C++
+Framework For Asynchronous Distributed Message Passing and Event
+Dispatching</h2>
+<h2 style="text-align: center;">Yigong Liu (9/24/2006)</h2>
+<hr style="width: 100%; height: 2px;">
+<ul id="mozToc">
+<!--mozToc h3 1 h4 2--><li>1. Introduction</li>
+ <li>2. Build</li>
+ <li>3. Tutorials
+ <ul>
+ <li>3.1 gui event handling</li>
+ <li><a href="#mozTocId147115">3.2 gui event handling with 2 local
+channels</a></li>
+ <li>3.3 distributed gui events</li>
+ <li>3.4 chat with direct connection</li>
+ <li><a href="#mozTocId680978">3.5 buffered channel with blocking
+active receiver (synchronous choice, join synchronization patterns)</a></li>
+ <li><a href="#mozTocId232384">3.6 buffered channel with async
+receivers (asynchronous choice, join synchronization patterns)</a></li>
+ <li><a href="#mozTocId836556">3.7 distributed chat thru a
+central server</a></li>
+ <li><a href="#mozTocId266315">3.8 channel
+connection thru shared memory</a></li>
+ <li><a href="#mozTocId300223">3.9 channel using regex name
+matching </a></li>
+ <li><a href="#mozTocId440147">3.10 channel using Linda-style
+associative lookup</a></li>
+ <li><a href="#mozTocId505601">3.11 channel name space management
+and security with filters
+and translators</a></li>
+ <li><a href="#sample_dispatcher">3.12 port and signal: unnamed
+point of tightly-coupled local interactions</a><br>
+ </li>
+ </ul>
+ </li>
+ <li>4. Design
+ <ul>
+ <li><a href="#mozTocId135917">4.0 Overall Design
+Idea</a></li>
+ <li>4.1 Name space</li>
+ <ul>
+ <li>4.1.1 What's in a name?</li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId582741">4.1.2 Types of
+name space</a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId182536">4.1.3 Name binding
+set and Name matching
+algorithm, binding rules </a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId891206">4.1.4 Name spaces
+merge and connections </a></li>
+ </ul>
+ <li>4.2 Dispatching</li>
+ <ul>
+ <li><a href="#mozTocId862080">4.2.1 How message
+data move: push/pull, buffering</a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId629360">4.2.2 How operations
+are performed: synchronous/asynchronous</a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId248159">4.2.3 Message passing
+coordination
+patterns </a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId995030">4.2.4 Messages
+handling</a></li>
+ </ul>
+ <li>4.3 Connection related</li>
+ <ul>
+ <li>4.3.1 Connections</li>
+ </ul>
+ <ul>
+ <li>4.3.2 Peer</li>
+ </ul>
+ <li><a href="#unnamed_design">4.4 "Unnamed" binding of
+output/input or points of tightly-coupled
+local
+interactions</a></li>
+ <li><a href="#mozTocId970853">4.5 Application
+architecture and integration</a></li>
+ </ul>
+ </li>
+ <li>5. Classes
+ <ul>
+ <li>5.1 name space related</li>
+ <ul>
+ <li>5.1.1 name spaces</li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId828224"> 5.1.2 id_type and
+id_trait </a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId856863">5.1.3 name and name
+binding callback</a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId915384">5.1.4 named_out and
+named_in; publisher and subscriber</a></li>
+ <li><a href="#unnamed_class">5.1.5 unnamed in/out: port and
+signal/slot</a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId750531">5.1.6
+binder, filter and translator</a></li>
+ </ul>
+ <li><a href="#mozTocId985604">5.2 dispatching
+related</a></li>
+ <ul>
+ <li>5.2.1 dispatchers</li>
+ </ul>
+ <ul>
+ <li>5.2.2 messages</li>
+ </ul>
+ <ul>
+ <li>5.2.3 queues</li>
+ </ul>
+ <ul>
+ <li>5.2.4 executors </li>
+ </ul>
+ <li>5.3 connection related</li>
+ <ul>
+ <li><a href="#mozTocId460401">5.3.1&nbsp; global
+functions for connecting channels </a></li>
+ </ul>
+ <ul>
+ <li>5.3.2 connection</li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId581357">5.3.3 peer and
+interface</a></li>
+ </ul>
+ <ul>
+ <li>5.3.4 streams</li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId711260">5.3.5 marshaling
+registry</a></li>
+ </ul>
+ <li><a href="#mozTocId128213">5.4 platform
+abstraction policy and synchronization policy </a></li>
+ <ul>
+ <li><a href="#mozTocId345412">5.4.1 platform
+abstraction</a></li>
+ </ul>
+ <ul>
+ <li><a href="#mozTocId405486">5.4.2 synchronization
+policy</a></li>
+ </ul>
+ </ul>
+ </li>
+ <li><a href="#mozTocId283551">6. Class Concepts and
+How to extend
+Channel framework</a>
+ <ul>
+ <li><a href="#mozTocId162285">6.1 id_type and
+id_trait</a></li>
+ <li>6.2 name space</li>
+ <li>6.3 dispatcher</li>
+ <li>6.4 executor</li>
+ <li>6.5 queue</li>
+ <li><a href="#mozTocId441870">6.6
+streams/connectors (or integrate into new architecture)</a></li>
+ </ul>
+ </li>
+ <li><a href="#mozTocId631535">7. Compare Channel to
+others (plan9, STL)</a>
+ <ul>
+ <li><a href="#mozTocId547030">7.1 Compare
+Unix/Plan9/Inferno file-system name space and Channel's name space</a></li>
+ <li><a href="#mozTocId82643">7.2 compare STL and
+Channel</a></li>
+ </ul>
+ </li>
+ <li>8. Reference Links</li>
+</ul>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId347090"></a><small>1. Introduction</small></h3>
+In Unix and most OSes, file systems allow applications to identify,
+bind to and operate on system resources and entities (devices,
+files,...) using a "name" (path name) in a hierarchical name space
+(directory system) which is different&nbsp; from variables and pointers
+in flat address space. Many interprocess communication facilities (IPC)
+often depend on some kind of "names" to identify them too, such as the
+pathname of FIFO or named-pipe, pathname for unix domain socket,
+ip-address and port for tcp/udp socket , and keys for System V shared
+memory, message queue and semaphores. "The set of possible names for a
+given type of IPC is called its <span
+ style="font-style: italic; font-weight: bold;">name space</span>. The
+name space is important because for all forms of IPC other than plain
+pipes, the name is how the client and server&nbsp; "connect" to
+exchange messages." (quote from W. Richard Stevens "Unix Network
+Programming").<br>
+<br>
+Channel is a C++ template library to provide name spaces for
+asynchronous, distributed message passing and event dispatching.
+Message senders and receivers bind to names in name space; binding and
+matching rules decide which senders will bind to which receivers; then
+message passing and event dispatching could happen among bound senders
+and receivers.<br>
+Channel's signature:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; template &lt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename idtype,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename platform_type = boost_platform,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename synchpolicy = mt_synch&lt;platform_type&gt;,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename executor_type = abstract_executor, </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename name_space =
+linear_name_space&lt;idtype,executor_type,synchpolicy&gt;,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename dispatcher =
+broadcast_dispatcher&lt;name_space,platform_type&gt; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; class
+channel;&nbsp;&nbsp; </span><br>
+Various name spaces (linear/hierarchical/associative) can be used for
+different applications. For example, we can use integer ids as names to
+send messages in linear name space, we can use string path name ids <a
+ id="intro">(such as
+"/sports/basketball")</a> to send
+messages in hierarchical name space<a id="intro"> and we can use regex
+patterns or
+Linda tuple-space style tuples to send messages in associative name
+space</a>; User can configure name space
+easily
+by setting a channel template parameter.<br>
+<br>
+Channel's other major components are dispatchers; which dispatch
+messages/events from senders to bounded receivers. Dispatcher is also a
+channel template parameter. The design of dispatchers can vary in
+several dimensions:<br>
+<ul>
+ <li>how msgs move: push or pull; </li>
+ <li>how callbacks executed: synchronous or asynchronous. </li>
+</ul>
+Sample dispatchers includes : synchronous broadcast dispatcher,
+buffered asynchronous dispatchers,...<br>
+<br>
+Name space and dispatchers are orthogonal; they can mix and match
+together freely; just as STL algorithms can be used with any STL
+containers by means of the iterator range concept, name space and
+dispatchers can be used together because of the name binding set
+concept. <br>
+<br>
+By combining different name space and dispatching policies, we can
+achieve various models:<br>
+<ul>
+ <li>synchronous event dispatching&nbsp;&nbsp;&nbsp; </li>
+ <li>associative name space based on matching/look-up rules similar to
+Linda tuple space</li>
+ <li>asynchronous messaging model similar to Microsoft CCR
+(Concurrency Coordination Runtime)<br>
+ </li>
+</ul>
+Similar to distributed files systems, distributed channels can be
+connected or "mounted" to allow transparent distributed message
+passing. Filters and translators are used to control name space changes.<br>
+<br>
+For tightly coupled single-address-space applications/modules,
+Channel's "unnamed" in/out
+objects : ports and signal/slots support fine grained and local message
+passing model without
+the hassle of setting up a name space and assigning names.<br>
+<br>
+Channel is built on top of Boost facilities: <br>
+<ul>
+ <li>Boost::shared_ptr for message/event data life-time management</li>
+ <li>Boost.Bind, Boost.Function for callback</li>
+ <li>Boost.Thread for synchronization</li>
+ <li>Boost.Serialization for message marshaling/demarshaling</li>
+ <li>Boost.Regex and Boost.Tuple for associative name-matching<br>
+ </li>
+ <li><big><small>Boost.Asio and Boost.Shmem are used to build
+transports among remote channels.</small></big></li>
+</ul>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId587884"></a>2. Build</h3>
+Channel is continuously being developed and tested in linux (Fedora
+Core 3 &amp;
+4) and Windows (WIndowsXP and Visual C++ 2005 express). The
+implementation is solely based on standard boost facilities plus
+Boost.Asio and
+Boost.Interprocess (shmem). <br>
+Download: http://channel.sourceforge.net<br>
+<div style="text-align: left;">Build: <br>
+<div style="margin-left: 40px;"><a
+ href="http://www.boost.org/more/getting_started.html">checkout boost
+cvs source code</a><br>
+download latest boost_channel_x_x.tar.gz<br>
+tar xvzf boost_channel_x_x.tar.gz<br>
+cd &lt;top directory of channel&gt;<br>
+copy subdirectory boost/channel/ to &lt;boost
+root directory&gt;/boost/<br>
+copy subdirectory
+libs/channel/ to &lt;boost root directory&gt;/libs/<br>
+cd to &lt;boost root
+directory&gt;/libs/channel/exmaple/&lt;specific samples such as
+ping_pong&gt;<br>
+bjam<br>
+</div>
+</div>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId174795"></a>3. Tutorials</h3>
+<p>the following are a few samples showing how different name spaces
+and dispatchers can be used in various situations:</p>
+<h4><a name="mozTocId270435"></a>3.1 gui event handling</h4>
+<p>A simple sample shows that a gui window send (broadcast) simple
+events to callbacks (either free functions or object members).
+details...</p>
+<h4><a name="mozTocId147115"></a>3.2 gui event handling with 2 local
+channels</h4>
+<p>This sample shows how 2 channels can be connected to allow gui
+events propagate from one channel to another. Also we use a POD struct
+as message id/name.&nbsp; <a
+ href="../example/gui_evt/sample2_text.html">details...</a></p>
+<h4><a name="mozTocId280170"></a>3.3 distributed gui events</h4>
+<p>A sample shows how events can be sent (broadcast) to callbacks in
+remote process by connecting local channel to remote channels thru
+Boost.Asio. details...</p>
+<h4><a name="mozTocId886481"></a>3.4 chat with direct connection</h4>
+<p>This sample shows the usage of hierarchical name space by defining
+chat subjects as string path names. For demo, chat peers directly
+connect to each other, subscribing to the subjects they are
+interested and send messages with each other. Since it a hierarchical
+name space, peers can subscribe to wildcard ids such as "all
+sports related subjects". <a
+ href="../example/chat_direct/sample4_text.html">details...</a></p>
+<h4><a name="mozTocId680978"></a>3.5 buffered channel with blocking
+active receiver (synchronous choice, join synchronization patterns)</h4>
+<p>A sample shows the usage of buffered channels implemented thru a
+synchronous pull dispatcher. In this channel
+configuration, messages are buffered inside channel at sender side.
+The receiver is active, a thread blocking waiting for the arrival of
+messages at synchronous join/choice arbiters and then processing the
+messages. details...</p>
+<h4><a name="mozTocId232384"></a>3.6 buffered channel with async
+receivers (asynchronous choice, join synchronization patterns)</h4>
+<p>This sample shows a buffered channel support asynchronous
+receivers using asynchronous coordination patterns: choice and join.
+The callback actions are dispatched thru a thread pool executor.
+details...</p>
+<h4><a name="mozTocId836556"></a><b>3.7 distributed chat thru a
+central server</b></h4>
+<p>This sample shows simple chat client and server design. Clients
+connect to server to chat with each other in seperate chat groups
+identified by subject. The chat subject (a string) is the ids in name
+space. Clients can join/leave chat groups identified by subject ids
+and send messages to chat groups. If the chat group (subject) doesn't
+exist yet, the first member's "join" will make it created.
+details...</p>
+
+<span style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+<h4><a class="mozTocH4" name="mozTocId266315"></a>3.8 channel
+connection thru shared memory</h4>
+This sample shows that remote channels at 2 processes (chat1, chat2)
+can be connected thru shared memory message queues based on
+Boost.Interprocess. details...<br>
+<h4><a class="mozTocH4" name="mozTocId300223"></a>3.9 channel using
+regex name matching<br>
+</h4>
+This sample demos channels using regex pattern matching for
+name-matching and message dispatching. Peers can use regex patterns to
+bind/subscribe to names/ids. Boost.Regex is used for implementation. <a
+ href="../example/chat_regex/sample9_text.html">details...</a><br>
+<h4><a class="mozTocH4" name="mozTocId440147"></a>3.10 channel using
+Linda-style associative lookup<br>
+</h4>
+This sample demos channels using Linda-style associative name space.
+Tuples are used as names/ids and associative lookup is used for
+name-matching. Boost.Tuple is used for implementation. <a
+ href="../example/chat_assoc/sample10_text.html">details...</a><br>
+<h4><a class="mozTocH4" name="mozTocId505601"></a>3.11 channel name
+space management and security with filter and
+translator</h4>
+<h4></h4>
+This sample demos how we can use filters and translators to achieve
+name space management and security. <a
+ href="../example/filter_translator/sample11_text.html">details...</a><br>
+<h4><a name="sample_dispatcher"></a>3.12 port and signal: unnamed point
+of tightly-coupled local interactions
+</h4>
+This tutorial explains 3 samples based on port and signal. <a
+ href="../example/prime_sieve/sample12_text.html">details...</a><br>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId750399"></a>4. Design</h3>
+<h4><a class="mozTocH4" name="mozTocId135917"></a>4.0 Overall Design
+Idea</h4>
+"Names" play important role in distributed computing:<br>
+<ul>
+ <li>Name space plays a central role in plan9/inferno distributed OS
+as
+described in [1][2]. </li>
+</ul>
+<div style="margin-left: 40px;">quote: <br>
+"... a new kind of system, organized around communication and naming
+..."<br>
+"A single paradigm (writing to named places) unifies all kinds of
+control and interprocess signaling."<br>
+It can be briefly summerized as following:<br>
+<ul>
+ <li>Every resource, either local or remote, is represented as a
+hierarchical file system (name space).</li>
+ <li>Each process can assemble a private view of the system by
+constructing a local/private name space that connect these resources
+thru mount, bind and umount on demand.</li>
+ <li>The interface to named resources are file-oriented; they are
+accessed thru open/close/read/write calls.</li>
+</ul>
+</div>
+<ul>
+ <li>Robin Milner[3][4] gives a detailed discussion about what we can
+do
+with a name in asynchronous message passing, or the interactions thru
+"name":</li>
+</ul>
+<div style="text-align: left; margin-left: 40px;">The following
+operations on names are identified:<br>
+<ul>
+ <li>use name: call, co-calling (response)<br>
+ </li>
+</ul>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">call -
+vocative use of name by one agent</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">co-call/response - reaction by other</span><br>
+Synchronized action is the coming together (binding) of calling and
+co-calling (thru name).<br>
+The reason to distinquish between "calling" and "response" is that, in
+describing any agents ( processes/ threads/ ...), we define its
+potential
+behaviour (or capabilities) by what calls and responses it can make -
+this is the basic idea underlying the active objects or communicating
+processes based design which will be detailed in later section.<br>
+</div>
+<ul>
+ <li>mention name: quote/co-quote, match<br>
+ </li>
+</ul>
+<div style="margin-left: 40px; font-weight: bold;">quote, co-quote:</div>
+</div>
+<div style="text-align: left;">
+<div style="margin-left: 80px;">quote/co-quote is refering to the way
+we can pass names as/inside message content. We can simulate function
+call (call-and-return) by packing a "return" name/id inside message and
+waiting on this name for result (from remote).<br>
+</div>
+</div>
+<div style="text-align: left; margin-left: 40px;">
+<div style="margin-left: 40px; font-weight: bold;">match:</div>
+</div>
+<div style="text-align: left;">
+<div style="margin-left: 80px;">test a name for equality with another
+name. Name matching algorithms are mostly dependent on name space
+structure. In following sections, we will expand "matching" to include
+wildcards and regex matching<br>
+</div>
+<div style="margin-left: 40px;"><br>
+The design of Channel is based on the following integration of
+Plan9/Inferno's
+name space idea and Robin Milner's interaction thru names:<br>
+<ul>
+ <li>Channel provides process local private name_space which is
+customizable thru connecting to other channels.</li>
+ <li>The semantics of names are changed; names do not refer to named
+resources (which are relatively static entities), but to named "points
+of interaction" (which are mostly dynamic); thus file-oriented api and
+semantics are dropped and Robin Milner's operations/interactions on
+names are adopted as the api: calling/co-calling/matching.</li>
+</ul>
+</div>
+</div>
+<div style="text-align: left; margin-left: 40px;">
+<div style="margin-left: 80px;"></div>
+</div>
+<h4><a class="mozTocH3" name="mozTocId540592"></a>4.1 Name space</h4>
+<h4><a class="mozTocH4" name="mozTocId84795"></a>4.1.1 What's in a name?</h4>
+In Channel, to facilitate name-matching/binding operations, a name has
+the
+following attributes:<br>
+<ul>
+ <li>id_type<br>
+ </li>
+</ul>
+<div style="margin-left: 40px;">Id is the main content of names.
+Various types of ids can be used for different applications: integer,
+strings, POD structs etc can be used for linear name space;
+string
+path names can be used for hierarchical name spaces and regex patterns
+and Linda style tuples can be used for associative name space.<br>
+</div>
+<ul>
+ <li>id_trait and id-matching algorithms<br>
+ </li>
+</ul>
+<div style="margin-left: 40px;">Id_trait defines the attributes of an
+id type. A major feature of id_trait is the
+id-matching algorithm,
+which partially decides name-matching and thus which senders will bind
+which receivers and be
+able to send messages to them. For example, exact matching can be used
+for linear name space ids; prefix matching can be used for path
+name ids; while in associative name spaces, regex pattern matching and
+Linda style associative lookup can be used for id-matching.<br>
+</div>
+<ul>
+ <li>membership</li>
+</ul>
+<div style="margin-left: 40px;">A channel is a process local name space
+which can be connected to other
+local or remote channels. So we have 2 types of communicating peers:<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>MEMBER_LOCAL (local peers): communication peers inside the same
+channel</li>
+ <li>MEMBER_REMOTE (remote peers): communication peers from different
+channels</li>
+</ul>
+<ul>
+ <li>sending and receiving scope</li>
+</ul>
+<div style="margin-left: 40px;">When sending/receiving messages, we can
+specify the scope of operations:<br>
+<ul>
+ <li>SCOPE_LOCAL: <br>
+ </li>
+ <ul>
+ <li>publish/send specified messages to local peers; <br>
+ </li>
+ <li>subscribe/receive specified messages from local peers</li>
+ </ul>
+ <li>SCOPE_REMOTE: <br>
+ </li>
+ <ul>
+ <li>publish/send specified messages to remote peers; <br>
+ </li>
+ <li>subscribe/receive specified messages from remote peers</li>
+ </ul>
+ <li>SCOPE_GLOBAL: <br>
+ </li>
+ <ul>
+ <li>publish/send specified messages to both local and
+remote peers; <br>
+ </li>
+ <li>subscribe/receive specified messages from both local and
+remote peers</li>
+ </ul>
+</ul>
+</div>
+<h4><a class="mozTocH4" name="mozTocId582741"></a>4.1.2 Types of
+name space</h4>
+There are 3 types of name spaces based on its id-matching algorithms
+and naming structures:<br>
+<ul>
+ <li>linear:</li>
+</ul>
+<div style="margin-left: 40px;">There are ordering relationship among
+ids, so they can be arranged in linear range. <span
+ style="font-weight: bold; font-style: italic;">Exact matching</span>
+is used
+for
+id-matching.<br>
+</div>
+<ul>
+ <li>hierarchical:</li>
+</ul>
+<div style="margin-left: 40px;">There are containment relationship
+among ids, so they can be arranged in tree/trie structures. <span
+ style="font-style: italic; font-weight: bold;">Prefix
+matching</span> is used for id-matching<br>
+</div>
+<ul>
+ <li>associative:</li>
+</ul>
+<div style="margin-left: 40px;">Id-matching is based on <span
+ style="font-style: italic; font-weight: bold;">associative
+lookup</span> similar to Linda's tuple space or regular expression
+matching
+algorithms<br>
+</div>
+<h4><a class="mozTocH4" name="mozTocId182536"></a>4.1.3 Name binding
+set and Name matching
+algorithm, binding rules<br>
+</h4>
+No pure name exist; Names are ONLY created into name space when bound
+for sending/receiving msgs:<br>
+<ul>
+ <li>Named_Out: output/send interface bound with name</li>
+ <li>Named_In: input/receiv interface bound with name</li>
+</ul>
+Name binding sets:<br>
+<ul>
+ <li>for Named_Out, its binding_set is the set of bound Named_Ins to
+which to send messages</li>
+ <li>for Named_In, its binding_set is the set of bound Named_Outs from
+which to receive messages</li>
+</ul>
+There are 2 aspects to the name matching algorithms and binding rules
+to decide binding_sets:<br>
+<ul>
+ <li>id matching: the id of Named_Out must "match" the id of Named_In
+based on matching operation defined in id_trait<br>
+ </li>
+ <li>scope &amp; membership matching: the membership and scope of both
+Named_Out and Named_In must match. This doesn't mean they must be the
+same. For example, a local sender&nbsp; (MEMBER_LOCAL) with SCOPE_LOCAL
+can bind to receivers with &lt;MEMBER_LOCAL, SCOPE_LOCAL&gt; or
+&lt;MEMBER_LOCAL, SCOPE_GLOBAL&gt;. There is an internal table
+recording
+all such valid combinations.</li>
+</ul>
+Named_Out and Named_In don't bind to each other directly (as in most
+event dispatching systems). Instead, they bind to names in name
+space. Based on binding and matching rules, their binding set will
+be resolved which will contain the direct pointers to their
+counterpart. Actual message passing and dispatching happen on the
+binding set; never need to go thru name space again. So the actual
+message passing and dispatching behaviour and performance should be the
+same as&nbsp; we&nbsp; have registered the Named_In directly with
+Named_Out ( as we would have done in normal event dispatching systems ).<br>
+Based on name-matching, there are possibly the following 4 kinds of
+binding sets:<br>
+<ul>
+ <li>1 - 1:&nbsp; one named_out binds with exactly one named_in</li>
+ <li>1 - N: one named_out binds with a group of named_ins (e.g. when
+many subscribers subscribe to the same name)</li>
+ <li>N - 1: one named_in binds with a group of named_outs (e.g. when a
+subscriber subscribes using a wildcard name or regex pattern, it could
+receive from multiple sources)</li>
+ <li>N - M: both named_out and named_in bind with a group of
+counterparts.<br>
+ </li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId891206"></a>4.1.4 Name spaces
+merge and connections<br>
+</h4>
+When 2 channels (A &amp; B) are connected/mounted, their name spaces
+are
+merged as following:<br>
+<ul>
+ <li>names flowing from B-&gt;A:&nbsp; the intersection of A's set of
+Named_In with global/remote scope (global subscriptions) and B's set
+of&nbsp; Named_Out with global/remote scope (global
+publications) </li>
+ <li>names flowing from A-&gt;B:&nbsp; the intersection of B's set of
+Named_In with global/remote scope (global subscriptions) and A's set
+of&nbsp; Named_Out with global/remote scope (global
+publications) </li>
+ <li>newly created names/ids are automatically
+propogated to connected channels. So peers in channel A can communicate
+with peers in channel B transparently the same way as with the local
+peers. </li>
+</ul>
+Filter, translator can be specified at connections among channels to
+control name space merge:<br>
+<ul>
+ <li>filter: decide which ids are allowed to be exported/sent to
+(visible at) remote
+channels and which remote ids are allowed be imported to local name
+space<br>
+ </li>
+ <li>translator: allow translation of ids imported to local name space
+and ids exported to remote name space; so we can relocate the imported
+remote name space ids to a specific subspace in the local name space,
+similar to the way that in distributed file systems, a remote file
+system can be mounted to a specific point in local file system.</li>
+</ul>
+Based on applications name space management requirements, we may need
+to "relocate"/"mount" the names imported (from a connection to a remote
+name space) to a specific sub-region in name space. For example, if we
+have a name space in desktop computer and connect to a PDA and a
+laptop, we can set translators at connections so that names imported
+from PDA will appear under "/pda/" and names from laptop will appear
+under "/laptop/". Or if our application use integer as ids/names, we
+may want to relocate ids from the 1st connection to [1000-1999] and ids
+from next connection to [2000-2999] and so on. That is similar to the
+way how we mount remote file-systems to local file-system.<br>
+Based on security requirements, we may need to use filters to restrict
+the valid range of names allowed to pass in/out specific channel
+connections. For example, a server's name space connect to 2 clients
+and we want that these clients' name spaces and messaging are totally
+separate, so that one client is unware of anything happening inside the
+other client's name space such as new name-publications and message
+passing. That is also similar to the way we protect network by
+firewalls and NATs.
+<ul>
+</ul>
+<h4><a class="mozTocH3" name="mozTocId210395"></a>4.2 Dispatching</h4>
+Dispatchers or dispatching policies are operations or algorithms
+defined over name binding set. They define the semantics of
+"interactions
+thru names". Based on RobinMilner's separation of
+calling and co-calling, there are 2 parts defined for each
+dispatching algorithm:<br>
+<ul>
+ <li>sending (or sender) algorithm: corresponding to calling<br>
+ </li>
+ <ul>
+ <li>defined over the set of bound Named_In (receiver) objects</li>
+ <li>may contain message buffering mechanism inside channel
+(Named_Outs)<br>
+ </li>
+ </ul>
+ <li>receiving (or receiver) algorithm: corresponding to co-calling<br>
+ </li>
+ <ul>
+ <li>defined over the set of bound Named_Out (sender) objects</li>
+ <li>may support high level messaging coordination patterns (such as
+Choice and Join)</li>
+ </ul>
+</ul>
+The following are major design considerations for dispatchers.<br>
+<h4><a class="mozTocH4" name="mozTocId862080"></a>4.2.1 How message
+data move: push/pull, buffering</h4>
+There are 2 basic models of passing messages/events from senders to
+receivers:<br>
+<ul>
+ <li>push model: message data are pushed by senders to receivers</li>
+ <li>pull model: message data are pulled by receivers from senders</li>
+</ul>
+Since Channel is for asynchronous messaging, mostly the following 2
+dispatching categories are used:<br>
+<ul>
+ <li>push:&nbsp;</li>
+</ul>
+<div style="margin-left: 40px;">Dispatching variations can be:
+broadcast, round-robin,...<br>
+Execution variations can be: <br>
+<ul>
+ <li>synchronous: the sending threads will push messages all the way
+to
+receviers and invoke receiving callbacks directly</li>
+ <li>asynchronous: the sending threads will push messages to receivers
+and dispatch the receiving callbacks to some executors for later
+executions<br>
+ </li>
+</ul>
+</div>
+<ul>
+ <li>buffering+pull:</li>
+</ul>
+<div style="margin-left: 40px;">Messages are buffered inside channel at
+Named_Out side; receivers pull message data in two ways:<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>sync/blocking receiver: in this model, receivers are active
+receiving threads block-waiting at Named_In, unblocked when message
+data are
+available and pull data from Named_Out</li>
+ <li>async receiver: async callback operations are registered to
+logical conditions of message arrivals (choice and join) and will be
+dispatched to executors depending on message arrivals.</li>
+</ul>
+<div style="margin-left: 40px;">Message coordination patterns (choice
+and join) are applied for both pull synchronous and asynchronous model
+to
+decide when a synchronous receiving thread can be unblocked or
+asynchronous callback can be fired based on the available messages.<br>
+<br>
+</div>
+For message buffering inside channel, we can have various design
+choices:<br>
+<ul>
+ <li>synchronized queues with flow control: low water mark and high
+water mark</li>
+ <li>timeouts for when messages will expire</li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId629360"></a>4.2.2 How operations
+are performed: synchronous/asynchronous</h4>
+When messages arrive, we have 2 choices for how dispatching operations
+and callbacks are performed:<br>
+<ul>
+ <li>synchronous: the sending thread will carry out dispatching and
+callbacks</li>
+ <li>asynchronous: dispatching or callbacks will be scheduled in an
+executor; and later executed by the executor in a different calling
+context or thread</li>
+</ul>
+There are various designs of executors. [7] provides detailed
+discussion about Java's executor design. <br>
+Different executors can run threads in different scheduling priorities
+and we can assign callbacks to run in propr executors according to
+applications' requirements<br>
+<h4><a class="mozTocH4" name="mozTocId248159"></a>4.2.3 Message passing
+coordination
+patterns<br>
+</h4>
+Join-calculus, Comega, and CCR [5][6] define a few messaging
+coordination
+patterns regarding to when and how messages will be consumed and
+callbacks be fired: <br>
+<ul>
+ <li>Choice: a combo registration of a group of &lt;name,
+callback&gt;; whenever any "name" has message delivered, its associated
+callback will be fired<br>
+ </li>
+ <li>Join: a callback is registered with a set of names; when messages
+become available on all names, the messages will be taken from all
+names "atomically" and the registered callback will be invoked.<br>
+ </li>
+</ul>
+In channel, both choice and join are applied in synchronous and
+asynchronous forms.<br>
+<h4><a class="mozTocH4" name="mozTocId995030"></a>4.2.4 Messages
+handling</h4>
+life-time management of messages:<br>
+<ul>
+ <li>avoid data copying, pass pointers to messages instead of
+duplicating message data</li>
+ <li>wrap message data pointer inside boost::shared_ptr so that
+message data's life time management is automatic<br>
+ </li>
+</ul>
+marshaling/demarshaling of messages:<br>
+<ul>
+ <li>use Boost.Serialization for marshaling/demarshaling</li>
+ <li>a channel could have multiple remote connections, each of them
+could use different transport (tcp/ip, soap, shared-memory) and on-wire
+message format
+(text/binary/xml). In Channel based applications, a marshaler_registry
+can be created for each specific transport type and format.
+By registering message data type with a marshaler_registry using ids as
+key, internal marshaling/demarshaling functions will be created for the
+registered message data types and invoked automatically when messages
+are sent-to and received-from remote channels. When a
+channel is connected to a remote channel thru "streams", we must
+specify
+which marshaler_registry to use for marshaling. <br>
+ </li>
+ <li>for each id/msg-type, we can have different settings of
+marshaling:</li>
+</ul>
+<ul style="margin-left: 40px;">
+ <li>explicitly register a message data type: internally a marshaler
+object will be created and registered with ids<br>
+ </li>
+ <li>use a globally registered default marshaler (if all ids use the
+same data structure)</li>
+</ul>
+<h4><a class="mozTocH3" name="mozTocId967906"></a>4.3 Connection related</h4>
+The following are design considerations related to channel connections.<br>
+<h4><a class="mozTocH4" name="mozTocId216417"></a>4.3.1 Connections</h4>
+there are 2 kinds of connections:<br>
+<ul>
+ <li>local connection:&nbsp; inside the same process, we can have
+multiple channels for different purposes; we can connect these local
+channels to facilitate the communication among their peers.<br>
+ </li>
+ <li>remote connection: we can connect channel to a remote channel
+inside a different process or different machines; the remote interface
+is represented as "streams": socket stream, pipe, or a message queue
+inside shared memory;</li>
+</ul>
+connection object is a simple object, just containing the two
+peers/ends of the connection.<br>
+ways to break a connection:<br>
+<ul>
+ <li>delete connection object; peers are deleted and channels
+disconnect</li>
+ <li>one peer channel is destroyed, the connection will be destroyed
+automatically and the other channel disconnect</li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId162029"></a>4.3.2 Peer</h4>
+&nbsp;&nbsp;&nbsp; the common interface for connection peers:
+interfaces and streams<br>
+<ul>
+ <li>interface:</li>
+</ul>
+<div style="margin-left: 40px;">proxy of peer channel<br>
+core of channel connection logic:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;. how remote
+binding/unbinding events will effect local name space<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;. how messages are
+propagated from and to remote channels<br>
+</div>
+<ul>
+ <li>stream:</li>
+</ul>
+<div style="margin-left: 40px;">Stream is used to wrap a remote
+transport connection (socket, pipe or message queue inside shared
+memory).<br>
+In earlier implementation of Channel on ACE[8], a Connector class is
+included as one of the core classes; which will connect local and
+remote channels. the disadvantage of this design is that Channel is
+tied to a specific architecture (such as thread per connection); making
+it difficult to integrate channel with other existing servers.<br>
+In plan9/inferno, when we mount a remote name space to local, the real
+function is to mount a descriptor (file, pipe, or socket connection) to
+a specific point in name space.<br>
+Following this style, remote channel connection is to connect/mount a
+"stream" to a local channel/name_space; the stream wraps a socket,
+pipe, or shared_memory message
+queue connecting a remote channel in another process or machine. thus
+avoid interfering with servers' internal design: such as
+threading; so that channel can work well with both single-thread async
+and multi-thread sync server design.<br>
+</div>
+<h4><a name="unnamed_design"></a>4.4 "Unnamed" binding of output/input
+or points of tightly-coupled
+local
+interactions</h4>
+&nbsp;&nbsp;&nbsp; As discussed in the "Overall Design Idea" section,
+message passing happens on the binding of calling(the sender of
+dispatcher) and co-calling(the receiver of dispatcher).<br>
+&nbsp;&nbsp;&nbsp; All the above discussions focus on setting up this
+binding thru name-matching in name spaces. "Binding thru names"
+provides a loosely coupled computing model. A agent or thread can
+perform or provide its functionality thru the "names" which it
+publishes and subscribs in application channel. It can be moved to
+another process or another machine and continue functioning as before
+as long as in its new enviroment there is a channel connected to the
+original channel and the moved agent attaches to the new channel with
+the same set of "names". However sometimes it may be too much
+burden/overhead than benefit to set up a name space and assign proper
+names, if all we want is performing "localized" computation based on
+message passing model.<br>
+&nbsp;&nbsp;&nbsp; In many message passing based
+systems,
+threads(or
+processes in CSP meaning) communicate thru "ports" or
+"channels" which are normal local objects with possible internal
+message queue.
+Choice/Join arbiters work directly with these local objects. Pointers
+to these objects can be passed inside messages to enable various
+message-passing based idioms. These provide a tightly coupled localized
+models inside the same address space.<br>
+&nbsp;&nbsp;&nbsp; From channel's design perspective, these localized
+communication primitives can be encoded as special kinds of binding set
+of senders (named_out) and
+receivers (named_in). They are "unnamed", not set up thru name matching
+in name space. For example in C++CSP, there are One2OneChannel,
+Any2OneChannel and One2AnyChannel. One2OneChannel can be encoded as the
+binding of one "unnamed_out" and one "unnamed_in"; Any2OneChannel can
+be encoded as the binding of a group of "unnamed_out" and a single
+"unnamed_in"; One2AnyChannel can be encoded as the binding of a single
+"unnamed_out" and a group of "unnamed_in" (please note that CSP
+requires synchronous rendezvous of sender and recevier which can be
+implemented thru a
+special dispatcher). There is a similar case with normal event
+dispatching systems
+where application code directly attaches event receivers (slots) to
+event sources (signals), not thru name-matching in name space.<br>
+&nbsp;&nbsp;&nbsp; Channel provides generic functions to set up
+and break binding among any pair of named_out and named_in:<br>
+<span style="font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+template &lt;typename name&gt; void bind(name *named_out, name
+*named_in);</span><br style="font-weight: bold; font-style: italic;">
+<span style="font-weight: bold; font-style: italic;">
+&nbsp;&nbsp;&nbsp; template &lt;typename name&gt; void unbind(name
+*named_out, name *named_in);</span><br>
+&nbsp;&nbsp;&nbsp; By means of these functions, we can setup any
+imaginable bindings (1-N, N-1, N-M) among named_out and named_in.<br>
+&nbsp;&nbsp;&nbsp; Various message passing systems use different idioms
+or patterns of binding sets. Channel provides the following
+sample tightly coupled idioms thru "unnamed" in/out objects (<a
+ href="../../../boost/channel/unnamed_in_out.hpp">unnamed_in_out.hpp</a>):
+<br>
+<ul>
+ <li>Ports are objects with internal message buffering. Applications
+can
+send messages thru ports. Choice/Join arbiters coordinate how messages
+are consumed from ports and how handlers are called. (similar to CCR's
+ports)<br>
+ </li>
+ <li>Signals and Slots objects provide direct support for "localized"
+event dispatching. Slots objects identify the bindings between&nbsp;
+event source (signal) and callbacks; Deletion of either signal or slots
+will remove these bindings automatically.<br>
+ </li>
+</ul>
+&nbsp;&nbsp;&nbsp; Ports and Signals are simple template specialization
+of
+Named_Out and Named_Ins with null_id (unnamed!) and proper dispatchers
+(pull dispatcher for Port and push dispatcher for Signal/Slot). They
+can be customized by template parameters just as normal
+channel entities, e.g. Port can be customized with different queue
+types and Signal/Slot can be customized with different dispatching
+algorithms (broadcast, round-robin ...). Ports and Signals are well
+integrated with "named" entities:<br>
+<ul>
+ <li>Ports can participate in the same Choice/Join arbiter as
+"ids/names"; so arbiters can coordinate both local and remote messages.
+Some important usage of this is to implement the timeout or exception
+exit of Choice/Join. A timer generate events into a timeout port which
+can be included in a Choice. Choice could receive timeout message and
+exit when it happens.</li>
+ <li>Ports and Signals can later be attached to names in name space;
+so they become normal "named" entities and can enjoy binding thru
+name-matching and remote message passing as usual.</li>
+</ul>
+<div style="margin-left: 40px;"></div>
+<h4><a class="mozTocH4" name="mozTocId970853"></a>4.5 Application
+architecture and integration</h4>
+Channel is intentionally designed to be indepedent of threading models
+and connection strategies. So channel can be helpful to implement
+various applications with different designs of threading and connection:<br>
+<ul>
+ <li>event dispatching/callbacks based applications: such as GUI
+frameworks where there is no explicit mentioning of thread (single
+threaded)</li>
+ <li>asynchronous I/O based server applications: such as servers based
+on Boot.Asio, eventlib or libasync; in these kind of servers, there may
+be single or a few "main" threads driving the reactive or proactive
+main event loop; all threads play equal role.</li>
+ <li>active objects or communicating processes based design: this is
+the original target applications of Channel; they are popular in large
+scale distributed embedded systems design. In these designs, the whole
+system is partitioned into many interacting processes/threads; each of
+which performs a specific functionality (defined mostly by its
+publishing/sending names-set and subscribing/receiving names-set),
+maintains/own a part of system
+state (finite state machines) and interacting with each other ONLY thru
+message passing. No one can directly change the system state owned by
+another process/thread; Change requests can only be sent to owner
+process/thread as messages and owner can reasonably reject them.</li>
+ <li>thread pool based server design: In these systems, servers' job
+can be partitioned into scheduling units - tasks, which are dispatched
+to a dedicated pool of threads for execution. There are two kind of
+threads in system: <br>
+ </li>
+ <ul>
+ <li>master threads: listening for incoming client requests and
+dispatch tasks to pool</li>
+ <li>worker threads: member of pool, waiting for tasks and execute
+them</li>
+ </ul>
+</ul>
+Channel's independence of threading and connection also makes it easy
+to integrate Channel with exising server applications of various
+designs. Basically we'll write wrapper classes to glue channel to
+existing server mechanisms:<br>
+<ul>
+ <li>"executors" wrappers to integrate channel's asynchronous
+operations execution into servers' threading model</li>
+ <li>"streams" wrappers to implement remote channel connection thru
+server existing connection strategies<br>
+ </li>
+</ul>
+<div style="margin-left: 40px;"></div>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId39115"></a>5. Classes</h3>
+<h4><a class="mozTocH4" name="mozTocId591675"></a>5.1 name space related</h4>
+<h4><a class="mozTocH4" name="mozTocId899602"></a>5.1.1 name spaces</h4>
+&nbsp;&nbsp;&nbsp; The major purpose of name space is to set up the
+bindings among named_outs and named_ins based on id-matching and
+scoping rules. There are 3 kinds of name spaces:<br>
+<ul>
+ <li><a href="../../../boost/channel/name_spaces/linear_name_space.hpp">linear
+name_space (with exact matching)<br>
+ </a></li>
+ <li><a
+ href="../../../boost/channel/name_spaces/hierarchical_name_space.hpp">hierarchical
+name_space (with prefix matching)</a><br>
+ </li>
+ <li>associative
+name_space (implemented as linear name space with associative matching)<br>
+ </li>
+</ul>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name space API are fixed, must support
+the following methods:<br>
+<div style="margin-left: 40px;">void bind_named_out(name *n);<br>
+void unbind_named_out(name *n);<br>
+void bind_named_in(name *n);<br>
+void unbind_named_in(name *n);<br>
+</div>
+<h4><a class="mozTocH4" name="mozTocId828224"></a> 5.1.2 id_type and
+id_trait </h4>
+As described above, various id_types (integer, string, PODS, pathnames,
+tuples etc) can be used for different applications and name spaces. To
+support
+name binding operations, id_type should support the following
+operations:<br>
+<ul>
+ <li>id_types used for linear name space support operator&lt;() for
+linear "ordering" among ids</li>
+ <li>id_types used for hierarchical name space support "containment"
+operation to decide among 2 ids which will contain the other</li>
+ <li>all id_type should define "match" operation in its id_trait
+classes:</li>
+</ul>
+<ul>
+ <ul>
+ <li>For ids in linear name space, we define exact match in <a
+ href="../../../boost/channel/name_spaces/linear_id_trait.hpp">linear_id_trait</a><br>
+ </li>
+ <li>For ids in hierarchical name space, we define prefix match in <a
+ href="../../../boost/channel/name_spaces/hierarchical_id_trait.hpp">hierarchical_id_trait</a>
+(ie.
+"/sports/*" will match both "/sports/basketball" and
+"/sport/baseball")&nbsp; <br>
+ </li>
+ <li>For ids in associative name space, ids will be either regex or
+tuples
+containing
+multiple fields; for regex ids, regex pattern matching is used; for
+tuple ids, 2 ids will match if all their fields match or some
+fields are wildcards. regex ids and tuple ids are defined in <a
+ href="../../../boost/channel/name_spaces/assoc_id_trait.hpp">assoc_id_trait</a>.<br>
+ </li>
+ </ul>
+</ul>
+To be able to use primitive data types as name space ids, containment
+and matching operations are defined inside id_trait classes.<br>
+For channels to be connected with remote name spaces, non-primitive
+id_type should define serialize() methods to allow ids be marshaled and
+demarshaled using Boost.Serialization.<br>
+Id_trait classes also contain definitions of the following 8 system ids:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type channel_conn_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type channel_disconn_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type
+init_subscription_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type connection_ready_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type subscription_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type unsubscription_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type publication_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type unpublication_info_msg.<br>
+These ids are used internally for channel name space management.
+Applications can also subscribe to these system ids to receive
+notifications about name space changes and add application logic to
+react properly; for example:<br>
+<ul>
+ <li>start communication when remote channels connect in or remote
+peers join
+in.<br>
+ </li>
+ <li>perform special handlings when channel disconnect.<br>
+ </li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId856863"></a>5.1.3 name and name
+binding callback</h4>
+Class name
+is an internal class; application code will not use names
+directly however. Applications will instantiate <a
+ href="../../../boost/channel/named_in_out.hpp">named_out
+and named_in</a> to set up message passing logic.<br>
+Class name
+contains the most important information in name space: id,
+scope, membership and binding_set.<br>
+When Named_In and Named_Out are instantiated, a name binding callback
+can be specified to allow applications to be notify when peers bind
+to the name. Its signature :<br>
+<span style="font-weight: bold;">void binding_callback(name *n,
+typename name::binding_event e).</span><br>
+<h4><a class="mozTocH4" name="mozTocId915384"></a>5.1.4 named_out and
+named_in; publisher and subscriber</h4>
+Class <a href="../../../boost/channel/named_in_out.hpp">named_out
+and named_in</a> are where name space and dispatcher meets.
+In fact, they inherit from both class name and dispatcher.<br>
+Class <a href="../../../boost/channel/named_in_out.hpp">named_out_bundle
+and named_in_bundle</a> are helper classes to
+conveniently use a group of name bindings.<br>
+On top of named_out_bundle and named_in_bundle, class <a
+ href="../../../boost/channel/pub_sub.hpp">publisher
+and
+subscriber</a> provide direct support for publish/subscribe model.<br>
+<h4><a name="unnamed_class"></a>5.1.5 <a
+ href="../../../boost/channel/unnamed_in_out.hpp">unnamed in/out: port
+and signal/slot</a></h4>
+Class port provides direct support for localized tightly coupled
+message passing model. Port inherit pull_dispatcher's sender which
+inherit queue class. So port can be used directly as a message queue
+and application can put messages into it and get messages from it.
+However ports are mostly used with choice/join arbiters.<br>
+Class signal/slot support localized "unnamed" event dispatching model.<br>
+<h4><a class="mozTocH4" name="mozTocId750531"></a><a
+ href="../../../boost/channel/binder.hpp">5.1.6
+binder, filter and translator</a></h4>
+Filters and translators are defined to control name space changes
+during name space connection and binding. Binders contain both filters
+and translators and are specified in channel connection function calls.
+APIs and dummy operations of binders, filters and translators are
+defined here,<br>
+<h4><a class="mozTocH4" name="mozTocId985604"></a>5.2 dispatching
+related</h4>
+<h4><a class="mozTocH4" name="mozTocId308124"></a>5.2.1 dispatchers</h4>
+As we discussed above, dispatchers have 2 parts: sending and receiving
+algorithms.
+Dispatcher's API are not fixed, depending on whether it uses push or
+pull model and it is synchronous or asynchronous. The following sample
+dispatchers are provided:<br>
+<ul>
+ <li><a
+ href="../../../boost/channel/dispatchers/push_dispatcher_base.hpp">push
+dispatchers</a>:<br>
+ </li>
+ <ul>
+ <li><a
+ href="../../../boost/channel/dispatchers/broadcast_dispatcher.hpp">broadcast_dispatcher</a>:
+ <br>
+ </li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">senders/named_out broadcast
+messages/events to all bound receivers/named_in. This is the most
+common event dispatching semantics.<br>
+</div>
+<ul>
+ <ul>
+ <li><a
+ href="../../../boost/channel/dispatchers/round_robin_dispatcher.hpp">round_robin_dispatcher</a>:&nbsp;</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">senders/named_out send messages/events
+to bound receivers/named_in in round-robin manner. Simple server load
+balance can be achieved thru this.<br>
+</div>
+<ul>
+ <ul>
+ <li><a
+ href="../../../boost/channel/dispatchers/always_1st_dispatcher.hpp">always_latest_dispatcher</a>:</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">senders/named_out always send
+messages/events to the latest bound receivers/named_in. This is a
+dispatcher to simulate plan9's union directory (though most semantics
+is achieved thru nam space binding/connection). Suppose we use an id
+(such as "/dev/printer") represent a printer resource. To print
+something, we send a message to that id. On another machine there is
+another printer bound to the same id in their local channel.&nbsp; To
+be able to use the 2nd printer, we could connect or mount the remote
+channel to local channel. Then if always_latest_dispatcher is used, all
+following printouts (sent to&nbsp; /dev/printer) will come from the
+remote printer. The local printer will get
+print messages again after the channels disconnect.<br>
+</div>
+<ul>
+ <li><a
+ href="../../../boost/channel/dispatchers/pull_dispatcher_base.hpp">pull
+dispatcher</a>:</li>
+</ul>
+<div style="margin-left: 40px;">In pull dispatcher, messages/events are
+buffered inside channel at Named_Outs, high level messaging
+coordination patterns - "arbiters" are defined at Named_Ins to decide
+when and how messages are pulled from Named_Outs and consumed by
+receiving threads or callbacks.<br>
+</div>
+<ul>
+ <ul>
+ <li><a href="../../../boost/channel/dispatchers/arbiters_sync.hpp">synchronous
+arbiters (choice_sync, join_sync)</a>:</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">Both senders and
+receivers are active threads. Messages are buffered inside channel at
+sender/named_out side and sending thread returns right away. Receiving
+threads block waiting messages at synchronous arbiters. They unblock
+and process messages when messages are
+available at named_outs and their associated arbiters fired.<br>
+</div>
+<ul>
+ <ul>
+ <li><a href="../../../boost/channel/dispatchers/arbiters_async.hpp">asynchronous
+arbiters (choice_async, join_async)</a>:</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">Callbacks are registered with
+asynchronous arbiters. Messages are buffered inside channel at
+sender/named_out
+side and sending thread will notify receivers before return. Depending
+on arriving messages, asynchronous arbiters will decide which callbacks
+will fire; and schedule them to execute in an executor. Join arbiters
+will quarantee that
+related messages are consumed atomically.<br>
+</div>
+<h4><a class="mozTocH4" name="mozTocId187818"></a>5.2.2 messages</h4>
+<ul>
+</ul>
+<div style="margin-left: 40px;">Application message/event data can be
+any data type : primitives, structs and classes.&nbsp; For remote
+message passing, proper serialization functions must be defined using
+Boost.Serialization:<br>
+<ul>
+ <li>free serialization functions for non-intrusive serialization<br>
+ </li>
+ <li>message struct and classes can define serialize() methods; and
+should
+define default construtor for serialization, otherwise
+save_construct/load_construct need to be overwritten.</li>
+</ul>
+Please refer to the tutorials for sample message definitions.<br>
+</div>
+<h4><a class="mozTocH4" name="mozTocId953831"></a>5.2.3 queues</h4>
+Queues are used for inside channel message buffering. One of pull
+dispatcher's template parameter is queue type. Various applications can
+specify and use different queue types based on applications'
+requirements and queues' capability. Queues will support the following
+common interface:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+put(elem_type &amp; e);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+get(elem_type &amp; e);</span><br style="font-weight: bold;">
+<br>
+The following sample queue implementations are or will be provided:<br>
+<ul>
+ <li>unbounded_queue:
+a simple synchronized queue with unlimited buffer size, so senders are
+never blocked.<br>
+ </li>
+ <li>bounded_queue:
+a synchronized queue bounded with a maximum number of buffered
+messages; when queue buffer is full, the senders will be blocked till
+some messages are removed from the queue.<br>
+ </li>
+ <li>dropping_queue:
+a synchronized queue bounded with a maximum number of buffered
+messages; when queue buffer is full, newly added messages will force
+oldest messages to be dropped and senders will never be blocked.<br>
+ </li>
+ <li>flow_controlled_queue (coming): a flow controlled queue
+supporting priority based message enqueue and dequeue; modelled after
+ACE's message queue<br>
+ </li>
+ <li>timed_queue (coming): modelled after JavaSpace's "Lease on
+entries" mechanism; for each message inserted into queue, a time-out
+value will be specified; the message will be dropped if it is not
+consumed by receivers when its time-out expires.<br>
+ </li>
+</ul>
+<ul>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId573559"></a>5.2.4 executors<br>
+</h4>
+Executors allow us avoid explicitly spawning threads for asynchronous
+operations; thus avoiding thread life cycle overhead and resource
+consumption. &nbsp; Executors should support the following common
+interface to allow application register asynchronous operations to be
+executed later and cancel this registration:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename task_type&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+async_task_base * execute(task_type
+task);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool
+cancel(async_task_base *task);</span><br style="font-weight: bold;">
+<br>
+The following sample executors are provided:<br>
+<ul>
+ <li>in_place_executor:
+just run the asynchronous task in current
+thread and current calling context.<br>
+ </li>
+ <li>delayed_executor:
+asynchronous task is queued and calling thread
+returns. The queued tasks can be executed later by calling run().<br>
+ </li>
+ <li>asio_executor:
+a wrapper over asio's io_service.post() method.
+asynchronous tasks will be dispatched to asio's main thread to execute.<br>
+ </li>
+ <li><a
+ href="../../../boost/channel/executors/thread_pool_executor.hpp">thread_pool_executor</a>:
+a dedicated pool of threads executing
+submited tasks.</li>
+ <li>threadpool_executor:
+a wrapper over Philipp Henkel's <a
+ href="http://threadpool.sourceforge.net">threadpool</a> library<br>
+ </li>
+</ul>
+There are two places to plugin executors in framework:<br>
+<ul>
+ <li>channel-wide.</li>
+</ul>
+<div style="margin-left: 40px;">specifying an executor when channel is
+created. By default, all asynchronous operations (event/message
+callbacks, name binding callbacks,...) will be scheduled and executed
+in this executor.<br>
+</div>
+<ul>
+ <li>where callbacks are bound.</li>
+</ul>
+<div style="margin-left: 40px;">For example, some applications may want
+to give different priorities to handling different event ids (or
+message types). We can create several
+executors with their threads running in different scheduling priority;
+and specify proper executors when named_in and named_out are created.<br>
+</div>
+<h4><a class="mozTocH4" name="mozTocId872320"></a>5.3 connection related</h4>
+<h4><a class="mozTocH4" name="mozTocId460401"></a>5.3.1&nbsp; global
+functions for connecting channels </h4>
+There are 3 overloaded global functions for connecting channels:<br>
+<ul>
+ <li>one for connecting 2 local channels of the same type:</li>
+</ul>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename channel&gt;<br>
+typename channel::connection*
+connect(channel &amp;peer1, channel &amp;peer2,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; typename channel::binder_type *binder1 = NULL, </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; typename channel::binder_type *binder2 = NULL)</span><br
+ style="font-weight: bold;">
+connecting 2 local channels so that peers at both channels can
+communicate to each other transparently. binders1 (containing filter
+and translator) defines how channel peer1's name space will be changed.
+<br>
+</div>
+<ul>
+ <li>&nbsp;one for connecting 2 local channels of different types:</li>
+</ul>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename channel1, typename channel2&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+typename channel1::connection* connect(channel1 &amp;peer1, channel2
+&amp;peer2,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; typename channel1::binder_type *binder1 = NULL, </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; typename channel2::binder_type *binder2 = NULL);</span><br>
+<ul>
+ <li>one for connecting local channel
+to remote channels (streams):</li>
+</ul>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename channel, typename stream_t&gt;<br>
+connection*
+connect(channel &amp;peer, </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
+stream_t * stream, </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; bool
+active,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
+typename channel::binder_type *binder = NULL)<br>
+</span></div>
+<h4 style="margin-left: 40px;"><span class="mozTocH4"></span><span
+ class="mozTocH4"></span><span style="font-weight: normal;">Normally a
+connection to remote channel
+is represented as a "stream" objtect (tcp/ip socket connection or
+shared memory connection). This connect() function is used to connect a
+local channel to a remote channel represented by the stream.</span><br>
+</h4>
+<h4><a class="mozTocH4" name="mozTocId964803"></a>5.3.2 connection</h4>
+Class connection
+represent the connection between 2 channels. Deleting a connection
+object will break the connection between 2 channels; and deleting any
+of the member channels will result in connection object being
+deleted.&nbsp; <br>
+<h4><a class="mozTocH4" name="mozTocId581357"></a>5.3.3 peer and
+interface</h4>
+Class peer defines the
+common base class of connection proxies such as interface and streams.
+Normally application code will not need class peer, unless creating a
+new channel connection mechanism such as SOAP based streams.<br>
+Class interface is
+the proxy between its owner channel and a peer channel. It contains all
+the logic for how remote name space will be "mounted" at local name
+space and how local name space change will propagate to the remote name
+space and vice versa. It is here that filters filt message ids and
+translators translate incoming and outgoing messages<br>
+<h4><a class="mozTocH4" name="mozTocId567580"></a>5.3.4 streams</h4>
+Streams are proxies for remote channels and wrap transport mechanisms.
+The following streams are and will be provided:<br>
+<ul>
+ <li>asio_stream:
+a stream class using Boost.Asio socket to connect to peer channels.<br>
+ </li>
+ <ul>
+ <li>asio_connector:
+a helper class providing 2 functions:</li>
+ <ul>
+ <li>publishing local channels at specific ports (so that remote
+peer channel can connect)</li>
+ </ul>
+ </ul>
+</ul>
+<div style="margin-left: 120px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename sock_conn_handler&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+async_accept(int port, sock_conn_handler hndl) ;</span><br>
+</div>
+<ul>
+ <ul>
+ <ul>
+ <li>connecting to remote channels at their publication addresses
+(host, port):</li>
+ </ul>
+ </ul>
+</ul>
+<div style="margin-left: 120px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename sock_conn_handler&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+sync_connect(std::string host, std::string port, sock_conn_handler
+hndl) ;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename sock_conn_handler&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+async_connect(std::string host, std::string port, sock_conn_handler
+hndl) ;</span><br>
+</div>
+<ul>
+ <li>shmem_stream:
+a stream class using Boost.Interprocess shared memory message queues to
+connect to channels in a separate process inside the same node.<br>
+ </li>
+ <li>soap_stream (coming): use SOAP protocol to connect to remote
+channels<br>
+ </li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId711260"></a>5.3.5 marshaling
+registry</h4>
+<h4><a class="mozTocH4" name="mozTocId128213"></a>5.4 platform
+abstraction policy and synchronization policy<br>
+</h4>
+<h4><a class="mozTocH4" name="mozTocId345412"></a>5.4.1 platform
+abstraction</h4>
+Platform independence is one key factor for Channel's portability.
+Channel's internal implementation depends on some system facilities,
+such as
+mutex, condition, timers and logging. Various platforms have different
+levels of support and different APIs for these system facilities. Some
+boost libraries already provide nice wrappers over system facilities
+such as Boost.Thread and Boost.Date_Time. However for some system
+functions, boost doesn't have an approved library yet, such as logging.
+Class boost_platform
+is a platform policy class defined to support platform independence.
+All the system facilities Channel uses for internal implementation are
+either defined as nested classes wrapped inside it or its static
+methods. To port Channel to a different software/hardware platform, one
+major work is to reimplement the platform policy class using native
+functions (another is coping with compiler difference). Take logging
+for example, in future if we have a portable boost library for it, we
+could redefine boost_platform class to interface to it. Otherwise for a
+Windows specific application, we can implement platform class logging
+API using Windows event log facility; for linux based application, we
+can use syslog.<br>
+<h4><a class="mozTocH4" name="mozTocId405486"></a>5.4.2 synchronization
+policy</h4>
+Modeled after ACE's synchronization wrapper facades (ACE_Thread_Mutex,
+ACE_Null_Mutex, ACE_Null_Condition,...) and Null Object&nbsp; pattern,
+two "no-op" classes null_mutex and null_condition are defined. They
+follow the same interface as their counterparts in Boost.Thread and
+implement the methods as "no-op" inline functions, which can be
+optimized away by compilers. Also modeled after ACE's Synch_Strategy
+classes (MT_SYNCH, NULL_SYNCH) and Strategized Locking pattern, two
+synchronization policy classes are defined: <a
+ href="../../../boost/channel/platforms/synch_policy.hpp">mt_synch and
+null_synch</a>. mt_synch is for multithreaded applications which
+contains Boost.Thread's mutex/condition classes as nested types.
+null_synch is for single-threaded applications whose nested types are
+"null" types we mentioned above. synchronization policy class is one of
+channel template parameters which we can use either mt_synch for
+channel to be used in multithreaded application or use null_synch for
+single threaded application (such as event dispatching) without
+incurring overhead. The usage is different from the above mentioned
+platform independence, it is for application requirement and efficiency.<br>
+<br>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId283551"></a>6. Class Concepts and
+How to extend
+Channel framework</h3>
+One essential task of Generic Programming is to find the set of
+requirements for each class/type so that the template framework can
+compile and operate properly. These requirements are called "concepts"
+and include the following:<br>
+<ul>
+ <li>valid expressions</li>
+ <li>associated types</li>
+ <li>invariants</li>
+ <li>complexity guarantees</li>
+</ul>
+To extend Channel framework, new classes / types must satisfy the
+requirements of its "concept" so that code can compile and run.<br>
+In the following discussions, we classify 2 kinds of requirements:<br>
+<ul>
+ <li>Primary requirements: must be satisfied for the main framework
+design idea<br>
+ </li>
+ <li>Secondary requirements: should be satisfied per local
+implementations<br>
+ </li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId162285"></a>6.1 id_type and
+id_trait</h4>
+<ol>
+ <li>Primary requirements</li>
+</ol>
+<div style="margin-left: 40px;">For each id_type, a partially
+specialized template class id_trait should be defined with the
+following definitions:<br>
+<ul>
+ <li>nested/associated types: id_type</li>
+ <li>system internal message ids/names:</li>
+</ul>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static
+id_type channel_conn_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type channel_disconn_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type
+init_subscription_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type connection_ready_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type subscription_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type unsubscription_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type publication_info_msg;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static id_type unpublication_info_msg<br>
+</div>
+<ul>
+ <li>match() method: define the id-matching algorithm</li>
+ <li>serialize() method: marshaling/demarshaling method for passing id
+to remote channel (only need for user defined class / structs as
+id_type) &nbsp;&nbsp; <br>
+ </li>
+ <li>for the code to work in Windows/VC++, the class definition should
+contain BOOST_CHANNEL_DECL. </li>
+</ul>
+</div>
+<ol start="2">
+ <li>Secondary requirements</li>
+</ol>
+<div style="margin-left: 40px;">Per implementations, there are the
+following secondary requirements:<br>
+<ul>
+ <li>linear name space</li>
+</ul>
+<div style="margin-left: 40px;">Since current implementation use
+std::map to implement linear name space, user defined id_type must
+define the following methods to satisfy the requirements of std::map :<br>
+bool operator&lt; (const struct_id &amp;id) const<br>
+bool operator== (const struct_id &amp;id) const<br>
+bool operator!= (const struct_id &amp;id) const<br>
+</div>
+<ul>
+ <li>hierarchical name space</li>
+</ul>
+<div style="margin-left: 40px;">Hierarchical name space is implemented
+using trie data structure; to support trie related operations, id_trait
+should add the following definitions:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static token_type
+root_token;&nbsp;&nbsp;&nbsp;&nbsp; //just a name for root trie node,
+not in name_space<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static token_type wildcard_token;<br>
+&nbsp;&nbsp;&nbsp; &nbsp; static bool id1contains2(id_type id1, id_type
+id2)<br>
+<br>
+</div>
+</div>
+<div style="margin-left: 40px;">Here is <a href="assoc_id_text.html">a
+detailed description of how to add id_type and id_trait for associative
+name_space based on Linda-style associative lookup</a>.<a
+ href="assoc_id_text.html"></a><br>
+</div>
+<h4><a class="mozTocH4" name="mozTocId605583"></a>6.2 name space</h4>
+<ol>
+ <li>Primary requirements</li>
+</ol>
+<div style="margin-left: 40px;">
+<ul>
+ <li>nested/associated types:</li>
+</ul>
+<div style="margin-left: 40px;">id_type;<br>
+id_trait;<br>
+synch_policy;<br>
+executor;<br>
+platform;<br>
+name;<br>
+</div>
+<ul>
+ <li>name space management methods:</li>
+</ul>
+<div style="margin-left: 40px;">void bind_named_out(name *n)<br>
+void unbind_named_out(name *n)<br>
+void bind_named_in(name *n)<br>
+void unbind_named_in(name *n)<br>
+</div>
+</div>
+<ol start="2">
+ <li>Secondary requirements<br>
+ </li>
+</ol>
+<div style="margin-left: 40px;">name space query related:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template &lt;typename Predicate&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void bound_ids_for_in(Predicate p,
+std::vector&lt;id_type&gt; &amp;ids)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template &lt;typename Predicate&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void bound_ids_for_out(Predicate p,
+std::vector&lt;id_type&gt; &amp;ids)<br>
+executor_type * get_exec(void)<br>
+<br>
+</div>
+Please refer to <a
+ href="../../../boost/channel/name_spaces/linear_name_space.hpp">linear_name_space.hpp</a>
+and
+hierarchical_name_space.hpp
+for detailed code.<br>
+<h4><a class="mozTocH4" name="mozTocId379587"></a>6.3 dispatcher</h4>
+Dispatchers are used as policy classes for channel template. As
+discussed above, each dispatcher contains 2 algorithms: sending and
+receiving.<br>
+Dispatchers' API are not fixed, depending on whether it uses push or
+pull model and it is synchronous or asynchronous. The API of provided
+dispatchers follow the general convention of providing various
+send() and recv().
+<ol>
+ <li>Primary requirements</li>
+</ol>
+<div style="margin-left: 40px;">Each dispatcher class should define 2
+nested types:<br>
+<ul>
+ <li>sender </li>
+ <li>recver</li>
+</ul>
+These nested types are the parent classes of named_in and named_out.<br>
+Inside dispatcher nested types (sender and receiver classes),
+dispatching algorithms retrieve name binding set from associated "name"
+object.<br>
+</div>
+<ol start="2">
+ <li>Secondary requirements</li>
+</ol>
+<div style="margin-left: 40px;">For dispatchers which are used in
+channel types with possible remote connections, the nested receiver
+classes will expect the callback function's signature as :<br>
+&nbsp;&nbsp;&nbsp; void callback(id_type id,
+boost::shared_ptr&lt;void&gt; msg).<br>
+This requirement is because of the implementation of "interface" class.<br>
+<br>
+</div>
+Here is a <a href="../example/sample_dispatcher/dispatcher_text.html">detailed
+description of a
+sample pull dispatcher</a>.<br>
+<div style="margin-left: 40px;"></div>
+<h4><a class="mozTocH4" name="mozTocId872924"></a>6.4 executor</h4>
+<h4><a class="mozTocH4" name="mozTocId760775"></a>6.5 queue</h4>
+<h4><a class="mozTocH4" name="mozTocId441870"></a>6.6
+streams/connectors (or integrate into new architecture)</h4>
+<br>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId631535"></a>7. Compare Channel to
+others (plan9, STL)</h3>
+<h4><a class="mozTocH4" name="mozTocId547030"></a>7.1 Compare
+Unix/Plan9/Inferno file-system name space and Channel's name space</h4>
+In Unix and other OSes, file system provides the machine-wide
+hierarchical name space for most system resources. Applications
+use&nbsp; resources mostly by the standard file system calls:
+open/close/read/write. By mounting remote file-systems, remote name
+space (and resources) can be imported and accessed transparently by
+local applications.<br>
+Plan9/inferno push this idea further by 3 ideas: 1. all resources are
+represented as files. 2. each process has its own private name space
+which can be customized according to applications' requirements. 3. an
+uniform protocol - 9P is used for all remote message passings.[1][2]<br>
+<br>
+Channel provides a process local name space for asynchronous message
+passing and event dispatching. Compared to unix/plan9 name space:<br>
+<ul>
+ <li>Channel's name space is a light-weight user-space data structure;
+A process can create and use multiple name spaces for different
+purpose.
+Unix(plan9/inferno)'s name space is a more fundamental kernel feature
+well integrated with all system facilities (shell, window system,..).
+Each process has only one. </li>
+ <li>file-system name spaces are based on function-call (local or
+remote procedure call) or (request-response) semantics. Channel's name
+space is for asynchronous message passing or one way request.</li>
+ <li>file-system name spaces are based on normal client-server model:
+file servers purely serve; ie. clients will import names from servers,
+but servers never import names from clients. Channel is peer-peer
+model; connected channels will import names from each other for
+communication.</li>
+ <li>In file-system name spaces, names refer to assumely
+stable/permanent entites (either disk files or long-running servers);
+file name spaces are relatively static, ie, a specific name mostly
+refer to
+the same resource either local or from a specific server; operations on
+names with stale/empty binding will result in serious errors. Channel
+name spaces are purely dynamic. It is totally valid to have a Named_Out
+object in name space without bound Named_In object (since message
+subscribers may join in later). The binding of names (bound senders or
+receivers) can be different between this and next invocations. Just as
+RobinMilner has clarified [3]: &nbsp;&nbsp;&nbsp; <br>
+ </li>
+</ul>
+<div style="margin-left: 40px;">"... is built upon the idea that the
+respondent to (or referent of) a name<br>
+exists no more persistently than a caller of the name. In other words,
+the notions of<br>
+calling and responding are more basic than the notions of caller and
+respondent; every<br>
+activity contains calls and responses, but to have a persistent
+respondent to x &#8211; one that<br>
+responds similarly to every call on x &#8211; is a design choice that may be
+sensible but is<br>
+not forced."<br>
+</div>
+<ul>
+ <li>File-systems identify entities by string path names in a
+hierachical directories. Channel use different naming schemes in
+different applications:
+linear name space (such as integer ids), hierarchical name space (such
+as
+string path names), and associative name space (linda style)</li>
+ <li>in plan9, request dispatching is unicast - only one server get
+req and serve it. Channel can support various dispatching policies -
+broadcast, unicast, buffered,...</li>
+ <li>file-system api is stream oriented: byte-streams are read from
+file or write to file. channel's api is discrete message oriented.</li>
+</ul>
+<h4><a class="mozTocH4" name="mozTocId82643"></a>7.2 compare STL and
+Channel</h4>
+Some mapping between STL and Channel's concepts:<br>
+<ul>
+ <li>containers (sequence, assoc) &lt;=&gt; name spaces
+(linear/hier/assoc)</li>
+ <li>elements in container &lt;=&gt; names (unit/element in name space)</li>
+ <li>iterator_range (target of algorithms) &lt;=&gt; name binding set
+(sender-&gt;receiver(s), receiver-&gt;sender(s)) target of dispatchers</li>
+ <li>algorithms &lt;=&gt; dispatchers</li>
+</ul>
+Dispatchers are defined using named bindings of senders and receivers,
+which is provided by name space; similar to that STL algorithms are
+defined in iterator range of [begin_iterator, end_iterator), while
+iterator range is provided by containers.<br>
+<br>
+<hr style="width: 100%; height: 2px;">
+<h3><a class="mozTocH3" name="mozTocId802804"></a>8. Reference Links</h3>
+[1] <a href="http://plan9.bell-labs.com/sys/man/preface.html">Preface
+to the Second (1995) Edition (Doug McIlroy)</a><br>
+[2] <a href="http://cm.bell-labs.com/sys/doc/names.html">The Use of
+Name Spaces in Plan 9 (Rob Pike,...)</a><br>
+[3] <a href="http://www.cl.cam.ac.uk/%7Erm135/wosname.pdf">What's in a
+name? (Robin Milner)</a><br>
+[4] <a href="http://www.cl.cam.ac.uk/%7Erm135/turing.pdf">Turing,
+Computing and Communication (Robin Milner)</a><br>
+[5] <a
+ href="http://research.microsoft.com/Users/luca/Papers/Polyphony%20%28TOPLAS%29.pdf">Comega</a><br>
+[6] <a
+ href="http://research.microsoft.com/%7Etharris/scool/papers/sing.pdf">CCR</a><br>
+[7] Java's executor<br>
+[8] http://channel.sourceforge.net<br>
+<br>
+<br>
+<br>
+<platform_type><idtype ,executor_type,synchpolicy=""><name_space
+ ,platform_type=""></name_space></idtype></platform_type>
+</body>
+</html>

Added: sandbox/channel/libs/channel/doc/index.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/doc/index.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,213 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="keywords"
+ content="channel, namespace, distributed, communication, C++, template, Windows, Unix, Linux, NFS">
+ <meta name="description"
+ content="Channel - a C++ template framework for distributed computing.">
+ <title>Channel -- a C++ template framework for distributed message
+passing and event dispatching</title>
+ <link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+<div id="title">
+<h1> Channel </h1>
+<h2>A Name Space Based C++ Template Framework For Asynchronous
+Distributed Message
+Passing and Event Dispatching</h2>
+</div>
+<hr>
+<div class="link-bar"><small>Overview | <a
+ href="#boost"><span style="text-decoration: underline;">Boost Channel</span></a>
+| <span style="text-decoration: underline;"></span></small><small><a
+ href="#ace">ACE Channel</a></small><small>
+| <a href="#source"><span style="text-decoration: underline;">Download
+at Sourceforge</span></a> | Supported Platforms
+| Build | <a href="#contact">Contact /
+Support</a> </small>
+</div>
+<hr>
+<div>
+<h3><a id="intro">Overview</a></h3>
+<a id="intro">
+Channel is a C++ template library to provide name spaces for
+asynchronous, distributed message passing and event dispatching.
+Message senders and receivers bind to names in name space; binding and
+matching rules decide which senders will bind to which receivers; then
+message passing and event dispatching could happen among bound senders
+and receivers.<br>
+<br>
+Channel's signature:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; template &lt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename idtype,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename platform_type = boost_platform,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename synchpolicy = mt_synch&lt;platform_type&gt;,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename executor_type = abstract_executor, </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename name_space =
+linear_name_space&lt;idtype,executor_type,synchpolicy&gt;,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typename dispatcher =
+broadcast_dispatcher&lt;name_space,platform_type&gt; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; class
+channel;&nbsp;&nbsp; </span><br>
+<br>
+Various name spaces (linear/hierarchical/associative) can be used for
+different applications. For example, we can use integer ids as names to
+send messages in linear name space, we can use path name ids (such as
+"/sports/basketball") to send
+messages in hierarchical name space and we can use regex patterns or
+Linda tuple-space style tuples to send messages in associative name
+space; User can configure name space
+easily
+by setting a channel template parameter.<br>
+<br>
+Channel's other major components are dispatchers; which dispatch
+messages/events from senders to bounded receivers. Dispatcher is also a
+channel template parameter. </a>Sample dispatchers includes :
+synchronous broadcast dispatcher,
+buffered asynchronous dispatchers,...<br>
+<br>
+Name space and dispatchers are orthogonal; they can mix and match
+together freely; just as STL algorithms can be used with any STL
+containers. <br>
+<br>
+By combining different name space and dispatching policies, we can
+achieve various models:<br>
+<ul>
+ <li>synchronous event dispatching&nbsp;&nbsp;&nbsp; </li>
+ <li>associative name space based on matching/look-up rules similar to
+Linda tuple space</li>
+ <li>asynchronous messaging model similar to Microsoft CCR
+(Concurrency Coordination Runtime)<br>
+ </li>
+</ul>
+Similar to distributed files systems, distributed channels can be
+connected or "mounted" to allow transparent distributed message
+passing. Filters and translators are used to control name space changes.<br>
+<br>
+For tightly coupled single-address-space applications/modules,
+Channel's "unnamed" in/out
+objects : ports and signal/slots support fine grained and local message
+passing model without
+the hassle of setting up a name space and assigning names.<br>
+<hr style="width: 100%; height: 2px;">
+<h3><a name="boost"></a>Boost Channel</h3>
+Boost Channel is the latest implementation of Channel framework for
+Boost. Boost provides free
+peer-reviewed portable C++ source libraries. It is emphasized that
+libraries work well with the C++ Standard Library. Boost libraries are
+intended to be widely useful, and usable across a broad spectrum of
+applications. Boost Channel is solely based on standard boost
+facilities:<br>
+<ul>
+ <li>Boost::shared_ptr for message/event data life-time management</li>
+ <li>Boost.Bind, Boost.Function for callback</li>
+ <li>Boost.Thread for synchronization</li>
+ <li>Boost.Serialization for message marshaling/demarshaling</li>
+ <li>Boost.Regex and Boost.Tuple for associative name-matching<br>
+ </li>
+ <li><big><small>Boost.Asio and Boost.Shmem are used to build
+transports among remote channels.</small></big></li>
+</ul>
+Detailed Info:<br>
+<ul>
+ <li><a
+ href="http://channel.sourceforge.net/boost_channel/libs/channel/doc/design.html">Design
+Document</a></li>
+ <li><a
+ href="http://channel.cvs.sourceforge.net/channel/boost_channel/boost_channel/">Browse
+CVS Source Code</a><br>
+ </li>
+</ul>
+<ul>
+</ul>
+</div>
+<hr>
+<div>
+<h3><a name="ace"></a>ACE Channel</h3>
+ACE Channel is the first implementation of Channel framework on top of <a
+ href="http://www.cs.wustl.edu/%7Eschmidt/ACE.html">ACE (Adaptive
+Communication Environment) </a>. ACE is a
+powerful and portable OO/C++ framework for system programming. It
+provides not only wrapper facade classes to abstract the complete OS
+facilities, but also frameworks and design patterns for developing
+multithreaded and distributed applications. ACE Channel uses several
+key ACE facilities including Reactor,
+Service Configurator, Task and Acceptor-Connector.
+<ul>
+ <li><a href="http://channel.sourceforge.net/ace_index.html">Design
+Docs and more info...</a></li>
+ <li><a href="http://channel.cvs.sourceforge.net/channel/channel/">Browse
+CVS Source Code</a><br>
+ </li>
+</ul>
+<ul>
+</ul>
+</div>
+<hr>
+<div>
+<h3><a name="source"></a><a id="source">Source Code Download<br>
+</a></h3>
+<ul>
+ <li>Download</li>
+</ul>
+All released files are hosted at sf.net: <a
+ href="http://sourceforge.net/projects/channel">http://sourceforge.net/projects/channel>
+</div>
+<hr>
+<div>
+<div>
+<h3><a name="platform"></a><a id="source">Supported Platforms<br>
+</a></h3>
+Theoretically Boost Channel can work on any platforms where Boost is
+supported, since it is solely dependent on&nbsp; Boost
+facilities.&nbsp; Currently Boost Channel is being actively developed
+and tested in the
+following platforms:<br>
+<ul>
+ <li>Linux (Fedora, Ubuntu) with gcc</li>
+ <li>Windows XP with Visual C++ 2005 Express</li>
+</ul>
+It will be tested on other platforms (Solaris, NetBSD...) when time and
+resources are available.<br>
+</div>
+<hr>
+<h3><a name="build"></a><a id="source">Build<br>
+</a></h3>
+<a href="
http://www.boost.org/more/getting_started.html">checkout boost
+cvs source code</a><br>
+download latest boost_channel_x_x.tar.gz<br>
+tar xvzf boost_channel_x_x.tar.gz<br>
+cd &lt;top directory of channel&gt;<br>
+copy subdirectory boost/channel/ to &lt;boost
+root directory&gt;/boost/<br>
+copy subdirectory
+libs/channel/ to &lt;boost root directory&gt;/libs/<br>
+cd to &lt;boost root
+directory&gt;/libs/channel/exmaple/&lt;specific samples such as
+ping_pong&gt;<br>
+bjam
+<hr>
+<h3><a id="contact">Contact / Support</a></h3>
+yigongliu@gmail.com
+</div>
+<hr>
+<div class="footer"><small>This page is maintained by: <a
+ href="yigongliu_at_[hidden]">yigongliu_at_[hidden]</a></small>
+</div>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/buffered_async_join/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_async_join/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,50 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj chat_join.obj : chat_join.cpp ;
+exe chat_join : chat_join.obj ;
+obj chat_join2.obj : chat_join_2chan.cpp ;
+exe chat_join2 : chat_join2.obj ;
+obj chat_join_timer.obj : chat_join_timer.cpp ;
+exe chat_join_timer : chat_join_timer.obj ;

Added: sandbox/channel/libs/channel/example/buffered_async_join/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_async_join/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,77 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/channel/channel.hpp>
+#include <boost/channel/executors/thread_pool_executor.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef str_path_id<'/'> id_type;
+//use channel internal simple thread_pool_executor
+typedef thread_pool_executor<mt_synch<boost_platform> > exec_type;
+//use Philipp Henkel's threadpool library
+//#include <boost/channel/executors/threadpool_executor.hpp>
+//typedef threadpool_executor<> exec_type;
+typedef hierarchical_name_space<id_type,
+ exec_type,
+ mt_synch<boost_platform> > name_space_type;
+typedef pull_dispatcher<name_space_type,boost_platform,unbounded_que> dispatcher_type;
+typedef dispatcher_type::choice_async choice_arbiter_t;
+typedef dispatcher_type::join_async join_arbiter_t;
+//chat channel type to consume mesgs
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ exec_type,
+ name_space_type,
+ dispatcher_type
+ > chat_chan;
+//distribution channel type to distribute mesgs
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ exec_type,
+ name_space_type,
+ broadcast_dispatcher<name_space_type, boost_platform>
+> dist_chan;
+
+//sample subject ids in chat_chan
+//sports
+id_type basketball = "/sports/basketball";
+id_type tennis = "/sports/tennis";
+id_type baseball = "/sports/baseball";
+//financial
+id_type tax = "/financial/tax";
+id_type stock = "/financial/stock";
+id_type investment = "/financial/investment/";
+
+//a simple struct for chat msg
+struct chat_msg {
+ string data_;
+ chat_msg(char *d) : data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar & data_;
+ }
+};
+
+struct null_event {
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/buffered_async_join/chat_join.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_async_join/chat_join.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,120 @@
+//
+// chat_join.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void choice_msg_hdlr1(boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "choice_msg_hdlr1 recved: [" << msg->data_ << "]" << endl;
+}
+void choice_msg_hdlr2(boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "choice_msg_hdlr2 recved: [" << msg->data_ << "]" << endl;
+}
+
+void join_msg_hdlr(std::vector<boost::shared_ptr<void> >& p)
+{
+ cout << "join_msg_hdlr recved " << p.size() << "msgs:\n";
+ for(size_t i=0; i < p.size(); i++) {
+ cout << "msg " << i << ":";
+ chat_msg *msg = (chat_msg *) p[i].get();
+ cout << " [" << msg->data_ << "]" << endl;
+ }
+}
+
+int main(int, char **) {
+ //create executor with one thread
+ exec_type exec(1);
+
+ //create local channel and run all channel async operations inside executor
+ chat_chan chan(&exec);
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::out basketball_o(chan, basketball);
+ chat_chan::out tennis_o(chan, tennis);
+ chat_chan::out baseball_o(chan, baseball);
+ chat_chan::out tax_o(chan, tax);
+ chat_chan::out stock_o(chan, stock);
+ chat_chan::out investment_o(chan, investment);
+
+ //subscribe to sport msgs thru choice which will
+ //fire callback mesg handlers when any mesg arrives
+ choice_arbiter_t choice(chan);
+ choice.bind(basketball, choice_msg_hdlr1);
+ choice.bind(tennis, choice_msg_hdlr2);
+ choice.bind(baseball, choice_msg_hdlr1);
+
+ //subscribe to financial msgs thru join which will
+ //only fire the callback mesg handler when all subjects
+ //have messages arriving
+ join_arbiter_t join(chan, join_msg_hdlr);
+ join.bind(tax);
+ join.bind(stock);
+ join.bind(investment);
+
+ //start sending msgs and see how choice and join work differently
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-tennis, 3-baseball, 4-tax, 5-stock, 6-investment, 7-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ basketball_o.send(new chat_msg(msg));
+ break;
+ case 2:
+ tennis_o.send(new chat_msg(msg));
+ break;
+ case 3:
+ baseball_o.send(new chat_msg(msg));
+ break;
+ case 4:
+ tax_o.send(new chat_msg(msg));
+ break;
+ case 5:
+ stock_o.send(new chat_msg(msg));
+ break;
+ case 6:
+ investment_o.send(new chat_msg(msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 7:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ exec.shut_down_wait();
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/buffered_async_join/chat_join_2chan.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_async_join/chat_join_2chan.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,123 @@
+//
+// chat_join_2chan.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void choice_msg_hdlr1(boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "choice_msg_hdlr1 recved: [" << msg->data_ << "]" << endl;
+}
+void choice_msg_hdlr2(boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "choice_msg_hdlr2 recved: [" << msg->data_ << "]" << endl;
+}
+
+void join_msg_hdlr(std::vector<boost::shared_ptr<void> >& p)
+{
+ cout << "join_msg_hdlr recved " << p.size() << "msgs:\n";
+ for(size_t i=0; i < p.size(); i++) {
+ cout << "msg " << i << ":";
+ chat_msg *msg = (chat_msg *) p[i].get();
+ cout << " [" << msg->data_ << "]" << endl;
+ }
+}
+
+int main(int, char **) {
+ //create executor with one thread
+ exec_type exec(1);
+
+ //create local channel and run all channel async operations inside executor
+ chat_chan chan(&exec);
+ dist_chan chan0;
+
+ connect(chan0, chan);
+
+ //create/bind-to subjects i am going to speak about
+ dist_chan::out basketball_o(chan0, basketball);
+ dist_chan::out tennis_o(chan0, tennis);
+ dist_chan::out baseball_o(chan0, baseball);
+ dist_chan::out tax_o(chan0, tax);
+ dist_chan::out stock_o(chan0, stock);
+ dist_chan::out investment_o(chan0, investment);
+
+ //subscribe to sport msgs thru choice which will
+ //fire callback mesg handlers when any mesg arrives
+ choice_arbiter_t choice(chan);
+ choice.bind(basketball, choice_msg_hdlr1);
+ choice.bind(tennis, choice_msg_hdlr2);
+ choice.bind(baseball, choice_msg_hdlr1);
+
+ //subscribe to financial msgs thru join which will
+ //only fire the callback mesg handler when all subjects
+ //have messages arriving
+ join_arbiter_t join(chan, join_msg_hdlr);
+ join.bind(tax);
+ join.bind(stock);
+ join.bind(investment);
+
+ //start sending msgs and see how choice and join work differently
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-tennis, 3-baseball, 4-tax, 5-stock, 6-investment, 7-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ basketball_o.send(new chat_msg(msg));
+ break;
+ case 2:
+ tennis_o.send(new chat_msg(msg));
+ break;
+ case 3:
+ baseball_o.send(new chat_msg(msg));
+ break;
+ case 4:
+ tax_o.send(new chat_msg(msg));
+ break;
+ case 5:
+ stock_o.send(new chat_msg(msg));
+ break;
+ case 6:
+ investment_o.send(new chat_msg(msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 7:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ exec.shut_down_wait();
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/buffered_async_join/chat_join_timer.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_async_join/chat_join_timer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,160 @@
+//
+// chat_join_timer.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <vector>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include "./chat_defs.hpp"
+
+typedef chat_chan::port port_t;
+
+//timeout handler
+void timeout_hdlr(boost::shared_ptr<void> p)
+{
+ cout << "recv a timeout event at choice !" << endl;
+}
+//chat msg handler; print out data
+void choice_msg_hdlr1(boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "choice_msg_hdlr1 recved: [" << msg->data_ << "]" << endl;
+}
+void choice_msg_hdlr2(boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "choice_msg_hdlr2 recved: [" << msg->data_ << "]" << endl;
+}
+
+void join_msg_hdlr(std::vector<boost::shared_ptr<void> >& p)
+{
+ cout << "join_msg_hdlr recved " << p.size() << "msgs:\n";
+ for(size_t i=0; i < p.size(); i++) {
+ cout << "msg " << i << ":";
+ chat_msg *msg = (chat_msg *) p[i].get();
+ cout << " [" << msg->data_ << "]" << endl;
+ }
+}
+
+class my_timer
+{
+public:
+ my_timer(boost::asio::io_service& io, port_t &p)
+ : timer_(io, boost::posix_time::seconds(5)),
+ port_(p)
+ {
+ timer_.async_wait(boost::bind(&my_timer::timeout, this));
+ }
+
+ void timeout()
+ {
+ port_.send(new null_event); //send timeout notifications
+ timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(5));
+ timer_.async_wait(boost::bind(&my_timer::timeout, this));
+ }
+
+private:
+ boost::asio::deadline_timer timer_;
+ port_t &port_;
+};
+
+int main(int, char **) {
+ //create executor with one thread
+ exec_type exec(1);
+
+ //create local channel and run all channel async operations inside executor
+ chat_chan chan(&exec);
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::out basketball_o(chan, basketball);
+ chat_chan::out tennis_o(chan, tennis);
+ chat_chan::out baseball_o(chan, baseball);
+ chat_chan::out tax_o(chan, tax);
+ chat_chan::out stock_o(chan, stock);
+ chat_chan::out investment_o(chan, investment);
+
+ boost::asio::io_service io;
+ port_t timeout_port;
+ my_timer(io,timeout_port);
+ //spawn a thread to run timer
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
+
+ //subscribe to sport msgs thru choice which will
+ //fire callback mesg handlers when any mesg arrives
+ choice_arbiter_t choice(chan);
+ choice.bind(basketball, choice_msg_hdlr1);
+ choice.bind(tennis, choice_msg_hdlr2);
+ choice.bind(baseball, choice_msg_hdlr1);
+ choice.bind(timeout_port, timeout_hdlr);
+
+ //subscribe to financial msgs thru join which will
+ //only fire the callback mesg handler when all subjects
+ //have messages arriving
+ join_arbiter_t join(chan, join_msg_hdlr);
+ join.bind(tax);
+ join.bind(stock);
+ join.bind(investment);
+
+ //start sending msgs and see how choice and join work differently
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-tennis, 3-baseball, 4-tax, 5-stock, 6-investment, 7-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ basketball_o.send(new chat_msg(msg));
+ break;
+ case 2:
+ tennis_o.send(new chat_msg(msg));
+ break;
+ case 3:
+ baseball_o.send(new chat_msg(msg));
+ break;
+ case 4:
+ tax_o.send(new chat_msg(msg));
+ break;
+ case 5:
+ stock_o.send(new chat_msg(msg));
+ break;
+ case 6:
+ investment_o.send(new chat_msg(msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 7:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ exec.shut_down_wait();
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/buffered_async_join/sample6_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_async_join/sample6_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body>
+<h2>Sample 6: Buffered Channel With Asynchronous Receivers (choice,
+join synchronization patterns)</h2>
+<br>
+This sample shows a buffered channel support asynchronous receivers
+using asynchronous coordination patterns: choice and join. The callback
+actions are dispatched thru a thread pool executor.<br>
+<br>
+More comments to come ...<br>
+<br>
+Complete source code:<br>
+chat_defs.hpp<br>
+chat_join.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/buffered_sync_sendrecv/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_sync_sendrecv/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,46 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj sync_send_recv.obj : sync_send_recv.cpp ;
+exe sync_send_recv : sync_send_recv.obj ;

Added: sandbox/channel/libs/channel/example/buffered_sync_sendrecv/sample5_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_sync_sendrecv/sample5_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body>
+<h2>Sample 5:<span style="font-weight: bold;"> </span>Buffered Channel
+With Blocking Active Receiver
+</h2>
+<br>
+A sample shows the usage of buffered channels implemented thru a
+synchronous pull dispatcher. In this channel
+configuration, messages are buffered inside channel at sender side. The
+receiver is active, a thread blocking waiting for the arrival of
+messages at synchronous join/choice arbiters and then processing the
+messages.<br>
+<br>
+More comments to come...<br>
+<br>
+Complete source code:<br>
+sync_send_recv.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/buffered_sync_sendrecv/sync_send_recv.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/buffered_sync_sendrecv/sync_send_recv.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,87 @@
+//
+// sync_send_recv.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+//
+// demo of buffered synchronous dispatcher: ie. recver is blocking waiting for data to arrive
+//
+
+#include <iostream>
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef pull_dispatcher<linear_name_space<string, abstract_executor, mt_synch<boost_platform> >,
+ boost_platform> dispatcher_type;
+typedef channel<
+ string,
+ boost_platform,
+ mt_synch<boost_platform>,
+ abstract_executor,
+ linear_name_space<string, abstract_executor, mt_synch<boost_platform> >,
+ dispatcher_type
+> evt_chan;
+typedef dispatcher_type::choice_sync choice_type;
+
+//event ids in name_space
+//sample events for sending text
+string evt_id1 = "_1st_event_to_send_text_";
+string evt_id2 = "_2nd_event_to_send_text_";
+
+//a simple struct for event data
+struct evt_data {
+ string data_;
+ evt_data(const char *d) : data_(d) {}
+};
+
+//entry point function for recving thread; print out data
+void evt_recv(choice_type & recver)
+{
+ string id;
+ boost::shared_ptr<void> p;
+ while (1) {
+ recver.recv(id, p);
+ cout << "recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+}
+
+int main(int, char **) {
+ //create event channel
+ evt_chan chan;
+
+ //bind event source to channel
+ evt_chan::out sender1(chan, evt_id1);
+ evt_chan::out sender2(chan, evt_id2);
+
+ //bind event sink to channel
+ choice_type choice(chan);
+ choice.bind(evt_id1);
+ choice.bind(evt_id2);
+
+ //a separate thread to run recver
+ boost::thread t(boost::bind(evt_recv, boost::ref(choice)));
+
+ //main thread fire events
+ char msg[1024];
+ for(int i=0;;i++) {
+ cin.getline(msg, 1024);
+ if(i % 2 == 0)
+ sender1.send(new evt_data(msg));
+ else
+ sender2.send(new evt_data(msg));
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_assoc/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_assoc/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj chat1.obj : chat1.cpp ;
+exe chat1 : chat1.obj ;
+obj chat2.obj : chat2.cpp ;
+exe chat2 : chat2.obj ;

Added: sandbox/channel/libs/channel/example/chat_assoc/chat1.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_assoc/chat1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,104 @@
+//
+// chat1.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+int main(int, char **) {
+ const char *my_name = "chatter 1";
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channel and bind local event source/sink
+ chat_chan chan;
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::out robin_o(chan, robin_s_id);
+ chat_chan::out adam_o(chan, adam_s_id);
+ chat_chan::out tina_o(chan, tina_s_id);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::in smith_i(chan, smith_r_id, msg_handler);
+ chat_chan::in math_i(chan, math_r_id, msg_handler);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_connect("localhost", "8888", //remote channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which id : 1-(robin,smith,M,art), 2-(adam,smith,M,math), 3-(tina,su,F,physics), 4-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ robin_o.send(new chat_msg(my_name, msg));
+ break;
+ case 2:
+ adam_o.send(new chat_msg(my_name, msg));
+ break;
+ case 3:
+ tina_o.send(new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_assoc/chat2.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_assoc/chat2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,133 @@
+//
+// chat2.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan1: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+void msg_handler21(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan2.1: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+void msg_handler22(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan2.2: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+/**
+ * here we are going to use the publish/subscribe API built on top of
+ * named_in/named_out
+ */
+
+int main(int, char **) {
+ const char* my_name = "chatter 2";
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channels and connect them
+ chat_chan chan;
+ chat_chan chan2;
+ connect(chan, chan2);
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::publisher pub(chan);
+ pub.publish(adam_s_id);
+ pub.publish(robin_s_id);
+ pub.publish(tina_s_id);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::subscriber sub(chan, msg_handler);
+ //i am a sports fan
+ sub.subscribe(female_r_id);
+ sub.subscribe(robin_s_id);
+
+ //subscribe at chan2, using named_in/out api
+ chat_chan::in smith_i(chan2, smith_r_id, msg_handler21);
+ chat_chan::in math_i(chan2, math_r_id, msg_handler22);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_accept(8888, // channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ //in the following code, main thread will drive the interactive loop
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which id : 1-(robin,smith,M,art), 2-(adam,smith,M,math), 3-(tina,su,F,physics), 4-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ cout << "enter your message: ";
+ cin.getline(msg,1024);
+ switch (subject) {
+ case 1:
+ pub.send(robin_s_id, new chat_msg(my_name, msg));
+ break;
+ case 2:
+ pub.send(adam_s_id, new chat_msg(my_name, msg));
+ break;
+ case 3:
+ pub.send(tina_s_id, new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_assoc/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_assoc/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,95 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/tuple/tuple_io.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate channel type, define id_type
+/**
+ * using the following tuple fields to identify a person
+ * string - first name
+ * string - last name
+ * int - male(0), female(1)
+ * int - department: math(0), physics(1), art(2)...
+ */
+typedef boost::tuple<string, string, int, int> tuple_type;
+typedef tuple_id<tuple_type> id_type;
+
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ abstract_executor, //force in place execution
+ linear_name_space<id_type, abstract_executor, mt_synch<boost_platform>, false> ///false - assoc matching
+///broadcast dispatcher by default
+ > chat_chan;
+
+//sample subject ids in chat_chan
+//1. all msgs for student with last name "smith"
+id_type smith_r_id(tuple_type(
+ field_trait<string>::wildcard,
+ "smith",
+ field_trait<int>::wildcard,
+ field_trait<int>::wildcard));
+//2. all msgs for student in "math" department
+id_type math_r_id(tuple_type(
+ field_trait<string>::wildcard,
+ field_trait<string>::wildcard,
+ field_trait<int>::wildcard,
+ 0));
+//2. all msgs for female
+id_type female_r_id(tuple_type(
+ field_trait<string>::wildcard,
+ field_trait<string>::wildcard,
+ 1,
+ field_trait<int>::wildcard));
+//3. id for a specific person
+id_type robin_s_id(tuple_type(
+ "robin",
+ "smith",
+ 0,
+ 2));
+//4. id for a specific person
+id_type adam_s_id(tuple_type(
+ "adam",
+ "smith",
+ 0,
+ 0));
+//5. id for a specific person
+id_type tina_s_id(tuple_type(
+ "tina",
+ "su",
+ 1,
+ 1));
+
+//a simple struct for chat msg
+struct chat_msg {
+ string source_;
+ string data_;
+ chat_msg(const char *s, char *d) : source_(s), data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar &source_ & data_;
+ }
+};
+
+//define name space system ids
+DEFINE_ASSOC_SYS_IDS(tuple_type)
+
+#endif

Added: sandbox/channel/libs/channel/example/chat_assoc/sample10_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_assoc/sample10_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,240 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 10.&nbsp; channel using Linda-style associative lookup<br>
+</h2>
+This sample modifies chat_direct sample to show how we can pass
+messages and events among distributed processes based on Linda-style
+associative name lookup.<br>
+<br>
+Lets walk thru the code.<br>
+<br>
+All name space related types are defined in chat_defs.hpp.<br>
+<br>
+In Linda tuple space, each tuple consist of a set of fields. When
+tuples are read from tuple space, some fields can be set as wildcard
+and they can match any values. In Channel we can use tuples as
+names/ids in name space and similarly associative lookup will be used
+for
+name-matching. Please refer to <a href="../../doc/assoc_id_text.html">simple
+design doc</a> for more details. Boost.Tuple is used for tuple
+implementation, so &lt;boost/tuple.hpp&gt; is included.<br>
+<br>
+For this sample, we use the following tuple type with 4 fields:<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">typedef
+boost::tuple&lt;string, string, int, int&gt; tuple_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">typedef
+tuple_id&lt;tuple_type&gt; id_type;<br>
+</span></div>
+These 4 fields are used to identify a person:<br>
+&nbsp;*&nbsp; string - first name<br>
+&nbsp;*&nbsp; string - last name<br>
+&nbsp;*&nbsp; int&nbsp;&nbsp;&nbsp; - male(0), female(1)<br>
+&nbsp;*&nbsp; int&nbsp;&nbsp;&nbsp; - department: math(0), physics(1),
+art(2)...<br>
+Next we instantiate the channel type. A associative name space is
+implemented as a linear namespace with associative&nbsp; lookup. The
+lookup method is defined as the last template argument of
+linear_name_space class template. The default value "true" means "exact
+matching"; for "associative lookup" we set it to false.<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">typedef channel&lt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; id_type,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+boost_platform,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+mt_synch&lt;boost_platform&gt;,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+abstract_executor, //force in place execution</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+linear_name_space&lt;id_type, abstract_executor,
+mt_synch&lt;boost_platform&gt;, false&gt; ///false - assoc matching</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; &gt;
+chat_chan;</span><br>
+</div>
+<br>
+Next we define ids/names we are going to use in this application. They
+are names and attributes of persons we are interested. Two sets of ids
+are defined: ids for specific persons and ids for categories:<br>
+Ids for specific persons:<br>
+<div style="margin-left: 40px;">A person with name "robin smith", male
+and in department of "art"<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">id_type
+robin_s_id(tuple_type(</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "robin",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "smith",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 2));</span><br>
+</div>
+A person with name "adam smith", male and in department of "math"<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">id_type
+adam_s_id(tuple_type(</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "adam",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "smith",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0));</span><br>
+</div>
+A person with name "tina su", female and in department of "physics"<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">id_type
+tina_s_id(tuple_type(</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "tina",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "su",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1));</span><br>
+</div>
+</div>
+<span style="font-style: italic;"></span>Ids for categories:<br>
+<div style="margin-left: 40px;">Id for all people with last name "smith"<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">id_type
+smith_r_id(tuple_type(</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;string&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "smith",</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;int&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;int&gt;::wildcard));</span><br>
+</div>
+Id for all people in "math" department<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">id_type
+math_r_id(tuple_type(</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;string&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;string&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;int&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 0));</span><br>
+</div>
+Id for all female<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">id_type
+female_r_id(tuple_type(</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;string&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;string&gt;::wildcard,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 1,</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+field_trait&lt;int&gt;::wildcard));</span><br>
+</div>
+</div>
+<br>
+Next we define a simple structure for message data:<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">struct chat_msg {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; string
+source_;</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; string
+data_;</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+chat_msg(char *s, char *d) : source_(s), data_(d) {}</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+chat_msg() {} //have to define this for marshaling to work</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+//serialization function for chat_msg</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+template &lt;typename Archive&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; void
+serialize(Archive &amp; ar, const unsigned int version)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+ar &amp;source_ &amp; data_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">};</span><br>
+</div>
+<br>
+As a last step, we need to add the following macro to define the system
+internal messages (ugly):<br>
+<span style="font-style: italic; color: rgb(153, 0, 0);">DEFINE_ASSOC_SYS_IDS(tuple_type)
+</span><br>
+<br>
+The code in the peer process (chat1.cpp,
+chat2.cpp) are similar to
+other samples. We bind to names to send messages to distributed
+processes, except that we are using associative lookup for
+name-matching. So if application subscribe to <span
+ style="font-style: italic; color: rgb(153, 0, 0);">"smith_r_id", </span><span
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);">it
+will receive messages for both "robin smith" and "adam smith".</span></span><br>
+<br>
+Complete source code listing:<br>
+chat_defs.hpp<br>
+chat1.cpp<br>
+chat2.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/chat_direct/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_direct/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj chat1.obj : chat1.cpp ;
+exe chat1 : chat1.obj ;
+obj chat2.obj : chat2.cpp ;
+exe chat2 : chat2.obj ;

Added: sandbox/channel/libs/channel/example/chat_direct/chat1.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_direct/chat1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,107 @@
+//
+// chat1.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+int main(int, char **) {
+ char *my_name = "chatter 1";
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channel and bind local event source/sink
+ chat_chan chan;
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::out basketball_o(chan, basketball);
+ chat_chan::out tennis_o(chan, tennis);
+ chat_chan::out stock_o(chan, stock);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::in basketball_i(chan, basketball, msg_handler);
+ //i want hear all about financials
+ chat_chan::in all_financial_i(chan, all_financial, msg_handler);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_connect("localhost", "8888", //remote channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-tennis, 3-stock, 4-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ basketball_o.send(new chat_msg(my_name, msg));
+ break;
+ case 2:
+ tennis_o.send(new chat_msg(my_name, msg));
+ break;
+ case 3:
+ stock_o.send(new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ std::cout << "---1" << std::endl;
+ t.join();
+ std::cout << "---2" << std::endl;
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_direct/chat2.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_direct/chat2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,132 @@
+//
+// chat2.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan1: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+void msg_handler2(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan2: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+/**
+ * here we are going to use the publish/subscribe API built on top of
+ * named_in/named_out
+ */
+
+int main(int, char **) {
+ char* my_name = "chatter 2";
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channels and connect them
+ chat_chan chan;
+ chat_chan chan2;
+ connect(chan, chan2);
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::publisher pub(chan);
+ pub.publish(basketball);
+ pub.publish(baseball);
+ pub.publish(tax);
+ pub.publish(investment);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::subscriber sub(chan, msg_handler);
+ //i am a sports fan
+ sub.subscribe(all_sports);
+ sub.subscribe(stock);
+ sub.subscribe(tax);
+
+ //subscribe at chan2, using named_in/out api
+ chat_chan::in basketball_i(chan2, basketball, msg_handler2);
+ chat_chan::in all_financial_i(chan2, all_financial, msg_handler2);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_accept(8888, // channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ //in the following code, main thread will drive the interactive loop
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-base_ball, 3-tax, 4-investment, 5-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ cout << "enter your message: ";
+ cin.getline(msg,1024);
+ switch (subject) {
+ case 1:
+ pub.send(basketball, new chat_msg(my_name, msg));
+ break;
+ case 2:
+ pub.send(baseball, new chat_msg(my_name, msg));
+ break;
+ case 3:
+ pub.send(tax, new chat_msg(my_name, msg));
+ break;
+ case 4:
+ pub.send(investment, new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_direct/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_direct/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,55 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef str_path_id<'/'> id_type;
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ abstract_executor, //force in place execution
+ hierarchical_name_space<id_type, abstract_executor, mt_synch<boost_platform> >
+///broadcast dispatcher by default
+ > chat_chan;
+
+//sample subject ids in chat_chan
+//sports
+id_type basketball = "/sports/basketball";
+id_type tennis = "/sports/tennis";
+id_type baseball = "/sports/baseball";
+id_type all_sports = "/sports/*";
+//financial
+id_type tax = "/financial/tax";
+id_type stock = "/financial/stock";
+id_type investment = "/financial/investment/";
+id_type all_financial = "/financial/*";
+
+//a simple struct for chat msg
+struct chat_msg {
+ string source_;
+ string data_;
+ chat_msg(char *s, char *d) : source_(s), data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar &source_ & data_;
+ }
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/chat_direct/sample4_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_direct/sample4_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body>
+<h2>Sample 4: Chat with direct connection</h2>
+<br>
+This sample shows the usage of hierarchical namespace by defining chat
+subjects as string path names. Chat peers directly connect to
+each other, subscribing to the subjects they are interested and send
+messages with each other. Since it a hierarchical namespace, peers can
+subscribe to wildcard ids such as "all sports related subjects".<br>
+<br>
+More comments...<br>
+<br>
+Complete source code:<br>
+chat_defs.hpp<br>
+chat1.cpp<br>
+<a href="chat2.cpp">chat2.cpp<br>
+</a><br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/chat_regex/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_regex/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj chat1.obj : chat1.cpp ;
+exe chat1 : chat1.obj ;
+obj chat2.obj : chat2.cpp ;
+exe chat2 : chat2.obj ;

Added: sandbox/channel/libs/channel/example/chat_regex/chat1.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_regex/chat1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,107 @@
+//
+// chat1.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+int main(int, char **) {
+ char *my_name = "chatter 1";
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channel and bind local event source/sink
+ chat_chan chan;
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::out basketball_o(chan, basketball);
+ chat_chan::out tennis_o(chan, tennis);
+ chat_chan::out stock_o(chan, stock);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::in basketball_i(chan, basketball, msg_handler);
+ //i want hear all about financials
+ chat_chan::in all_financial_i(chan, all_financial, msg_handler);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_connect("localhost", "8888", //remote channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-tennis, 3-stock, 4-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ basketball_o.send(new chat_msg(my_name, msg));
+ break;
+ case 2:
+ tennis_o.send(new chat_msg(my_name, msg));
+ break;
+ case 3:
+ stock_o.send(new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ std::cout << "---1" << std::endl;
+ t.join();
+ std::cout << "---2" << std::endl;
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_regex/chat2.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_regex/chat2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,133 @@
+//
+// chat2.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan1: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+void msg_handler2(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan2: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+/**
+ * here we are going to use the publish/subscribe API built on top of
+ * named_in/named_out
+ */
+
+int main(int, char **) {
+ char* my_name = "chatter 2";
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channels and connect them
+ chat_chan chan;
+ chat_chan chan2;
+ connect(chan, chan2);
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::publisher pub(chan);
+ pub.publish(basketball);
+ pub.publish(baseball);
+ pub.publish(tax);
+ pub.publish(investment);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::subscriber sub(chan, msg_handler);
+ //i am a sports fan
+ sub.subscribe(all_balls);
+ sub.subscribe(tennis);
+ sub.subscribe(stock);
+ sub.subscribe(tax);
+
+ //subscribe at chan2, using named_in/out api
+ chat_chan::in basketball_i(chan2, basketball, msg_handler2);
+ chat_chan::in all_financial_i(chan2, all_financial, msg_handler2);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_accept(8888, // channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ //in the following code, main thread will drive the interactive loop
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-base_ball, 3-tax, 4-investment, 5-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ cout << "enter your message: ";
+ cin.getline(msg,1024);
+ switch (subject) {
+ case 1:
+ pub.send(basketball, new chat_msg(my_name, msg));
+ break;
+ case 2:
+ pub.send(baseball, new chat_msg(my_name, msg));
+ break;
+ case 3:
+ pub.send(tax, new chat_msg(my_name, msg));
+ break;
+ case 4:
+ pub.send(investment, new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_regex/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_regex/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,56 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/regex.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using regex_id as id_type
+typedef regex_id id_type;
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ abstract_executor, //force in place execution
+ linear_name_space<id_type, abstract_executor, mt_synch<boost_platform>, false> ///false - assoc matching
+///broadcast dispatcher by default
+ > chat_chan;
+
+//sample subject ids in chat_chan
+//sports
+id_type basketball = "[sports]: basketball";
+id_type tennis = "[sports]: tennis";
+id_type baseball = "[sports]: baseball";
+id_type all_balls(new boost::regex(".*ball.*"));
+//financial
+id_type tax = "[financial]: tax";
+id_type stock = "[financial]: stock";
+id_type investment = "[financial]: investment";
+id_type all_financial(new boost::regex(".*financial.*"));
+
+//a simple struct for chat msg
+struct chat_msg {
+ string source_;
+ string data_;
+ chat_msg(char *s, char *d) : source_(s), data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar &source_ & data_;
+ }
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/chat_regex/sample9_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_regex/sample9_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 9.&nbsp; channel using regex name matching<br>
+</h2>
+<br>
+This sample modifies chat_direct sample to show how we can pass
+messages and events among distributed processes based on regex name
+matching.<br>
+<br>
+Lets walk thru the code.<br>
+<br>
+All name space related types are defined in chat_defs.hpp.<br>
+<br>
+First we set regex_id to be the id_type. With regex_id, applications
+can use strings and regex patterns (Boost.Regex) as message ids and
+names (also we need to include &lt;boost/regex.hpp&gt;). <br>
+Next we instantiate the channel type. A associative name space is
+implemented as a linear namespace with associative&nbsp; lookup. The
+lookup method is defined as the last template argument of
+linear_name_space class template. The default value "true" means "exact
+matching"; for "associative lookup" we set it to false.<br>
+<div style="margin-left: 40px;"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">typedef regex_id
+id_type;</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">typedef
+channel&lt;</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; id_type,</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+boost_platform,</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+mt_synch&lt;boost_platform&gt;,</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+abstract_executor, //force in place execution</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+linear_name_space&lt;id_type, abstract_executor,
+mt_synch&lt;boost_platform&gt;, false&gt; ///false - assoc matching</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; &gt;
+chat_chan;</span><br>
+</div>
+Next we define ids/names we are going to use in this channel
+application. We define 2 sets of ids: plain text strings and&nbsp;
+regex patterns: <br>
+<div style="margin-left: 40px; background-color: rgb(255, 255, 255);"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">id_type basketball
+= "[sports]: basketball";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">id_type tennis
+= "[sports]: tennis";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">id_type
+baseball = "[sports]: baseball";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="font-style: italic; color: rgb(0, 0, 102);">id_type
+all_balls(new boost::regex(".*ball.*"));</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">id_type tax =
+"[financial]: tax";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">id_type stock
+= "[financial]: stock";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">id_type
+investment = "[financial]: investment";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="font-style: italic; color: rgb(0, 0, 102);">id_type
+all_financial(new boost::regex(".*financial.*"));</span><br
+ style="color: rgb(0, 0, 102);">
+</div>
+<br>
+Next we define a simple structure for message data:<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">struct chat_msg {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; string
+source_;</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; string
+data_;</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+chat_msg(char *s, char *d) : source_(s), data_(d) {}</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+chat_msg() {} //have to define this for marshaling to work</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+//serialization function for chat_msg</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+template &lt;typename Archive&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; void
+serialize(Archive &amp; ar, const unsigned int version)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+ar &amp;source_ &amp; data_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">};</span><br>
+</div>
+<br>
+The code in the peer process (chat1.cpp,
+chat2.cpp) are similar to
+other samples. We bind to names to send messages to distributed
+processes, except that
+we are using regex matching for name-matching. So if application
+subscribe to <span style="font-style: italic; color: rgb(153, 0, 0);">"all_balls",
+</span><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);">it will receive messages for both
+"basketball", "baseball" and any other balls.</span></span><br>
+<br>
+Complete source code listing:<br>
+chat_defs.hpp<br>
+chat1.cpp<br>
+chat2.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/chat_regex/test.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_regex/test.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,18 @@
+#include <string>
+#include <iostream>
+#include <boost/regex.hpp>
+
+using namespace std;
+using namespace boost;
+
+regex *re = new regex(".*ball.*");
+
+int main(int argc, char **argv) {
+ string s = "/sports/basketball";
+ regex rn(re->str(),re->flags());
+ if (regex_match(s,rn) == true) {
+ std::cout << "matched\n";
+ } else
+ std::cout << "not matched\n";
+ return 0;
+}

Added: sandbox/channel/libs/channel/example/chat_shmem/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_shmem/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj chat1.obj : chat1.cpp ;
+exe chat1 : chat1.obj ;
+obj chat2.obj : chat2.cpp ;
+exe chat2 : chat2.obj ;

Added: sandbox/channel/libs/channel/example/chat_shmem/chat1.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_shmem/chat1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,96 @@
+//
+// chat1.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/streams/shmem_stream.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:" << endl;
+ cout << msg->data_ << endl;
+}
+
+int main(int, char **) {
+ char *my_name = "chatter 1";
+ //create local channel and bind local event source/sink
+ chat_chan chan;
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::out basketball_o(chan, basketball);
+ chat_chan::out tennis_o(chan, tennis);
+ chat_chan::out stock_o(chan, stock);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::in basketball_i(chan, basketball, msg_handler);
+ //i want hear all about financials
+ chat_chan::in all_financial_i(chan, all_financial, msg_handler);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create shmem stream and connect to channel
+ //let the other side (chat2) create shmem, we jus open and use it
+ shmem_stream<
+ id_type,
+ chat_chan::text_marshaler_registry
+ >
+ shmstream(false, que_name, que_max_num, que_max_size, mar_reg);
+
+ //as active connection side, so we start connection handshaking
+ //inside shmem_stream, an internal thread will pump messages
+ connect(chan, &shmstream, true);
+
+ //in the following code, main thread will drive the interactive loop
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-tennis, 3-stock, 4-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ cout << "enter your message: ";
+ cin.getline(msg, 1024);
+ switch (subject) {
+ case 1:
+ basketball_o.send(new chat_msg(my_name, msg));
+ break;
+ case 2:
+ tennis_o.send(new chat_msg(my_name, msg));
+ break;
+ case 3:
+ stock_o.send(new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ shmstream.shutdown_wait();
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_shmem/chat2.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_shmem/chat2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,122 @@
+//
+// chat2.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include "./chat_defs.hpp"
+#include <boost/channel/streams/shmem_stream.hpp>
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan1: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:" << endl;
+ cout << msg->data_ << endl;
+}
+
+void msg_handler2(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << "chan2: " << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:" << endl;
+ cout << msg->data_ << endl;
+}
+
+/**
+ * here we are going to use the publish/subscribe API built on top of
+ * named_in/named_out
+ */
+
+int main(int, char **) {
+ char* my_name = "chatter 2";
+ //create local channels and connect them
+ chat_chan chan;
+ chat_chan chan2;
+ connect(chan, chan2);
+
+ //create/bind-to subjects i am going to speak about
+ chat_chan::publisher pub(chan);
+ pub.publish(basketball);
+ pub.publish(baseball);
+ pub.publish(tax);
+ pub.publish(investment);
+
+ //subscribe to subjects i am interested in listening
+ chat_chan::subscriber sub(chan, msg_handler);
+ //i am a sports fan
+ sub.subscribe(all_sports);
+ sub.subscribe(stock);
+ sub.subscribe(tax);
+
+ //subscribe at chan2, using named_in/out api
+ chat_chan::in basketball_i(chan2, basketball, msg_handler2);
+ chat_chan::in all_financial_i(chan2, all_financial, msg_handler2);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create shmem stream and connect to channel
+ //we'll create shmem msg_que and allow chat1 to connect
+ shmem_stream<
+ id_type,
+ chat_chan::text_marshaler_registry
+ >
+ shmstream(true, que_name, que_max_num, que_max_size, mar_reg);
+
+ //as passive conn side, we wait for chat1 to start connection handshaking
+ //inside shmem_stream, an internal thread will pump messages
+ connect(chan, &shmstream, false);
+
+ //in the following code, main thread will drive the interactive loop
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ //speak
+ cout << "which subject : 1-basket_ball, 2-base_ball, 3-tax, 4-investment, 5-exit:\n";
+ int subject;
+ cin.getline(msg, 1024);
+ subject = atoi(msg);
+ switch(subject) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ cout << "enter your message: ";
+ cin.getline(msg,1024);
+ switch (subject) {
+ case 1:
+ pub.send(basketball, new chat_msg(my_name, msg));
+ break;
+ case 2:
+ pub.send(baseball, new chat_msg(my_name, msg));
+ break;
+ case 3:
+ pub.send(tax, new chat_msg(my_name, msg));
+ break;
+ case 4:
+ pub.send(investment, new chat_msg(my_name, msg));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 5:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ shmstream.shutdown_wait();
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_shmem/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_shmem/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,59 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef str_path_id<'/'> id_type;
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ abstract_executor, //force in place execution
+ hierarchical_name_space<id_type, abstract_executor, mt_synch<boost_platform> >
+///broadcast dispatcher by default
+ > chat_chan;
+
+//sample subject ids in chat_chan
+//sports
+id_type basketball = "/sports/basketball";
+id_type tennis = "/sports/tennis";
+id_type baseball = "/sports/baseball";
+id_type all_sports = "/sports/*";
+//financial
+id_type tax = "/financial/tax";
+id_type stock = "/financial/stock";
+id_type investment = "/financial/investment/";
+id_type all_financial = "/financial/*";
+
+//a simple struct for chat msg
+struct chat_msg {
+ string source_;
+ string data_;
+ chat_msg(char *s, char *d) : source_(s), data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar &source_ & data_;
+ }
+};
+
+const char *que_name = "chat_shmem_que";
+int que_max_num = 100;
+int que_max_size = sizeof(chat_msg) + 1024 /* add some buffers for internal msgs */ ;
+
+#endif

Added: sandbox/channel/libs/channel/example/chat_shmem/sample8_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_shmem/sample8_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 8.&nbsp; channel
+connection thru shared memory</h2>
+<br>
+This sample shows that remote channels at 2 processes (chat1, chat2)
+can be connected thru shared memory message queues based on
+Boost.Interprocess.<br>
+<br>
+Boost.Interprocess provides rich facilities for intra-node
+inter-process communication, including message queues residing inside
+shared memory. Channel uses this shmem message queue as one of its
+transport among processes in the same node.<br>
+<br>
+Here is the code walk thru at one of peer process (chat1.cpp):<br>
+First we define a message handler function which just print out the
+received messages.<span style="color: rgb(153, 0, 0);"></span><br
+ style="color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);">void msg_handler(id_type id, boost::shared_ptr&lt;void&gt; p, int sz, timeout_type * t)</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);">{</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> chat_msg *msg = (chat_msg *) p.get();</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> cout &lt;&lt; msg-&gt;source_ &lt;&lt; " speak on [" &lt;&lt; chat_chan::id_trait::id_to_string(id) &lt;&lt; "]:\n";</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> cout &lt;&lt; msg-&gt;data_ &lt;&lt; "\n";</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);">}</span><br
+ style="color: rgb(153, 0, 0);"></pre>
+In the main function, we create channel; bind named_out to ids for
+sending messages; bind named_in to ids and message handler for handling
+incoming messages.<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);">int main(int, char **) {</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> char *my_name //create local channel and bind local event source/sink<br> chat_chan chan;<br><br> //create/bind-to subjects i am going to speak about<br> chat_chan::out basketball_o(chan, basketball);<br> chat_chan::out tennis_o(chan, tennis);<br> chat_chan::out stock_o(chan, stock);<br><br> //subscribe to subjects i am interested in listening<br> chat_chan::in basketball_i(chan, basketball, msg_handler);<br> //i want hear all about financials<br> chat_chan::in all_financial_i(chan, all_financial, msg_handler);<br></span></pre>
+register message type for marshaling/demarshaling:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> //register chat msg type for marshaling/demarshaling<br> chat_chan::text_marshaler_registry mar_reg;<br> mar_reg.register_default_msg_marshaler&lt;chat_msg&gt;();<br></span></pre>
+Next we create a "stream" based on shared memory message queue for
+connecting chat channel to remote channel in other processes. The 1st
+argument "false" means this process just open the share memory message
+queue and don't create it.<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> shmem_stream&lt;<br> id_type,<br> chat_chan::text_marshaler_registry,<br> timeout_type<br> &gt; <br> shmstream(false, que_name, que_max_num, que_max_size, mar_reg); //let the other side create shmem<br></span></pre>
+Then we connect channel to this shmem "stream" and this is the active
+side to start channel connection hand shaking.<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> connect(chan, &amp;shmstream, true); //active connection side<br></span></pre>
+Here comes the main loop for sending chat messages:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> char msg[1024];<br> bool cont = true;<br> while (cont) {<br> //speak<br> cout &lt;&lt; "which subject : 1-basket_ball, 2-tennis, 3-stock, 4-exit:\n";<br> int subject;<br> cin.getline(msg, 1024);<br> subject = atoi(msg);<br> switch(subject) {<br> case 1:<br> case 2:<br> case 3:<br> cout &lt;&lt; "enter your message: ";<br> cin.getline(msg, 1024);<br> switch (subject) {<br> case 1:<br> basketball_o.send(new chat_msg(my_name, msg));<br> break;<br> case 2:<br> tennis_o.send(new chat_msg(my_name, msg));<br> break;<br> case 3:<br> stock_o.send(new chat_msg(my_name, msg));<br> break;<br> default:<br> break;<br> }<br></span></pre>
+<br>
+Next we walk thru the code for 2nd peer process (chat2.cpp).
+Most code is
+similar to chat1.cpp, besides we have 2 local channels here.<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"><br>int main(int, char **) {<br> char* my_name = "chatter 2";<br> //create local channels and connect them<br> chat_chan chan;<br> chat_chan chan2;<br> connect(chan, chan2);<br><br> //create/bind-to subjects i am going to speak about<br> chat_chan::publisher pub(chan);<br> pub.publish(basketball);<br> pub.publish(baseball);<br> pub.publish(tax);<br> pub.publish(investment);<br> <br> //subscribe to subjects i am interested in listening<br> chat_chan::subscriber sub(chan, msg_handler);<br> //i am a sports fan<br> sub.subscribe(all_sports);<br> sub.subscribe(stock);<br> sub.subscribe(tax);<br><br> //subscribe at chan2, using named_in/out api<br> chat_chan::in basketball_i(chan2, basketball, msg_handler2);<br> chat_chan::in all_financial_i(chan2, all_financial, msg_handler2);<br><br> //register chat msg type for marshaling/demarshaling<br> chat_chan::text_marshaler_registry mar_reg;<br> mar_reg.register_default_msg_marshaler&lt;chat_msg&gt;();<br></span>
</pre>
+Here we create shared memory "stream" to connect to remote channel;
+notice that the 1st argument is "true", so the shared memory message
+queue will be created if it doesn't exist.<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> //create shmem stream and connect to channel<br> shmem_stream&lt;<br> id_type,<br> chat_chan::text_marshaler_registry,<br> timeout_type<br> &gt; <br> shmstream(true, que_name, que_max_num, que_max_size, mar_reg); //i'll create shmem<br> connect(chan, &amp;shmstream, false); //i am passive side</span><span
+ style="color: rgb(153, 0, 0);"><br></span></pre>
+<br>
+Complete source code listing:<br>
+chat_defs.hpp<br>
+chat1.cpp<br>
+chat2.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/chat_thru_server/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_thru_server/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj chat_cli.obj : chat_cli.cpp ;
+exe chat_cli : chat_cli.obj ;
+obj chat_srv.obj : chat_srv.cpp ;
+exe chat_srv : chat_srv.obj ;

Added: sandbox/channel/libs/channel/example/chat_thru_server/chat_cli.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_thru_server/chat_cli.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,112 @@
+//
+// chat_cli.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+int main(int argc, char **argv) {
+ if (argc < 4) {
+ std::cout << "Usage: chat_cli chatter_name srv_name srv_port\n";
+ exit(0);
+ }
+ const char *my_name = argv[1];
+ const char *srv_name = argv[2];
+ const char *srv_port = argv[3];
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create asio_executor and run callbacks in asio main thread
+ asio_executor asio_exec(io_service);
+ //create local channel
+ chat_chan chan(&asio_exec);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to chat server
+ asio_connector_async connector(io_service);
+ connector.async_connect(srv_name, srv_port,
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ //in main thread, we pub/sub subjects and send/recv msgs
+ chat_chan::publisher pub(chan);
+ chat_chan::subscriber sub(chan, msg_handler);
+
+ bool cont = true;
+ char buf[1024];
+ while (cont) {
+ cout << "action : 1-join, 2-leave, 3-send, 4-exit:\n";
+ int action;
+ cin.getline(buf, 1024);
+ action = atoi(buf);
+ switch (action) {
+ case 1:
+ case 2:
+ case 3:
+ {
+ cout << "subject: ";
+ cin.getline(buf, 1024);
+ id_type id(buf);
+ switch (action) {
+ case 1:
+ pub.publish(id);
+ sub.subscribe(id);
+ break;
+ case 2:
+ pub.unpublish(id);
+ sub.unsubscribe(id);
+ break;
+ case 3:
+ cout << "message: ";
+ cin.getline(buf, 1024);
+ pub.send(id, new chat_msg(my_name,buf));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case 4:
+ cont = false;
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_thru_server/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_thru_server/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,42 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/channel/channel.hpp>
+#include <boost/channel/executors/asio_executor.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef string id_type;
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ asio_executor //asynchronous channel
+ > chat_chan;
+
+//a simple struct for chat msg
+struct chat_msg {
+ string source_;
+ string data_;
+ chat_msg(const char *s, const char *d) : source_(s), data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar &source_ & data_;
+ }
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/chat_thru_server/chat_srv.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_thru_server/chat_srv.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,98 @@
+//
+// chat_srv.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat srv handler: update name space based clients' publications and subscriptions
+//and forward chat msgs
+class msg_handler {
+public:
+ chat_chan::publisher pub;
+ chat_chan::subscriber sub;
+ msg_handler(chat_chan &chan) :
+ pub(chan),
+ sub(chan,boost::bind(&msg_handler::handling, this, _1,_2))
+ {
+ //subscribe to name space change events
+ sub.subscribe(chat_chan::publication_info_msg, chat_chan::in::scope_remote);
+ }
+ void handling(id_type id, boost::shared_ptr<void> p)
+ {
+ typedef pubsub_info_msg_t<id_type> pubsub_info_msg_t;
+ pubsub_info_msg_t *pubsub_info = NULL;
+ if(id == chat_chan::publication_info_msg) {
+ pubsub_info = (pubsub_info_msg_t *) p.get();
+ for(std::vector<id_type>::iterator iter = pubsub_info->msg_types.begin();
+ iter != pubsub_info->msg_types.end(); iter++) {
+ pub.publish((*iter), chat_chan::in::scope_remote);
+ sub.subscribe((*iter), chat_chan::in::scope_remote);
+ }
+ }
+ else { //chat subject ids
+ //forward chat msgs to subscribers
+ pub.send(id, p);
+ }
+ }
+};
+
+
+/**
+ * here we are going to use the publish/subscribe API built on top of
+ * named_in/named_out
+ */
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ std::cout << "Usage: chat_srv srv_port\n";
+ exit(0);
+ }
+
+ const char * srv_port = argv[1];
+
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create asio_executor and run callbacks in asio main thread
+ asio_executor asio_exec(io_service);
+ //create local channel and run all its async operations in asio_exec
+ chat_chan chan(&asio_exec);
+
+ //pub/sub subjects and forard msgs
+ msg_handler handler(chan);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_accept(atoi(srv_port), // channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2,_3));
+
+ //main loop
+ io_service.run();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/chat_thru_server/sample7_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/chat_thru_server/sample7_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 7.&nbsp; distributed chat thru a central server</h2>
+This sample shows simple chat client and server design. Clients connect
+to server to chat with each other in seperate chat groups identified by
+subject. The chat subject (a string) is the ids in name space. Clients
+can join/leave chat groups identified by subject ids and send messages
+to chat groups. If the chat group (subject) doesn't exist yet, the
+first member's "join" will make it created; so unlimited number of
+subjects (thus chat groups) can be added to the name space.<br>
+<br>
+Here are code for chat client (chat_cli.cpp):<br>
+We first define the handler function for chat messages, simply print
+them out.<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);">void msg_handler(id_type id, boost::shared_ptr&lt;void&gt; p)<br>{<br> chat_msg *msg = (chat_msg *) p.get();<br> cout &lt;&lt; msg-&gt;source_ &lt;&lt; " speak on [" &lt;&lt; chat_chan::id_trait::id_to_string(id) &lt;&lt; "]:\n";<br> cout &lt;&lt; msg-&gt;data_ &lt;&lt; "\n";<br>}<br></pre>
+Chat clients start with 3 command line arguments: chatter's name,
+chat_server host name and port number:<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);">int main(int argc, char **argv) {<br> if (argc &lt; 4) {<br> std::cout &lt;&lt; "Usage: chat_cli chatter_name srv_name srv_port\n";<br> exit(0);<br> }<br> const char *my_name = argv[1];<br> const char *srv_name = argv[2];<br> const char *srv_port = argv[3];<br></pre>
+Next, we create ASIO io_service object; create a asio_executor object
+and create an asynchronous channel which will execute all its callbacks
+in asio_executor (in ASIO's main thread).<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> try {<br> boost::asio::io_service io_service;<br> asio_executor asio_exec(io_service);<br> chat_chan chan(&amp;asio_exec);<br></pre>
+Since chat messages will move from one client to server and to other
+subscribed clients, they need to be marshaled/demarshaled for
+transmission. Use channel's text_marshaler_registry which is based on
+Boost.Serialization. Since we only have one message data type, we can
+register its type as default (If we have more than one message data
+types, we can register the major one as default and register other with
+its corresponding ids.<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> chat_chan::text_marshaler_registry mar_reg;<br> mar_reg.register_default_msg_marshaler&lt;chat_msg&gt;();<br></pre>
+Connect chat channel to remote server as following and spawn a separate
+thread run ASIO's main loop:<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> asio_connector connector(io_service);<br> connector.async_connect(srv_name, srv_port, //remote channel address<br> boost::bind(asio_bind_sock_chan&lt;chat_chan, chat_chan::text_marshaler_registry&gt;(), <br> boost::ref(chan), boost::ref(mar_reg), _1, _2));<br> boost::thread t(boost::bind(&amp;boost::asio::io_service::run, &amp;io_service));<br></pre>
+In main thread, we handle chat clients main activities: join/leave
+chat_groups(subjects) and send/receive messages<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> chat_chan::publisher pub(chan);<br> chat_chan::subscriber sub(chan, msg_handler);<br><br> bool cont = true;<br> char buf[1024];<br> while (cont) {<br></pre>
+Clients can do 3 major things: join chat_group (subject), leave
+chat_group and send messages to chat_groups. If the chat group
+(subject) doesn't exist yet, the
+first member's "join" will make it created.
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> cout &lt;&lt; "action : 1-join, 2-leave, 3-send, 4-exit:\n";<br> int action;<br> cin.getline(buf, 1024);<br> action = atoi(buf);<br> switch (action) {<br> case 1:<br> case 2:<br> case 3:<br> {<br> cout &lt;&lt; "subject: ";<br> cin.getline(buf, 1024);<br> id_type id(buf);<br> switch (action) {<br> case 1:<br></pre>
+we join the chat_group by both publishing and subscribing the subject
+id:<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> pub.publish(id);<br> sub.subscribe(id);<br> break;<br> case 2:<br></pre>
+we leave the chat_group by both unpublishing and unsubscribing the
+subject id:
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> pub.unpublish(id);<br> sub.unsubscribe(id);<br> break;<br> case 3:<br></pre>
+clients send messages:<br>
+<pre
+ style="background-color: rgb(204, 204, 204); color: rgb(153, 0, 0);"> cout &lt;&lt; "message: ";<br> cin.getline(buf, 1024);<br> pub.send(id, new chat_msg(my_name,buf));<br> break;<br> default:<br> break;<br> }<br></pre>
+<br>
+Next let's step thru the server code (chat_srv.cpp).
+In
+normal chat server design based on basic socket, the chat server has 2
+main responsibilities: maintaining membership info (which clients are
+in which chat groups) and forwarding messages. Channel's facilities
+greatly simplifies the design and code of chat server.<br>
+First, channel has 4 internal system messages notifying about name
+space changes:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"> id_type subscription_info_msg;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> id_type unsubscription_info_msg;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> id_type publication_info_msg;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> id_type unpublication_info_msg;</span><br></pre>
+These internal system messages are defined inside id_trait class of
+channel type. Application code can bind to (or subscribe to) these
+system messages to get notified whenever name space changes (such as
+some peers join in and starts publishing and subscribing messages).<br>
+During chatting, whenever a client join a group (subject), it will
+publish/send messages on this subject and subscribe/receive messages on
+this subject. By subscribing to <span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);">publication_info_msg, chat servers can
+know when a client joins a group and the subject of this group. In the
+following msg_handler function, chat server does the following to
+fullfill its 2 responsibilities:<br>
+</span></span>
+<ul>
+ <li>When server receives name space change message (<span
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);">publication_info_msg):</span></span></li>
+ <ul>
+ <li>server retrieves ids from publication_info_msg and subscribes
+to these ids, so all of the messages
+about this subject (or in this group) will be sent to server</li>
+ <li>server publishes these subject ids, so all the clients which
+are
+in this group will be connected to server to receive messages in this
+group</li>
+ </ul>
+ <li>When server receives chat messages, just forward them<br>
+ </li>
+</ul>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);">void msg_handler(chat_chan::publisher &amp;pub,</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> chat_chan::subscriber &amp;sub,</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> id_type id, boost::shared_ptr&lt;void&gt; p, int sz, timeout_type * t)</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);">{</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> typedef pubsub_info_msg_t&lt;id_type&gt; pubsub_info_msg_t;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> pubsub_info_msg_t *pubsub_info = NULL;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> if(id == chat_chan::publication_info_msg) {</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> //update name space based clients' publications and subscriptions</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> //and forward chat msgs</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> pubsub_info = (pubsub_info_msg_t *) p.get();</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> for(std::vector&lt;id_type&gt;::iterator iter = pubsub_info-&gt;msg_types.begin();</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> iter != pubsub_info-&gt;msg_types.end(); iter++) {</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> pub.publish((*iter), chat_chan::in::scope_remote);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> sub.subscribe((*iter), chat_chan::in::scope_remote);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> }</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> }</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> else { //chat subject ids</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> //forward chat msgs to subscribers</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> pub.send(id, p, sz, t);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> }</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);">}<br></span></pre>
+Chat server's main function is simple, having port number as only
+argument:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);">int main(int argc, char **argv) {</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> if (argc &lt; 2) {</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> std::cout &lt;&lt; "Usage: chat_srv srv_port\n";</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> exit(0);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> }</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> </span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> const char * srv_port = argv[1];</span><br
+ style="color: rgb(153, 0, 0);"></pre>
+Similar to chat client code,&nbsp; we create an asynchronous channel
+with asio_executor:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"> try {</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> boost::asio::io_service io_service;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> asio_executor asio_exec(io_service);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> chat_chan chan(&amp;asio_exec);</span><br
+ style="color: rgb(153, 0, 0);"></pre>
+Next we create channel publisher and subscriber and bind message handler<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> chat_chan::publisher pub(chan);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> chat_chan::subscriber sub(chan, boost::bind(msg_handler, boost::ref(pub), </span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> boost::ref(sub), _1,_2));<br></span></pre>
+We subscribe to name space change message here then,<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"></span><span
+ style="color: rgb(153, 0, 0);"> </span><span
+ style="color: rgb(153, 0, 0);"> sub.subscribe(chat_chan::publication_info_msg, chat_chan::in::scope_remote);</span><br
+ style="color: rgb(153, 0, 0);"></pre>
+Then same as chat client, server create message marshaler,
+asio_connector and start waiting for remote clients connections:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="color: rgb(153, 0, 0);"> //register chat msg type for marshaling/demarshaling</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> chat_chan::text_marshaler_registry mar_reg;</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> mar_reg.register_default_msg_marshaler&lt;chat_msg&gt;();</span><br
+ style="color: rgb(153, 0, 0);"><br style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(153, 0, 0);"> //create asio connectors and connect to remote channel</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> asio_connector connector(io_service);</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> connector.async_accept(atoi(srv_port), // channel address</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> boost::bind(asio_bind_sock_chan&lt;chat_chan, chat_chan::text_marshaler_registry&gt;(), </span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> boost::ref(chan), boost::ref(mar_reg), _1, _2));</span><br
+ style="color: rgb(153, 0, 0);"><br style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(153, 0, 0);"> //main loop</span><br
+ style="color: rgb(153, 0, 0);"><span style="color: rgb(153, 0, 0);"> io_service.run();<br></span></pre>
+A sample scenario could be as following:<br>
+<ol>
+ <li>start chat server:&nbsp; ./chat_srv 4455<br>
+ </li>
+ <li>start 2 chat clients and connect to server: ./chat_cli steve
+localhost 4455 and ./chat_cli regean localhost 4455<br>
+ </li>
+ <li>join chat&nbsp; groups in clients</li>
+ <li>send messages to groups</li>
+</ol>
+Complete source code listing:<br>
+chat_defs.hpp<br>
+chat_cli.cpp<br>
+chat_srv.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/dist_evt_chan/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/dist_evt_chan/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj evt_chan1.obj : evt_chan1.cpp ;
+exe evt_chan1 : evt_chan1.obj ;
+obj evt_chan2.obj : evt_chan2.cpp ;
+exe evt_chan2 : evt_chan2.obj ;

Added: sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan1.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,141 @@
+//
+// evt_chan1.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include <boost/channel/executors/asio_executor.hpp>
+#include "./evt_chan_defs.hpp"
+
+class gui_window {
+ evt_chan & chan_;
+ //a few event src
+ evt_chan::out down_out_;
+ evt_chan::out up_out_;
+ evt_chan::out close_out_;
+ ///should wait for remote channel conneted and ids/names bound and
+ ///then fire some sample events
+ bool rmt_down_bound;
+ bool rmt_up_bound;
+ bool rmt_close_bound;
+public:
+ gui_window(evt_chan & c):
+ chan_(c),
+ down_out_(chan_,
+ down_id,
+ boost::bind(&gui_window::binding_callback, this, _1, _2)),
+ up_out_(chan_,
+ up_id,
+ boost::bind(&gui_window::binding_callback, this, _1, _2)),
+ close_out_(chan_,
+ close_id,
+ boost::bind(&gui_window::binding_callback, this, _1, _2)),
+ rmt_down_bound(false),rmt_up_bound(false),rmt_close_bound(false)
+ {
+ }
+
+ //methods to fire some events
+ void up(const char * msg) {
+ up_out_.send(new evt_data(msg));
+ }
+ void down(const char * msg) {
+ down_out_.send(new evt_data(msg));
+ }
+ void close(const char * msg) {
+ close_out_.send(new evt_data(msg));
+ }
+
+ void binding_callback(evt_chan::name *n, evt_chan::name::binding_event e) {
+ if (n->type_ == evt_chan::name::member_remote && e == evt_chan::name::bind_ev) {
+ if (n->id_ == down_id) rmt_down_bound = true;
+ if (n->id_ == up_id) rmt_up_bound = true;
+ if (n->id_ == close_id) rmt_close_bound = true;
+ ///fire sample events after remote peer connected and ids bound
+ if (rmt_down_bound && rmt_up_bound && rmt_close_bound) {
+ up("..Hi there [mouse-left-up] ..");
+ down(".. a simple window test [mouse-right-down] ..");
+ close(".. simple window wiered [window-closed] ..");
+ }
+ }
+ }
+};
+
+class window_handler {
+ evt_chan & ch_;
+ //a few event sinks
+ evt_chan::in *down_in_;
+ evt_chan::in *up_in_;
+ evt_chan::in *close_in_;
+public:
+ window_handler(evt_chan & c): ch_(c) {
+ down_in_ = ch_.bind_name_in(down_id, boost::bind(&window_handler::down, this, _1, _2));
+ up_in_ = ch_.bind_name_in(up_id, boost::bind(&window_handler::up, this, _1, _2));
+ close_in_ = ch_.bind_name_in(close_id, boost::bind(&window_handler::close, this, _1, _2));
+ }
+ ~window_handler() {
+ delete down_in_;
+ delete up_in_;
+ delete close_in_;
+ }
+
+ //methods to handle events
+ void down(string id, boost::shared_ptr<void> p) {
+ cout << "window_handler::DOWN ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+ void up(string id, boost::shared_ptr<void> p) {
+ cout << "window_handler::UP ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+ void close(string id, boost::shared_ptr<void> p) {
+ cout << "window_handler::CLOSE ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+};
+
+
+int main(int, char **) {
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create asio_executor
+ asio_executor asio_exec(io_service);
+ //create local channel and run all its async operations in asio_exec
+ evt_chan chan(&asio_exec);
+
+ //bind event source (window) to channel and register name_binding_callback
+ //so that when remote channel connected and name bound, we can start firing sample events
+ gui_window window(chan);
+ //bind event sink (handler) to channel
+ window_handler hdlr(chan);
+
+ //register event msg type for marshaling/demarshaling
+ evt_chan::text_marshaler_registry mar_reg;
+ std::vector<evt_chan::id_type> ids;
+ ids.push_back(down_id);
+ ids.push_back(up_id);
+ ids.push_back(close_id);
+ mar_reg.register_msg_marshaler<evt_data>(ids);
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_connect("localhost", "6666", //remote channel address
+ boost::bind(asio_bind_sock_chan<evt_chan, evt_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2,_3));
+ io_service.run();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan2.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,58 @@
+//
+// evt_chan2.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include <boost/channel/executors/asio_executor.hpp>
+#include "./evt_chan_defs.hpp"
+
+//free event handler; print out data
+void evt_handler(string id, boost::shared_ptr<void> p)
+{
+ cout << "free handler ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+}
+
+int main(int, char **) {
+ //create local event channel
+ evt_chan chan;
+ //bind event sinks to channel
+ evt_chan::in window_down_in(chan, down_id, evt_handler);
+ evt_chan::in window_up_in(chan, up_id, evt_handler);
+ evt_chan::in shut_down_in(chan, close_id, evt_handler);
+
+ //register event msg type for marshaling/demarshaling
+ evt_chan::text_marshaler_registry mar_reg;
+ std::vector<evt_chan::id_type> ids;
+ ids.push_back(down_id);
+ ids.push_back(up_id);
+ ids.push_back(close_id);
+ mar_reg.register_msg_marshaler<evt_data>(ids);
+
+ //create asio connectors and wait for remote conn to local channel
+ try {
+ boost::asio::io_service io_service;
+ asio_connector_async connector(io_service);
+ connector.async_accept(6666, //channel published at port 6666
+ boost::bind(asio_bind_sock_chan<evt_chan, evt_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2,_3));
+
+ io_service.run();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/dist_evt_chan/evt_chan_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,46 @@
+//
+// evt_chan_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef EVT_CHAN_DEFS_HPP
+#define EVT_CHAN_DEFS_HPP
+
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+//and execute all async operations in asio executor
+typedef channel<string,
+ boost_platform,
+ mt_synch<boost_platform>,
+ asio_executor> evt_chan;
+
+//event ids in name_space
+//sample events for a gui window
+string down_id = "_window_button_down_";
+string up_id = "_window_button_up_";
+string close_id = "_window_close_";
+
+//a simple struct for event data
+struct evt_data {
+ string data_;
+ evt_data(const char *d) : data_(d) {}
+ evt_data() {} //have to define this for marshaling to work
+ //serialization function for evt_data
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar & data_;
+ }
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/dist_evt_chan/sample3_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/dist_evt_chan/sample3_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,309 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body>
+<h2>Sample 3: Distributed Event Channel<br>
+</h2>
+<br>
+This sample is based on Sample1 with changes to show how remote
+channels can be connected to facilitate distributed events dispatching.<br>
+<br>
+Now we put the event source (gui_window) in one process with some local
+event sinks and connect it to another process which contains other
+event
+sinks. We are going to use Boost.Asio to set up tcp socket for remote
+connection transport.<br>
+<br>
+All major data types are defined in a common header file <a
+ href="evt_chan_defs.hpp">evt_chan_defs.hpp.</a><br>
+<br>
+First we need to instantiate the concrete channel class. Different from
+Sample1 and Sample2, we are going to make Channel <span
+ style="font-weight: bold;">asynchronous</span> which means that
+callbacks are not executed by the event sending thread directly (or in
+place). In stead callbacks will be scheduled and executed lated in an
+executor. For best integration with asio, Channel provides a special
+executor (asio_executor) to dispatch asynchronous operations to asio's
+main thread. So here is our channel type:<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">typedef
+channel&lt;string, </span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; boost_platform,</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; mt_synch&lt;boost_platform&gt;,</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; asio_executor&gt; evt_chan;</span><br>
+Channel's implementation depends on some system facilities, such as
+mutex, condition, timers. To facilitate platform independence, these
+facilties are defined as nested types inside "platform" wrapper class,
+such as boost_platform used here. mt_synch is synchronization policy
+class for thread safe operations, while another class
+null_synch&lt;&gt; contains empty "null" definitions of synchronization
+primitives and can be used for single threaded application.<br>
+<br>
+Next we define event ids and data structure the same as Sample1.<br>
+<br>
+Since we are doing distributed event dispatching now, the
+messages/event_data need be marshaled/demarshaled across process
+boundary. Channel uses Boost.Serialization for message marshaling. So
+the message class contains the following serialize() method:<br>
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">struct
+evt_data {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+string data_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+evt_data(const char *d) : data_(d) {}</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+evt_data() {} //have to define this for marshaling to work</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+//serialization function for evt_data</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+template &lt;typename Archive&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+void serialize(Archive &amp; ar, const unsigned int version)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+{</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;&nbsp;&nbsp;
+ar &amp; data_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">&nbsp;
+}</span><br
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">
+<span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">};</span><br>
+<br>
+In file evt_chan1.cpp,
+we first define event source (gui_window) and handler class
+(window_handler) the same as Sample1 and Sample2. <br>
+Next we introduce a major addition in this sameple - name binding
+callback. Since we are going to connect channels in 2 processes and
+send events to remote process, we must start sending events after the
+remote process connect in and bind to event ids. Otherwise events will
+be lost. Channel allows registering callbacks to
+names (named_in and named_out) so that application will be notified
+when
+remote peers connect in and bind. The following is the binding callback
+in this sample in which we start sending events after remote peers
+connect and bind:<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">void
+name_binding_callback(evt_chan::name *n, </span><span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">evt_chan::name::binding_event
+e) {</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;
+if (n-&gt;type_ == evt_chan::name::member_remote &amp;&amp; e ==
+evt_chan::name::bind_ev) {</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+if (n-&gt;id_ == down_id) rmt_down_bound = true;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+if (n-&gt;id_ == up_id) rmt_up_bound = true;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+if (n-&gt;id_ == close_id) rmt_close_bound = true;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+///fire sample events after remote peer connected and ids bound</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+if (rmt_down_bound &amp;&amp; rmt_up_bound &amp;&amp; rmt_close_bound) {</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+window-&gt;up("..Hi there [mouse-left-up] ..");</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+window-&gt;down(".. a simple window test [mouse-right-down] ..");</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+window-&gt;close(".. simple window wiered [window-closed] ..");</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;
+}</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">}</span><br>
+<br>
+Now the main function in evt_chan1.cpp:<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">int
+main(int, char **) {</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;
+try {</span><br>
+First we create asio io_service and asio_executor for asynchronous
+operations.<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+boost::asio::io_service io_service;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+asio_executor asio_exec(io_service);</span><br>
+Next create local channel and configure it to run all its async
+operations in asio_exec<br>
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+evt_chan chan(&amp;asio_exec);</span><br>
+Same as Sample1 and Sample2, create event source (gui_window) and
+handler and bind them to channel. Also name binding callback is
+registered when creating gui_window.<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+gui_window window(chan</span><span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+window_handler hdlr(chan);</span><br>
+Since event messages will be sent to remote process, they will be
+marshaled into on-wire format at sender side and demarshaled at
+receiver side. Channel's marshaling mechanism is based on
+Boost.Serialization. Here we register event/message data class
+(evt_data) with corresponding event ids in a marshaler registry inside
+which a marshaler object is created automatically for this data class.
+Later when socket connection is set up, we should specify the
+marshaler_registry to use:<br>
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+evt_chan::text_marshaler_registry mar_reg;</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+std::vector&lt;evt_chan::id_type&gt; ids;</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+ids.push_back(down_id);</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+ids.push_back(up_id);</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+ids.push_back(close_id);</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+mar_reg.register_msg_marshaler&lt;evt_data&gt;(ids);</span><br>
+Now we create asio connector and connect local channel to remote
+channel. Since we are using asynchronous API at asio, we pass in a
+callback (asio_bind_sock_chan) asking asio_connector to connect socket
+streams to local channel, including which marshaler_registry to use.
+Here in evt_chan1.cpp, asio connector plays the active connecting role.<br>
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+asio_connector connector(io_service);</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+connector.async_connect("localhost", "6666", //remote channel address</span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+boost::bind(asio_bind_sock_chan&lt;evt_chan,
+evt_chan::text_marshaler_registry&gt;(), </span><br
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">
+<span
+ style="color: rgb(204, 0, 0); font-weight: bold; font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; boost::ref(chan), boost::ref(mar_reg), _1, _2));<br>
+</span>Finally start asio main event loop.<br>
+<span style="color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+<span style="font-weight: bold; font-style: italic;">io_service.run();</span></span><br>
+<span style="color: rgb(204, 0, 0);">...</span><br
+ style="color: rgb(204, 0, 0);">
+<span style="color: rgb(204, 0, 0);">}</span><br>
+<br>
+In file evt_chan2.cpp,
+most code is similar to code in evt_chan1.cpp
+with one major difference: asio_connector plays the passive side of
+connection (accept):<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;
+try {</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+boost::asio::io_service io_service;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+asio_connector connector(io_service);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+connector.async_accept(6666, //channel published at port 6666</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+boost::bind(asio_bind_sock_chan&lt;evt_chan,
+evt_chan::text_marshaler_registry&gt;(), </span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; boost::ref(chan),
+boost::ref(mar_reg), _1, _2));</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;&nbsp;&nbsp;
+io_service.run();</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(204, 0, 0);">&nbsp;
+}</span><br>
+<br>
+During testing, first start evt_chan2 and then start evt_chan1. From
+trace, we should see the events generated at evt_chan1 received and
+processed at both evt_chan1 and evt_chan2 processes.<br>
+<br>
+Here are complete source listing:<br>
+evt_chan_defs.hpp<br>
+evt_chan1.cpp<br>
+evt_chan2.cpp<br>
+<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/filter_translator/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/filter_translator/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj cli.obj : cli.cpp ;
+exe cli : cli.obj ;
+obj srv.obj : srv.cpp ;
+exe srv : srv.obj ;

Added: sandbox/channel/libs/channel/example/filter_translator/chat_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/filter_translator/chat_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,86 @@
+//
+// chat_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#ifndef CHAT_DEFS_HPP
+#define CHAT_DEFS_HPP
+
+#include <string>
+#include <boost/channel/channel.hpp>
+#include <boost/channel/executors/asio_executor.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type
+typedef string id_type;
+typedef channel<
+ id_type,
+ boost_platform,
+ mt_synch<boost_platform>,
+ asio_executor //asynchronous channel
+ > chat_chan;
+
+class filter_t : public filter_type<string> {
+public:
+ string prefix;
+ filter_t(string pre) : prefix(pre) {}
+ bool block_inward (string &id) {
+ if (id.find(prefix) != 0) {
+ cout << "id [" << id << "] blocked at inward<" << prefix << ">" << endl;
+ return true;
+ }
+ return false;
+ }
+ bool block_outward (string &id) {
+ if (id.find(prefix) != 0) {
+ cout << "id [" << id << "] blocked at outward<" << prefix << ">" << endl;
+ return true;
+ }
+ return false;
+ }
+};
+
+class translator_t : public translator_type<string> {
+public:
+ string prefix;
+ translator_t(string pre) : prefix(pre) {}
+ void translate_inward (string & id) {
+ cout << "translate_inward : id[" << id << "] into [" ;
+ id = prefix + id;
+ cout << id << "]\n";
+ }
+ void translate_outward (string & id) {
+ cout << "translate_outward : id[" << id << "] into [" ;
+ id.erase(0,prefix.size());
+ cout << id << "]\n";
+ }
+};
+
+class binder : public binder_type<string> {
+public:
+ binder(string prefix) {
+ filter = new filter_t(prefix);
+ translator = new translator_t(prefix);
+ }
+};
+
+//a simple struct for chat msg
+struct chat_msg {
+ string source_;
+ string data_;
+ chat_msg(const char *s, const char *d) : source_(s), data_(d) {}
+ chat_msg() {} //have to define this for marshaling to work
+ //serialization function for chat_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar &source_ & data_;
+ }
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/filter_translator/cli.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/filter_translator/cli.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,112 @@
+//
+// cli.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat msg handler; print out data
+void msg_handler(id_type id, boost::shared_ptr<void> p)
+{
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+}
+
+int main(int argc, char **argv) {
+ if (argc < 4) {
+ std::cout << "Usage: cli chatter_name srv_name srv_port\n";
+ exit(0);
+ }
+ const char *my_name = argv[1];
+ const char *srv_name = argv[2];
+ const char *srv_port = argv[3];
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create asio_executor and run callbacks in asio main thread
+ asio_executor asio_exec(io_service);
+ //create local channel
+ chat_chan chan(&asio_exec);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to chat server
+ asio_connector_async connector(io_service);
+ connector.async_connect(srv_name, srv_port,
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ //in main thread, we pub/sub subjects and send/recv msgs
+ chat_chan::publisher pub(chan);
+ chat_chan::subscriber sub(chan, msg_handler);
+
+ bool cont = true;
+ char buf[1024];
+ while (cont) {
+ cout << "action : 1-add id, 2-del id, 3-send, 4-exit:\n";
+ int action;
+ cin.getline(buf, 1024);
+ action = atoi(buf);
+ switch (action) {
+ case 1:
+ case 2:
+ case 3:
+ {
+ cout << "id: ";
+ cin.getline(buf, 1024);
+ id_type id(buf);
+ switch (action) {
+ case 1:
+ pub.publish(id);
+ sub.subscribe(id);
+ break;
+ case 2:
+ pub.unpublish(id);
+ sub.unsubscribe(id);
+ break;
+ case 3:
+ cout << "message: ";
+ cin.getline(buf, 1024);
+ pub.send(id, new chat_msg(my_name,buf));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case 4:
+ cont = false;
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/filter_translator/sample11_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/filter_translator/sample11_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,248 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 11.&nbsp; channel name space management and security with
+filter and translator<br>
+</h2>
+Based on applications name space management requirements, we may need
+to "relocate"/"mount" the names imported (from a connection to a remote
+name space) to a specific sub-region in name space. For example, if we
+have a name space in desktop computer and connect to a PDA and a
+laptop, we can set translators at connections so that names imported
+from PDA will appear under "/pda/" and names from laptop will appear
+under "/laptop/". Or if our application use integer as ids/names, we
+may want to relocate ids from the 1st connection to [1000-1999] and ids
+from next connection to [2000-2999] and so on. That is similar to the
+way how we mount remote file-systems to local file-system.<br>
+Based on security requirements, we may need to use filters to restrict
+the valid range of names allowed to pass in/out specific channel
+connections. For example, a server's name space connect to 2 clients
+and we want that these clients' name spaces and messaging are totally
+separate, so that one client is unware of anything happening inside the
+other client's name space such as new name-publications and message
+passing. That is also similar to the way we protect network by
+firewalls and NATs.<br>
+<br>
+This sample uses a linear name space with strings as ids and implements
+a server which can connect to multiple clients. For each connection,
+the server will relocate the imported names to sub-region. For demo
+purpose, we simply put the names from clients under "/client0/...",
+"/client1/..."... and so on. So a name "basketball" in the first client
+will appear in server's name space as "/client0/basketball".<br>
+<br>
+First we define sample filter and translator in <a
+ href="./chat_defs.hpp">chat_defs.hpp</a>.<br>
+<br>
+When filter is created and bound for a connection,&nbsp; a prefix
+string ( such as "/client0/", "/client1/" ) is passed in . Then this
+filter will check name space change messages (init_subscription,
+publication/unpublication, subscription/unsubscription) to block
+names/ids which are not allowed; in our sample, valid names should
+begin with correct prefix. both input and output directions will be
+checked:<br>
+<div style="margin-left: 40px;"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">class filter_t :
+public filter_type&lt;string&gt; {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">public:</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; string
+prefix;</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+filter_t(string pre) : prefix(pre) {}</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; bool
+block_inward (string &amp;id) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+if (id.find(prefix) != 0) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; "id [" &lt;&lt; id &lt;&lt; "] blocked at inward&lt;"
+&lt;&lt; prefix &lt;&lt; "&gt;" &lt;&lt; endl;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return true;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+return false;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; }</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; bool
+block_outward (string &amp;id) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+if (id.find(prefix) != 0) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; "id [" &lt;&lt; id &lt;&lt; "] blocked at outward&lt;"
+&lt;&lt; prefix &lt;&lt; "&gt;" &lt;&lt; endl;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return true;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+}</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+return false;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; }</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">};</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<br>
+</div>
+When translator is created and bound for a connection,&nbsp; a prefix
+string (
+such as "/client0/", "/client1/" ) is passed in which designates where
+imported names will appear. Then both incoming and outgoing messages
+will be translated by the translator. In our simple demo, the
+translation is adding and removing of the prefix:<br>
+<div style="margin-left: 40px;"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">class translator_t
+: public translator_type&lt;string&gt; {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">public:</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; string
+prefix;</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+translator_t(string pre) : prefix(pre) {}</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; void
+translate_inward (string &amp; id) { </span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; "translate_inward : id[" &lt;&lt; id &lt;&lt; "] into [" ;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+id = prefix + id;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; id &lt;&lt;&nbsp; "]\n";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; }</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; void
+translate_outward (string &amp; id) { </span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; "translate_outward : id[" &lt;&lt; id &lt;&lt; "] into ["
+;</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+id.erase(0,prefix.size());</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; id &lt;&lt; "]\n";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; }</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">};</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<br>
+</div>
+A binder is just the combination of filter and translator.<br>
+<div style="margin-left: 40px;"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">class binder :
+public binder_type&lt;string&gt; {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">public:</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+binder(string prefix) {</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+filter = new filter_t(prefix);</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;&nbsp;&nbsp;
+translator = new translator_t(prefix);</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; }</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">};</span><br>
+</div>
+<br>
+Next lets see how filter and translator is set up in srv.cpp.<br>
+<br>
+In srv.cpp, we define the following callback function, so that a proper
+binder object will be created based on information about the connection
+(here we use information about socket). In real applications, we may
+need security provisions such as which range of ids/names are allowed
+for which remote connections. Here we simply relocate names for remote
+clients to "/client0/", "/client1/", etc.<br>
+<div style="margin-left: 40px;"><span
+ style="color: rgb(153, 0, 0); font-style: italic;">binder *
+binder_generator(boost::shared_ptr&lt;tcp::socket&gt; sock)</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">{</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;"></span><span
+ style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; static int
+num = 0;</span><br style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; string
+prefix = "/client";</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp;
+std::ostringstream os;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; os
+&lt;&lt; num;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; num++;</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">&nbsp; return
+new binder(prefix+os.str()+"/");</span><br
+ style="color: rgb(153, 0, 0); font-style: italic;">
+<span style="color: rgb(153, 0, 0); font-style: italic;">}<br>
+</span></div>
+<br>
+Next in srv.cpp when we accept connection from clients,
+binder_generator is passed in so that proper binder will be created and
+used for each new connection:<br>
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+connector.async_accept(atoi(srv_port), // channel address</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+boost::bind(asio_bind_sock_chan&lt;chat_chan,
+chat_chan::text_marshaler_registry&gt;(&amp;binder_generator), </span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; boost::ref(chan),
+boost::ref(mar_reg), _1, _2,_3));</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<br>
+A sample session could be as following:<br>
+1. start server<br>
+&nbsp;&nbsp;&nbsp; srv 8888<br>
+2. start first client (test1)<br>
+&nbsp;&nbsp;&nbsp; cli test1 localhost 8888<br>
+3. start 2nd client (test2)<br>
+&nbsp;&nbsp;&nbsp; cli test2 localhost 8888<br>
+4. in test1, add a new id/name such as "fishing"; from server's log,
+we'll see it appears in server's namespace as "/client0/fishing";<br>
+&nbsp;&nbsp;&nbsp; in test1, we can use "fishing" to send message to
+server, while at server we need to use "/client0/fishing" to send
+message to &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+test1.<br>
+5. in test2, add a new id/name such as "reading"; from server's log,
+we'll see it appears in server's namespace as "/client1/reading";<br>
+&nbsp;&nbsp;&nbsp; in test2, we can use "reading" to send message to
+server, while at
+server we need to use "/client1/reading" to send message to
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; test2.<br>
+6. notice that test1 is not aware of what is happening with test2 and
+vice versa.<br>
+<br>
+Complete source code listing:<br>
+chat_defs.hpp<br>
+cli.cpp<br>
+srv.cpp<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/filter_translator/srv.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/filter_translator/srv.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,155 @@
+//
+// srv.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <sstream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./chat_defs.hpp"
+
+//chat srv handler: update name space based clients' publications and subscriptions
+//and forward chat msgs
+class msg_handler {
+public:
+ chat_chan::publisher pub;
+ chat_chan::subscriber sub;
+ msg_handler(chat_chan &chan) :
+ pub(chan),
+ sub(chan,boost::bind(&msg_handler::handling, this, _1,_2))
+ {
+ //subscribe to name space change events
+ sub.subscribe(chat_chan::publication_info_msg, chat_chan::in::scope_remote);
+ }
+ void handling(id_type id, boost::shared_ptr<void> p)
+ {
+ typedef pubsub_info_msg_t<id_type> pubsub_info_msg_t;
+ pubsub_info_msg_t *pubsub_info = NULL;
+ if(id == chat_chan::publication_info_msg) {
+ pubsub_info = (pubsub_info_msg_t *) p.get();
+ for(std::vector<id_type>::iterator iter = pubsub_info->msg_types.begin();
+ iter != pubsub_info->msg_types.end(); iter++) {
+ cout << "server pub/sub to " << (*iter) << endl;
+ pub.publish((*iter), chat_chan::in::scope_remote);
+ sub.subscribe((*iter), chat_chan::in::scope_remote);
+ }
+ }
+ else if(id == chat_chan::unpublication_info_msg) {
+ pubsub_info = (pubsub_info_msg_t *) p.get();
+ for(std::vector<id_type>::iterator iter = pubsub_info->msg_types.begin();
+ iter != pubsub_info->msg_types.end(); iter++) {
+ pub.unpublish((*iter));
+ sub.unsubscribe((*iter));
+ }
+ }
+ else { //chat subject ids
+ chat_msg *msg = (chat_msg *) p.get();
+ cout << msg->source_ << " speak on [" << chat_chan::id_trait::id_to_string(id) << "]:\n";
+ cout << msg->data_ << endl;
+ }
+ }
+};
+
+/**
+ * binder_generator : based on security requirement and name_space management req
+ * we can use diff binders (filter & translator) for diff sock conn
+ */
+binder * binder_generator(boost::shared_ptr<tcp::socket> sock)
+{
+ //in real application we may create binders based on remote ip address
+ //here we just do simple
+ static int num = 0;
+ string prefix = "/client";
+ std::ostringstream os;
+ os << num;
+ num++;
+ return new binder(prefix+os.str()+"/");
+}
+
+/**
+ * here we are going to use the publish/subscribe API built on top of
+ * named_in/named_out
+ */
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ std::cout << "Usage: chat_srv srv_port\n";
+ exit(0);
+ }
+
+ const char * my_name = "server";
+ const char * srv_port = argv[1];
+
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create asio_executor and run callbacks in asio main thread
+ asio_executor asio_exec(io_service);
+ //create local channel and run all its async operations in asio_exec
+ chat_chan chan(&asio_exec);
+
+ //pub/sub subjects and forard msgs
+ msg_handler handler(chan);
+
+ //register chat msg type for marshaling/demarshaling
+ chat_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<chat_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_accept(atoi(srv_port), // channel address
+ boost::bind(asio_bind_sock_chan<chat_chan, chat_chan::text_marshaler_registry>(&binder_generator),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2,_3));
+
+
+ //a separate thread to run io_service
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ bool cont = true;
+ char buf[1024];
+ while (cont) {
+ cout << "action : 1-send, 2-exit:\n";
+ int action;
+ cin.getline(buf, 1024);
+ action = atoi(buf);
+ switch (action) {
+ case 1:
+ {
+ cout << "subject: ";
+ cin.getline(buf, 1024);
+ id_type id(buf);
+ cout << "message: ";
+ cin.getline(buf, 1024);
+ handler.pub.send(id, new chat_msg(my_name,buf));
+ }
+ break;
+ case 2:
+ cont = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ connector.shutdown();
+ t.join();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/gui_evt/Jamfile
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/Jamfile 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,42 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+
+subproject libs/channel/example/gui_evt ;
+
+project boost : $(BOOST_ROOT) ;
+
+if $(UNIX)
+{
+ switch $(JAMUNAME)
+ {
+ case SunOS* :
+ {
+ SOCKET_LIBS = <find-library>socket <find-library>nsl ;
+ }
+ }
+}
+
+template example_options
+ : <lib>@boost/libs/channel/build/boost_channel
+ <lib>@boost/libs/serialization/build/boost_serialization
+ <lib>@boost/libs/thread/build/boost_thread
+ : <include>$(BOOST_ROOT)
+ <include>../../../..
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <mingw><*><find-library>ws2_32
+ <mingw><*><find-library>mswsock
+ $(SOCKET_LIBS)
+ ;
+
+exe gui_evt_chan1 : <template>example_options gui_evt_chan1.cpp ;
+exe gui_evt_chan2 : <template>example_options gui_evt_chan2.cpp ;
+exe gui_evt3 : <template>example_options gui_evt3.cpp ;

Added: sandbox/channel/libs/channel/example/gui_evt/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,49 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj gui_evt_chan1.obj : gui_evt_chan1.cpp ;
+exe gui_evt_chan1 : gui_evt_chan1.obj ;
+obj gui_evt_chan2.obj : gui_evt_chan2.cpp ;
+exe gui_evt_chan2 : gui_evt_chan2.obj ;
+obj gui_evt3.obj : gui_evt3.cpp ;
+exe gui_evt3 : gui_evt3.obj ;

Added: sandbox/channel/libs/channel/example/gui_evt/gui_evt3.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/gui_evt3.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,103 @@
+//
+// gui_evt3.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef signal<> signal_type;
+typedef signal_type::slot slot_type;
+
+//a simple struct for event data
+struct evt_data {
+ string data_;
+ evt_data(const char *d) : data_(d) {}
+};
+
+class gui_window {
+public:
+ //a few event src
+ signal_type down_;
+ signal_type up_;
+ signal_type close_;
+
+ gui_window(): down_(),
+ up_(),
+ close_() {}
+ //methods to fire some events
+ void up(const char * msg) {
+ up_.send(new evt_data(msg));
+ }
+ void down(const char * msg) {
+ down_.send(new evt_data(msg));
+ }
+ void close(const char * msg) {
+ close_.send(new evt_data(msg));
+ }
+};
+
+class window_handler {
+ gui_window & win_;
+ slot_type *down_slot, *up_slot, *close_slot;
+public:
+ window_handler(gui_window & w): win_(w) {
+ down_slot = win_.down_.bind(boost::bind(&window_handler::down, this, _1));
+ up_slot = win_.up_.bind(boost::bind(&window_handler::up, this, _1));
+ close_slot = win_.close_.bind(boost::bind(&window_handler::close, this, _1));
+ }
+ ~window_handler() {
+ delete down_slot;
+ delete up_slot;
+ delete close_slot;
+ }
+ //methods to handle events
+ void down(boost::shared_ptr<void> p) {
+ cout << "window_handler::DOWN ... recv [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+ void up(boost::shared_ptr<void> p) {
+ cout << "window_handler::UP ... recv [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+ void close(boost::shared_ptr<void> p) {
+ cout << "window_handler::CLOSE ... recv [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+};
+
+
+//free event handler; print out data
+void evt_handler(boost::shared_ptr<void> p)
+{
+ cout << "free handler ... recv event [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+}
+
+int main(int, char **) {
+ //bind event source (window) to channel
+ gui_window window;
+
+ //bind event sink (handler) to channel
+ window_handler hdlr(window);
+
+ //bind more event sinks
+ window.down_.bind(evt_handler);
+ window.up_.bind(evt_handler);
+ window.close_.bind(evt_handler);
+
+ //fire events
+ window.up("..Hi there [mouse-left-up] ..");
+ window.down(".. a simple window test [mouse-right-down] ..");
+ window.close(".. simple window wiered [window-closed] ..");
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/gui_evt/gui_evt_chan1.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/gui_evt_chan1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,116 @@
+//
+// gui_evt_chan1.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <iostream>
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef channel<string> evt_chan;
+
+//event ids in name_space
+//sample events for a gui window
+string down_id = "_window_button_down_";
+string up_id = "_window_button_up_";
+string close_id = "_window_close_";
+
+//a simple struct for event data
+struct evt_data {
+ string data_;
+ evt_data(const char *d) : data_(d) {}
+};
+
+class gui_window {
+ evt_chan & chan_;
+ //a few event src
+ evt_chan::out down_out_;
+ evt_chan::out up_out_;
+ evt_chan::out close_out_;
+public:
+ gui_window(evt_chan & c): chan_(c),
+ down_out_(chan_, down_id),
+ up_out_(chan_, up_id),
+ close_out_(chan_, close_id) {}
+ //methods to fire some events
+ void up(const char * msg) {
+ up_out_.send(new evt_data(msg));
+ }
+ void down(const char * msg) {
+ down_out_.send(new evt_data(msg));
+ }
+ void close(const char * msg) {
+ close_out_.send(new evt_data(msg));
+ }
+};
+
+class window_handler {
+ evt_chan & ch_;
+ //a few event sinks
+ evt_chan::in *down_in_;
+ evt_chan::in *up_in_;
+ evt_chan::in *close_in_;
+public:
+ window_handler(evt_chan & c): ch_(c) {
+ down_in_ = ch_.bind_name_in(down_id, boost::bind(&window_handler::down, this, _1, _2));
+ up_in_ = ch_.bind_name_in(up_id, boost::bind(&window_handler::up, this, _1, _2));
+ close_in_ = ch_.bind_name_in(close_id, boost::bind(&window_handler::close, this, _1, _2));
+ }
+ ~window_handler() {
+ delete down_in_;
+ delete up_in_;
+ delete close_in_;
+ }
+ //methods to handle events
+ void down(string id, boost::shared_ptr<void> p) {
+ cout << "window_handler::DOWN ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+ void up(string id, boost::shared_ptr<void> p) {
+ cout << "window_handler::UP ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+ void close(string id, boost::shared_ptr<void> p) {
+ cout << "window_handler::CLOSE ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+ }
+};
+
+
+//free event handler; print out data
+void evt_handler(string id, boost::shared_ptr<void> p)
+{
+ cout << "free handler ... recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]" << endl;
+}
+
+int main(int, char **) {
+ //create event channel
+ evt_chan chan;
+
+ //bind event source (window) to channel
+ gui_window window(chan);
+
+ //bind event sink (handler) to channel
+ window_handler hdlr(chan);
+
+ //bind more event sinks
+ evt_chan::in window_down_in(chan, down_id, evt_handler);
+ evt_chan::in window_up_in(chan, up_id, evt_handler);
+ evt_chan::in shut_down_in(chan, close_id, evt_handler);
+
+ //fire events
+ window.up("..Hi there [mouse-left-up] ..");
+ window.down(".. a simple window test [mouse-right-down] ..");
+ window.close(".. simple window wiered [window-closed] ..");
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/gui_evt/gui_evt_chan2.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/gui_evt_chan2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,117 @@
+//
+// gui_evt_chan2.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using struct_id as id_type
+typedef channel<struct_id> evt_chan;
+
+//event ids in name_space
+//sample events for a gui window
+struct_id win_but_down_id = {application_message, 1};
+struct_id win_but_up_id = {application_message, 2};
+struct_id win_close_id = {application_message, 3};
+
+//a simple struct for event data
+struct evt_data {
+ string data_;
+ evt_data(const char *d) : data_(d) {}
+};
+
+class gui_window {
+ evt_chan & chan_;
+ evt_chan::out down_out_;
+ evt_chan::out up_out_;
+ evt_chan::out close_out_;
+public:
+ gui_window(evt_chan & c): chan_(c),
+ down_out_(chan_, win_but_down_id),
+ up_out_(chan_, win_but_up_id),
+ close_out_(chan_, win_close_id) {}
+ //methods to fire some events
+ void up(const char * msg) {
+ up_out_.send(new evt_data(msg));
+ }
+ void down(const char * msg) {
+ down_out_.send(new evt_data(msg));
+ }
+ void close(const char * msg) {
+ close_out_.send(new evt_data(msg));
+ }
+};
+
+class window_handler {
+ evt_chan & ch_;
+ evt_chan::in *down_in_;
+ evt_chan::in *up_in_;
+ evt_chan::in *close_in_;
+public:
+ window_handler(evt_chan & c): ch_(c) {
+ down_in_ = ch_.bind_name_in(win_but_down_id, boost::bind(&window_handler::down, this, _1, _2));
+ up_in_ = ch_.bind_name_in(win_but_up_id, boost::bind(&window_handler::up, this, _1, _2));
+ close_in_ = ch_.bind_name_in(win_close_id, boost::bind(&window_handler::close, this, _1, _2));
+ }
+ ~window_handler() {
+ delete down_in_;
+ delete up_in_;
+ delete close_in_;
+ }
+ //methods to handle events
+ void down(struct_id id, boost::shared_ptr<void> p) {
+ cout << "window_handler::DOWN ... recv event [id=" << evt_chan::id_trait::id_to_string(id) << "], [data=" << ((evt_data*)p.get())->data_ << "]\n";
+ }
+ void up(struct_id id, boost::shared_ptr<void> p) {
+ cout << "window_handler::UP ... recv event [id=" << evt_chan::id_trait::id_to_string(id) << "], [data=" << ((evt_data*)p.get())->data_ << "]\n";
+ }
+ void close(struct_id id, boost::shared_ptr<void> p) {
+ cout << "window_handler::CLOSE ... recv event [id=" << evt_chan::id_trait::id_to_string(id) << "], [data=" << ((evt_data*)p.get())->data_ << "]\n";
+ }
+};
+
+
+//free event handler; print out data
+void evt_handler(struct_id id, boost::shared_ptr<void> p)
+{
+ cout << "free handler ... recv event [id=" << evt_chan::id_trait::id_to_string(id) << "], [data=" << ((evt_data*)p.get())->data_ << "]\n";
+}
+
+int main(int, char **) {
+ //create 2 event channels
+ evt_chan chan1;
+ evt_chan chan2;
+
+ //connect 2 channels
+ connect(chan1, chan2);
+
+ //bind event source (window) to channel1
+ gui_window window(chan1);
+
+ //bind event sink (handler) to channel1
+ window_handler hdlr(chan1);
+
+ //bind more event sinks to channel2
+ evt_chan::in window_down_in(chan2, win_but_down_id, evt_handler);
+ evt_chan::in window_up_in(chan2, win_but_up_id, evt_handler);
+ evt_chan::in shut_down_in(chan2, win_close_id, evt_handler);
+
+ //fire events
+ window.up("..Hi there [mouse-left-up] ..");
+ window.down(".. a simple window test [mouse-right-down] ..");
+ window.close(".. simple window wiered [window-closed] ..");
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/gui_evt/sample1_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/sample1_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,121 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 1: Simple GUI Events Handling</h2>
+<big><small>
+This sample introduces Channel by showing how to implement event
+handling thru Channel.<br>
+<br>
+</small></big>
+<p><big><small>We first include the channel header file</small></big></p>
+<big><small></small></big>
+<pre style="background-color: rgb(204, 204, 204);"><big><small><span
+ style="font-weight: bold; font-style: italic;">#include &lt;boost/channel/channel.hpp&gt;</span></small></big></pre>
+<big><small><span style="font-weight: bold; font-style: italic;"><span
+ style="color: rgb(102, 0, 0);">
+</span></span></small></big>
+<p><big><small>As a first step, instantiate a concrete channel type
+according to
+application's requirement. We could consider what data type to use as
+ids, and what kind of namespace and dispatcher will be best fit the
+application. Here we use strings as ids and use default
+linear_namespace and broadcast dispatcher:</small></big></p>
+<big><small></small></big>
+<pre style="background-color: rgb(204, 204, 204);"><big><em><span
+ style="color: rgb(153, 0, 0); font-weight: bold;"><small>typedef channel&lt;string&gt; evt_chan;</small></span></em></big></pre>
+<big><em><span style="color: rgb(153, 0, 0); font-weight: bold;"></span></em></big><big><span
+ style="color: rgb(0, 0, 0);">Next</span></big> we
+define a few event ids to simulate some possible events inside a GUI
+window:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-style: italic; font-weight: bold; color: rgb(153, 0, 0);">string down_id = "_window_button_down_";<br>string up_id = "_window_button_up_";<br>string close_id = "_window_close_";</span></pre>
+<br>
+In this sample, we use the following message/event data structure to
+pass some data:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">struct evt_data {<br> string data_;&nbsp;<br> evt_data(const char *d) : data_(d) {}<br>};</span></pre>
+<br>
+<p>Then we define&nbsp; the event source of this sample: a simplest GUI
+window
+without any features except those for sending events: bound channel and
+named_outs (also typedefed inside channel: evt_chan::out). Inside
+gui_window constructor, we bind named_outs to the above mentioned event
+ids in channel to send events:</p>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;">class gui_window {<br> evt_chan &amp; chan_;<br> &nbsp;//a few event src<br></span></pre>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-style: italic; color: rgb(153, 0, 0); font-weight: bold;"> evt_chan::out down_out_;<br>&nbsp; evt_chan::out close_out_;<br>public:<br> gui_window(evt_chan &amp; c): chan_(c),<br> down_out_(chan_, down_id),<br> up_out_(chan_, up_id),<br> close_out_(chan_, close_id) {}<br> ...and define some utility methods to send out events thru named_outs ...<br>};</span></pre>
+<br>
+After defining event source, we define a handler class to demo using
+object methods as event callbacks. In constructor, we create named_in
+(also nested typedefed inside channel: evt_chan::in) objects to bind
+callbacks to event ids in channel namespace. Named_out and named_in
+objects can be created in stack as we have done in class gui_window.
+Here we create them by invoking channel's factory method to create them
+from heap.<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">class window_handler {<br>&nbsp; evt_chan &amp; ch_;<br>&nbsp; //a few event sinks<br>&nbsp; evt_chan::in *down_in_;<br>&nbsp; evt_chan::in *up_in_;<br>&nbsp; evt_chan::in *close_in_;&nbsp; <br>public:<br>&nbsp; window_handler(evt_chan &amp; c): ch_(c) {<br>&nbsp;&nbsp;&nbsp; down_in_ = ch_.bind_name_in(down_id, boost::bind(&amp;window_handler::down, this, _1, _2));<br>&nbsp;&nbsp;&nbsp; up_in_ = ch_.bind_name_in(up_id, boost::bind(&amp;window_handler::up, this, _1, _2));<br>&nbsp;&nbsp;&nbsp; close_in_ = ch_.bind_name_in(close_id, boost::bind(&amp;window_handler::close, this, _1, _2));<br>&nbsp; }<br>.... here define methods as event callbacks ...<br>};</span></pre>
+<br>
+We define another global function to be used&nbsp; as event handler.<br>
+<span style="color: rgb(153, 0, 0);">void evt_handler(string id,
+boost::shared_ptr&lt;void&gt; p)</span><br
+ style="color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);">{</span><br
+ style="color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);">&nbsp; cout &lt;&lt; "free handler
+... recv event [id=" &lt;&lt; id &lt;&lt; "], [data=" &lt;&lt;
+((evt_data*)p.get())-&gt;data_ &lt;&lt; "]" &lt;&lt; endl;</span><br
+ style="color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);">}</span><br>
+<br>
+Now here is a simple main function:<br>
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">int main(int, char **) {</span></pre>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span>The
+first thing is to create the event channel<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">evt_chan chan;</span></pre>
+create the event source (gui_window) and bind it to channel<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">gui_window window(chan);</span></pre>
+create a handler object and bind it to channel<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;window_handler hdlr(chan);</span></pre>
+Next we create more event sinks to bind the global function to event
+ids.<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">evt_chan::in window_down_in(chan, down_id, evt_handler)<br>evt_chan::in window_up_in(chan, up_id, evt_handler);&nbsp;<br>evt_chan::in shut_down_in(chan, close_id, evt_handler);</span></pre>
+Last, we fire some events<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">window.up("..Hi there [mouse-left-up] ..");<br>window.down(".. a simple window test [mouse-right-down] ..");<br>window.close(".. simple window wiered [window-closed] ..");</span></pre>
+Then exit<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<pre style="background-color: rgb(204, 204, 204);"><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">cout &lt;&lt; "... exit ...\n";&nbsp;<br>return 0;</span></pre>
+<p><br>
+In this simple sample, we bind event handlers/callbacks to event
+sources indirectly by binding to names in channel namespace. After
+namespace binding, event dispatching happens directly between named_out
+(senders) and named_in (receivers).</p>
+<br>
+Finally, here is <a href="gui_evt_chan1.cpp">the
+complete
+source code.</a><br>
+<br>
+<br>
+<em><span style="color: rgb(153, 0, 0); font-weight: bold;"></span></em>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/gui_evt/sample2_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/gui_evt/sample2_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body>
+<h2>Sample 2: Simple GUI Events Handling By Connecting Two Local
+Channels</h2>
+<br>
+This sample is based on sample 1 with changes to demonstrate connecting
+two local channels.<br>
+<br>
+Also we use the following POD struct (defined in linear_id_trait.hpp)
+as message id/names:<br>
+&nbsp;&nbsp;&nbsp; struct struct_id {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message_family family;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int type;<br>
+&nbsp;&nbsp;&nbsp; &nbsp; ......<br>
+&nbsp;&nbsp;&nbsp; };<br>
+<br>
+The changes are inside main() function:<br>
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">int
+main(int, char **) {</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span>First
+we create 2 channels<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+evt_chan chan1;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+evt_chan chan2;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+Then we connect these 2 channels<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+connect(chan1, chan2);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+Bind event source to channel 1<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+gui_window window(chan1);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span>create
+handler object and bind it to channel 1<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+window_handler hdlr(chan1); </span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+create more event sinks and bind the global function to channel 2.<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+evt_chan::in window_down_in(chan2, win_but_down_id, evt_handler);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+evt_chan::in window_up_in(chan2, win_but_up_id, evt_handler);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+evt_chan::in shut_down_in(chan2, win_close_id, evt_handler);</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+Now we fire some event for testing.<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+window.up("..Hi there [mouse-left-up] ..");</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+window.down(".. a simple window test [mouse-right-down] ..");</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+window.close(".. simple window wiered [window-closed] ..");</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+Last exit<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+cout &lt;&lt; "... exit ...\n";</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+return 0;</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<span
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">}</span><br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<br>
+From testing, we should see events propagate to both channel 1 and
+channel 2 and events get printed out by callbacks at both channels.<br>
+<a href="gui_evt_chan2.cpp">Complete source
+listing...</a><br>
+<br
+ style="font-weight: bold; font-style: italic; color: rgb(153, 0, 0);">
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/ping_pong/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/ping_pong/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,48 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <library>/boost/system//boost_system
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj ping.obj : ping.cpp ;
+exe ping : ping.obj ;
+obj pong.obj : pong.cpp ;
+exe pong : pong.obj ;

Added: sandbox/channel/libs/channel/example/ping_pong/ping.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/ping_pong/ping.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,78 @@
+//
+// ping.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./pingpong_defs.hpp"
+
+//msg handler; print out data
+void msg_handler(msg_chan::out & ping_o, int id, boost::shared_ptr<void> p)
+{
+ pingpong_msg *msg = (pingpong_msg *) p.get();
+ cout << "Ping recv count = " << msg->count_ << endl;
+ ping_o.send(new pingpong_msg(msg->count_+1));
+}
+
+void binding_callback(msg_chan::out ** ping_o, msg_chan::name *n, msg_chan::name::binding_event e) {
+ if (n->type_ == msg_chan::name::member_remote && e == msg_chan::name::bind_ev) {
+ (*ping_o)->send(new pingpong_msg(0));
+ }
+}
+
+int main(int, char **) {
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channel and bind local event source/sink
+ msg_chan chan;
+
+ //publish ping msg
+ msg_chan::out *po = NULL;
+ msg_chan::out ping_o(chan,
+ msg_id_ping,
+ boost::bind(binding_callback, &po, _1,_2));
+ po = &ping_o;
+
+ //subscribe pong msg
+ msg_chan::in pong_i(chan, msg_id_pong, boost::bind(msg_handler,
+ boost::ref(ping_o), _1,_2));
+
+ //register msg type for marshaling/demarshaling
+ msg_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<pingpong_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ /*
+ connector.async_accept(8888, // channel address
+ boost::bind(asio_bind_sock_chan<msg_chan, chat_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ */
+ connector.async_connect("localhost", "9999", //remote channel address
+ boost::bind(asio_bind_sock_chan<msg_chan, msg_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+
+ io_service.run();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... ping exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/ping_pong/pingpong_defs.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/ping_pong/pingpong_defs.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,40 @@
+//
+// pingpong_defs.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef PINGPONG_DEFS_HPP
+#define PINGPONG_DEFS_HPP
+
+#include <boost/channel/channel.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type
+typedef channel<int> msg_chan;
+
+//sample msg ids
+int msg_id_base = msg_chan::app_msg_begin;
+int msg_id_ping = msg_id_base+1;
+int msg_id_pong = msg_id_ping+1;
+
+//a simple struct for ping-pong msg
+struct pingpong_msg {
+ int count_;
+ char dd[1024*1024]; //for checking mem-leak during msg passing
+ pingpong_msg(int cnt) : count_(cnt) {}
+ pingpong_msg() {} //have to define this for marshaling to work
+ //serialization function for pingpong_msg
+ template <typename Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar & count_;
+ }
+};
+
+#endif

Added: sandbox/channel/libs/channel/example/ping_pong/pong.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/ping_pong/pong.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,77 @@
+//
+// pong.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/streams/asio_stream_async.hpp>
+#include "./pingpong_defs.hpp"
+
+//msg handler; print out data
+void msg_handler(msg_chan::out & pong_o, int id, boost::shared_ptr<void> p)
+{
+ pingpong_msg *msg = (pingpong_msg *) p.get();
+ cout << "Pong recv count = " << msg->count_ << endl;
+ pong_o.send(new pingpong_msg(msg->count_+1));
+}
+
+void binding_callback(msg_chan::out ** pong_o, msg_chan::name *n, msg_chan::name::binding_event e) {
+ if (n->type_ == msg_chan::name::member_remote && e == msg_chan::name::bind_ev) {
+ (*pong_o)->send(new pingpong_msg(0));
+ }
+}
+
+int main(int, char **) {
+ try {
+ //create asio io_service
+ boost::asio::io_service io_service;
+ //create local channel and bind local event source/sink
+ msg_chan chan;
+
+ //publish pong msg
+ msg_chan::out *po = NULL;
+ msg_chan::out pong_o(chan,
+ msg_id_pong,
+ boost::bind(binding_callback, &po, _1,_2));
+ po = &pong_o;
+
+ //subscribe ping msg
+ msg_chan::in ping_i(chan, msg_id_ping, boost::bind(msg_handler,
+ boost::ref(pong_o), _1,_2));
+
+ //register msg type for marshaling/demarshaling
+ msg_chan::text_marshaler_registry mar_reg;
+ mar_reg.register_default_msg_marshaler<pingpong_msg>();
+
+ //create asio connectors and connect to remote channel
+ asio_connector_async connector(io_service);
+ connector.async_accept(9999, // channel address
+ boost::bind(asio_bind_sock_chan<msg_chan, msg_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ /*
+ connector.async_connect("localhost", "8888", //remote channel address
+ boost::bind(asio_bind_sock_chan<msg_chan, msg_chan::text_marshaler_registry>(),
+ boost::ref(chan), boost::ref(mar_reg), _1, _2, _3));
+ */
+ io_service.run();
+ }
+ catch (boost::system::error_code& e)
+ {
+ std::cerr << e << "\n";
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ cout << "... pong exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/example/prime_sieve/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/prime_sieve/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,45 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj prime_sieve.obj : prime_sieve.cpp ;
+exe prime_sieve : prime_sieve.obj ;

Added: sandbox/channel/libs/channel/example/prime_sieve/prime_sieve.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/prime_sieve/prime_sieve.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,113 @@
+//
+// prime_sieve.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+///* Copyright (c) 2005 Russ Cox, MIT; see COPYRIGHT */
+
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/channel/channel.hpp>
+#include <boost/channel/executors/thread_pool_executor.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+
+using namespace std;
+using namespace boost::channel;
+
+//define executor
+typedef thread_pool_executor<mt_synch<boost_platform> > exec_type;
+
+//define port type
+typedef port<exec_type> port_type;
+typedef port_type::choice_async choice_type;
+
+static int task_no = 0;
+
+//define task type: comprise of 3 parts:
+//1> a port to recv msgs
+//2> a run() method to process msgs
+//3> a executor to execute run()
+class prime_task {
+private:
+ //app data
+ int my_prime_;
+ int my_no_;
+ prime_task *next_;
+
+public:
+ //task main data
+ port_type port_;
+ choice_type choice_;
+ exec_type *exe_;
+
+ prime_task(exec_type *e) :
+ my_prime_(-1), next_(NULL),
+ port_(e), choice_(e), exe_(e)
+ {
+ my_no_ = task_no++;
+ choice_.bind(port_, boost::bind(&prime_task::run, this, _1));
+ }
+ ~prime_task() {
+ if (next_ != NULL) delete next_;
+ //cout << "prime_task [" << my_no_ << "] destroy " << endl;
+ }
+ void run(boost::shared_ptr<void> p)
+ {
+ int val = *(int *)p.get();
+ if (my_prime_ == -1) { //first time
+ my_prime_ = val;
+ cout << "------ prime_task [" << my_no_ << "] found prime = " << val << endl;
+ next_ = new prime_task(exe_); //create the next task
+ }
+ else {
+ if (val % my_prime_) { //not my multiples
+ next_->port_.send(p);
+ } else { //my multiples
+ cout << "prime_task [" << my_no_ << "] drop " << val << endl;
+ }
+ }
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+int main(int argc, char **argv) {
+ //create executor with two threads
+ exec_type exec(2);
+
+ int max_num;
+ if (argc > 1)
+ max_num = atoi(argv[1]);
+ else
+ max_num = 1000;
+
+ cout << "find primes in range [2-" << max_num << "]" << endl;
+
+ //create prime_task0
+ prime_task first_task(&exec);
+
+ for(int i=2; i<=max_num; i++) {
+ int *data = new int;
+ *data = i;
+ first_task.port_.send(data);
+ //sleep 1 sec, to avoid jam executor queue & better show diff tasks running
+ thread_sleep(1);
+ }
+
+ exec.wait(); //wait async tasks finish
+ exec.shut_down_wait(); //wait threads exit
+
+ return 0;
+
+ //when main() exit, first_task goes out of scope, it will delete itself and all chained tasks
+}

Added: sandbox/channel/libs/channel/example/prime_sieve/sample12_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/prime_sieve/sample12_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,205 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Sample 12.&nbsp; port and signal: unnamed point
+of tightly-coupled local interactions&nbsp;<br>
+</h2>
+Channel's name space and binding thru name-matching provide a loosely
+coupled model for asynchronous distributed message passing. However
+setting up name space and designing name assignment scheme could be too
+much trouble for applications based on tightly coupled message passing
+inside a single address space. This tutorial explains 3 samples showing
+how Channel's port and signal classes can help build these kind of
+applications.<br>
+<br>
+The 1st sample is using a pipeline of asynchronous tasks to generate
+all primes
+less than a thousand. For the original design and considerations,
+please refer to Russ Cox's essay <a
+ href="http://swtch.com/%7Ersc/thread/">"Bell Labs and CSP Threads"</a>.&nbsp;
+The original code is
+based on tasks(coroutines) and synchronous
+communication channels. In this sample, the code is changed to&nbsp; be
+based on port and asynchronous tasks executed by thread pool executor.
+Here is the complete source code<span
+ style="text-decoration: underline;"> </span>prime_sieve.cpp.&nbsp;
+Let's walk thru the code.<br>
+<br>
+First we define the type of thread pool executor to run the
+asynchronous tasks. Also we instantiate port template class to define
+port type and its related choice arbiter type. <br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">typedef
+port&lt;exec_type&gt; port_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">typedef
+port_type::choice_async choice_type;</span><br>
+</div>
+A port can be used as a message queue and allow applications put data
+into it and get data from it. However mostly ports are used with
+choice/join arbiters.<br>
+<br>
+Next we define a class for the asynchronous tasks which will do the
+real job of finding primes. A task consists of 3 main parts: &lt;1&gt;
+a port to receive messages; &lt;2&gt; a run() method to define task's
+functionality; &lt;3&gt; a executor to execute run() method. Please
+notice that in constructor the choice arbiter bind the port to run()
+method, so that each incoming message will create an asynchronous task
+which will execute run()'s code in a thread from thread pool.<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; void
+run(boost::shared_ptr&lt;void&gt; p)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+int val = *(int *)p.get();</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+if (my_prime_ == -1) { //first time</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+my_prime_ = val;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; "------ prime_task [" &lt;&lt; my_no_ &lt;&lt; "] found
+prime = " &lt;&lt; val &lt;&lt; endl;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+next_ = new prime_task(exe_); //create the next task</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+} </span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+else {</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if (val % my_prime_) { //not my multiples</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+next_-&gt;port_.send(p);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+} else { //my multiples</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+cout &lt;&lt; "prime_task [" &lt;&lt; my_no_ &lt;&lt; "] drop "
+&lt;&lt; val &lt;&lt; endl;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; }</span><br>
+</div>
+The method run() takes a single argument of pointer to message data
+which it received from port. If it is the 1st time this task receives a
+message, the received integer will be a prime and it is saved, and the
+next asynchronous task will be created. If it is not the 1st message,
+it will be compared with the prime saved by this task and dropped if it
+is a multiple of the saved prime; otherwise the message is sent to the
+port of the next task.<br>
+<br>
+The main() function is simple. First we create the thread pool executor
+and create the 1st task. Then we start feeding integers (2-1000) to the
+port of the 1st task. Before exit, we'll wait for the graceful exit of
+all thread pool threads.<br>
+<br>
+The 2nd example demos the signal class and its associated slot type. It
+is a modification of tutorial 1. Instead of using channel, named_out
+and named_in, this sample uses signal and slot to set up event
+dispatching system without the hassle of choosing id and assigning
+names. Here is the complete source gui_evt3.cpp
+.<br>
+<br>
+The 3rd sample demos how "unnamed" port can be used together with names
+/ ids in the same choice arbiter. Here is the complete source
+code&nbsp; chat_join_timer.cpp.&nbsp;
+This sample is based on sample 6 with the addition of a timer sending
+events to a port. Let's walk thru code.<br>
+<br>
+First port type is defined based on channel type.<br>
+&nbsp;&nbsp;&nbsp; <span
+ style="color: rgb(153, 0, 0); font-style: italic;">typedef
+chat_chan::port port_t;</span><br>
+<br>
+Next my_timer class is defined, which uses asio's deadline_timer and
+set timeout period to 5 seconds. When timeout happens, a null_event
+message is sent to a port.<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">class my_timer</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">{</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">public:</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+my_timer(boost::asio::io_service&amp; io, port_t &amp;p)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+: timer_(io, boost::posix_time::seconds(5)),</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+port_(p)</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+timer_.async_wait(boost::bind(&amp;my_timer::timeout, this));</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; void
+timeout()</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+port_.send(new null_event); //send timeout notifications</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(5));</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+timer_.async_wait(boost::bind(&amp;my_timer::timeout, this));</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">private:</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+boost::asio::deadline_timer timer_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp; port_t
+&amp;port_;</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">};</span><br>
+</div>
+<br>
+In main(), most code is similar to sample 6, except the following code
+for timer and port.<br>
+First, timer and port are created and a new thread is spawn to run asio.<br>
+<div
+ style="margin-left: 40px; font-style: italic; color: rgb(153, 0, 0);">&nbsp;
+boost::asio::io_service io;<br>
+&nbsp; port_t timeout_port;<br>
+&nbsp; my_timer(io,timeout_port);<br>
+&nbsp; //spawn a thread to run timer<br>
+&nbsp; boost::thread t(boost::bind(&amp;boost::asio::io_service::run,
+&amp;io));&nbsp; <br>
+</div>
+<br>
+Next, add the timeout_port to the choice arbiter and bind it with a
+timeout handler which simply prints a message.<br>
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);">&nbsp;<span
+ style="font-style: italic;">choice.bind(timeout_port, timeout_hdlr);</span><br>
+</span></div>
+Notice the same choice arbiter handles both "names/ids" and the
+timeout_port objects.<br>
+<br>
+During testing, we should see the timeout message every 5 seconds.<br>
+<br>
+<br>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/sample_dispatcher/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/sample_dispatcher/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,45 @@
+#////////////////////////////////////////////////////////////////////////////////
+#// Copyright (c) 2005, 2007 Yigong Liu
+#// Permission to use, copy, modify, distribute and sell this software for any
+#// purpose is hereby granted without fee, provided that the above copyright
+#// notice appear in all copies and that both that copyright notice and this
+#// permission notice appear in supporting documentation.
+#// The author makes no representations about the
+#// suitability of this software for any purpose. It is provided "as is"
+#// without express or implied warranty.
+#////////////////////////////////////////////////////////////////////////////////
+#
+# Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+ lib socket ;
+ lib nsl ;
+}
+else if [ os.name ] = NT
+{
+ lib ws2_32 ;
+ lib mswsock ;
+}
+
+project
+ : requirements
+ <library>/boost/channel//boost_channel
+ <library>/boost/serialization//boost_serialization
+ <library>/boost/thread//boost_thread
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ <os>SOLARIS:<library>socket
+ <os>SOLARIS:<library>nsl
+ <os>NT,<toolset>gcc:<library>ws2_32
+ <os>NT,<toolset>gcc:<library>mswsock
+ ;
+
+obj sync_send_recv.obj : sync_send_recv.cpp ;
+exe sync_send_recv : sync_send_recv.obj ;

Added: sandbox/channel/libs/channel/example/sample_dispatcher/dispatcher_text.html
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/sample_dispatcher/dispatcher_text.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,528 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>dispatcher_text.html</title>
+</head>
+<body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+<h2>Implementation of Sample Pull Dispatcher<br>
+</h2>
+The following is the description of implementation of a simple pull
+dispatcher.&nbsp; Its full source is <a
+ href="pull_dispatcher_sample.hpp">here...</a><br>
+<br>
+Each dispatcher has 2 parts: sending algorithm and receiving algorithm.
+They are defined as 2 separate nested template classes. With this
+dispatcher, sending thread buffers messages in queues at sending side,
+notifies the receivers and returns right away, receiving threads are
+blocked waiting at receiving side and unblocked when messages are
+available.<br>
+<br>
+Let's look at the sending class at first. Because it is a pull
+dispatcher, the messages will be buffered inside channel at sending
+side. A queue will be part of sending class. Queue type is one of
+template parameter of sender class to allow customization. We set the
+sender class inherit from queue class so that queue's methods are
+exposed to allow clients code to provision the queue's settings such as
+size or blocking timeout.<br>
+<br>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+template &lt;typename name_space, typename platform, template
+&lt;class,class,class&gt; class msg_queue_type&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+struct pull_sender_sample : </span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; public
+msg_queue_type&lt;boost::shared_ptr&lt;message&lt;typename
+name_space::id_type&gt; &gt;,</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; typename
+name_space::synch_policy,</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; platform&gt; {<br>
+<br>
+</span></span></div>
+Next, we define a few data types associated with sending class:<br>
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);"></span></span></div>
+<div style="text-align: left;">
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);"><span
+ style="font-style: italic;">&nbsp;&nbsp;&nbsp; typedef typename
+name_space::id_type id_type;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef typename name_space::synch_policy synch_policy;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef typename name_space::executor executor;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef name&lt;id_type,executor,synch_policy&gt; name_type;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef message&lt;id_type&gt; msg_type;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef typename name_type::binding_set_type binding_set_type;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef msg_queue_type&lt;boost::shared_ptr&lt;msg_type&gt;,
+synch_policy,</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; platform&gt; que_type;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef pull_recver_sample&lt;name_space, platform,msg_queue_type&gt;
+recver_type;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typedef named_in&lt;name_space, recver_type&gt; named_in_type;</span></span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Then constructor is defined.<br>
+</span></span>
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);"><span
+ style="font-style: italic;">&nbsp;&nbsp;&nbsp; name_type * name_;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+pull_sender_sample(name_type *n, executor *) : que_type(), name_(n) { }</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+~pull_sender_sample() {}</span></span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Next, the most important method in sending class is defined. Since this
+is a pull dispatcher, the message is not pushed directly to receivers.
+Instead, the message is stored in queue first, then bound receivers are
+notified that a message is available and receiving threads are
+unblocked. Notice the binding_set (set of bound receivers) are
+retrieved from associated name object.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+void notify(boost::shared_ptr&lt;msg_type&gt; msg) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; //first store msg in que</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; put(msg);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; //notify recevers</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; typename synch_policy::scoped_lock
+lock(this-&gt;name_-&gt;bind_lock_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; binding_set_type &amp;bindings = this-&gt;name_-&gt;bindings_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; if (!bindings.empty()) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; bool cont = true;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; for(typename binding_set_type::iterator iter =
+bindings.begin();</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; iter != bindings.end() &amp;&amp; cont; iter++) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; named_in_type *named_in = (named_in_type
+*)(*iter);</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recver_type *recver = (recver_type
+*)named_in;</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //for pull dispatchers, only send msgs
+to local receviers</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (named_in-&gt;type_ ==
+named_in_type::member_local)</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; cont = recver-&gt;notify(msg-&gt;id_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; }</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+After receiving notification, the 1st notified receiver will
+pull/retrieve message from sender's queue.<br>
+</span></span>
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);"><span
+ style="font-style: italic;">&nbsp;&nbsp;&nbsp; int
+pull(boost::shared_ptr&lt;msg_type&gt; &amp; msg) {</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp; if (!this-&gt;empty()) {</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; get(msg);</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return 1;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp; }</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp; return 0;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+}</span></span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+The following methods are various "send()" which are the API of this
+class. One basic rule is that message data are passed in as pointers,
+and this data will be owned by channel and released by channel after
+nobody refers to it anymore. To change this default behaviour (such as
+passing data on stack as message), invoker of "send()" can pass in
+proper deleter together with data pointer or pass in proper share_ptr
+initialized with proprt deleter.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+//after sending, channel becomes owner</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+template &lt;typename user_msg_type&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+void send(user_msg_type *msg) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;void&gt; m0(msg);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;msg_type&gt; m(new msg_type(name_-&gt;id_,
+m0));</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; notify (m);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+//after sending: 1&gt; channel becomes owner, if deleter does real
+deletion</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+// 2&gt; sender still owns msg, if deleter does nothing</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+template &lt;typename user_msg_type, typename deleter&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+void send(user_msg_type *msg, deleter deler) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;void&gt; m0(msg, deler);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;msg_type&gt; m(new msg_type(name_-&gt;id_,
+m0));</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; notify (m);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+//user_msg is already smarter pointer, channel becomes owner</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+template &lt;typename user_msg_type&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+void send(boost::shared_ptr&lt;user_msg_type&gt; msg) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;void&gt; m0(msg);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;msg_type&gt; m(new msg_type(name_-&gt;id_,
+m0));</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; notify (m);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);"></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+//for channel internal use on wildcard named_out</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+template &lt;typename user_msg_type&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+void send(id_type id, boost::shared_ptr&lt;user_msg_type&gt; msg) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;void&gt; m0(msg);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;msg_type&gt; m(new msg_type(id, m0));</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; notify (m);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+The following is about the implementation of receiving class.<br>
+<br>
+It has the same template parameters as sending class.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+template &lt;typename name_space, typename platform, template
+&lt;class,class,class&gt; class msg_que_type&gt;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+struct pull_recver_sample {<br>
+</span><span style="color: rgb(153, 0, 0);"><span
+ style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);">Similarly,
+associated types are defined.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef typename name_space::id_type id_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef typename name_space::synch_policy synch_policy;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef typename name_space::executor executor;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef name&lt;id_type,executor,synch_policy&gt; name_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef message&lt;id_type&gt; msg_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef pull_sender_sample&lt;name_space, platform, msg_que_type&gt;
+sender_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef named_out&lt;name_space, sender_type&gt; named_out_type;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+typedef typename name_type::binding_set_type binding_set_type;</span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Some synchronization variables and constructor.<br>
+</span></span>
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);"><span
+ style="font-style: italic;">&nbsp;&nbsp;&nbsp; name_type * name_;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typename synch_policy::mutex mutex_;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+typename synch_policy::condition cond_;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+int num_waiting_;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+pull_recver_sample(name_type *n) : </span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+&nbsp; name_(n), num_waiting_(0) {}</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+~pull_recver_sample() {}</span></span><br style="font-style: italic;">
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Here comes the "main" function of receiving threads. Recving thread
+will block here and wait for notifications from senders. And then
+messages will be pulled/retrieved from sending queue and processed.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+void recv(id_type &amp; id, boost::shared_ptr&lt;void&gt; &amp; msg) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; int st;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; boost::shared_ptr&lt;msg_type&gt; mesg;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; typename synch_policy::scoped_lock lock(mutex_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; while(1) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; st = pull(mesg);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; if (st != 0) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id = mesg-&gt;id_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; msg = mesg-&gt;data_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; num_waiting_++;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; cond_.wait(lock);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; num_waiting_--;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Sending thread will call this method to wake up blocked receiving
+threads.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+bool notify(id_type id) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; typename synch_policy::scoped_lock lock(mutex_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; if (num_waiting_ &gt; 0) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; cond_.notify_one();</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return false;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; } </span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; else</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return true;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Since a receiver can be bound to multiple senders, the following pull
+method try to retrieve data from any bound senders.<br>
+</span></span>
+<div style="margin-left: 40px;"><span
+ style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+int pull(boost::shared_ptr&lt;msg_type&gt; &amp; msg) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; int st = 0;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; //go-thru binding_set to pull from senders</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; typename synch_policy::scoped_lock lock(name_-&gt;bind_lock_);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; binding_set_type &amp;bindings = name_-&gt;bindings_;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; if (!bindings.empty()) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; for(typename binding_set_type::iterator iter =
+bindings.begin();</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; iter != bindings.end() &amp;&amp; st == 0; iter++) {</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; named_out_type *named_out =
+(named_out_type *)(*iter);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sender_type *sender = (sender_type
+*)(named_out);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; st = sender-&gt;pull(msg);</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; }</span><br style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+&nbsp; return st;</span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="font-style: italic; color: rgb(153, 0, 0);">&nbsp;&nbsp;&nbsp;
+}</span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Finally, a dispatcher template class wraps these sending class and
+receiving class together.<br>
+</span></span>
+<div style="margin-left: 40px;"><span style="color: rgb(153, 0, 0);"><span
+ style="font-style: italic;">&nbsp;&nbsp;&nbsp; template &lt;typename
+name_space, typename platform, template &lt;class,class,class&gt; class
+queue_type = unbounded_que&gt;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+struct pull_dispatcher_sample {</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef
+detail::pull_sender_sample&lt;name_space,platform,queue_type&gt; sender;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef
+detail::pull_recver_sample&lt;name_space,platform,queue_type&gt; recver;</span></span><br
+ style="font-style: italic; color: rgb(153, 0, 0);">
+<span style="color: rgb(153, 0, 0);"><span style="font-style: italic;">&nbsp;&nbsp;&nbsp;
+};</span></span><br>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"></span></span></div>
+<span style="color: rgb(153, 0, 0);"><span style="color: rgb(0, 0, 0);"><br>
+Here is <a href="sync_send_recv.cpp">a
+simple program demos usage of this dispatcher</a>.<br>
+<br>
+</span></span><span style="color: rgb(153, 0, 0); font-style: italic;"></span></div>
+</body>
+</html>

Added: sandbox/channel/libs/channel/example/sample_dispatcher/pull_dispatcher_sample.hpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/sample_dispatcher/pull_dispatcher_sample.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,193 @@
+//
+// pull_dispatcher_sample.hpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef PULL_DISPATCHER_SAMPLE_HPP
+#define PULL_DISPATCHER_SAMPLE_HPP
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/channel/channel.hpp>
+
+namespace boost {
+ namespace channel {
+
+ namespace detail {
+
+ template<class,class,template<class,class,class>class> class pull_recver_sample;
+
+ template <typename name_space, typename platform, template <class,class,class> class msg_queue_type>
+ struct pull_sender_sample :
+ public msg_queue_type<boost::shared_ptr<message<typename name_space::id_type> >,
+ typename name_space::synch_policy,
+ platform> {
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef name<id_type,executor,synch_policy> name_type;
+ typedef message<id_type> msg_type;
+ typedef typename name_type::binding_set_type binding_set_type;
+ typedef msg_queue_type<boost::shared_ptr<msg_type>, synch_policy,
+ platform> que_type;
+ typedef pull_recver_sample<name_space, platform,msg_queue_type> recver_type;
+ typedef named_in<name_space, recver_type> named_in_type;
+
+ name_type * name_;
+
+ pull_sender_sample(name_type *n, executor *) : que_type(), name_(n) { }
+ ~pull_sender_sample() {}
+
+ //assuming msgs contained inside shared_ptr
+ void notify(boost::shared_ptr<msg_type> msg) {
+ //first store msg in que
+ put(msg);
+ //notify recevers
+ typename synch_policy::scoped_lock lock(this->name_->bind_lock_);
+ binding_set_type &bindings = this->name_->bindings_;
+ if (!bindings.empty()) {
+ bool cont = true;
+ for(typename binding_set_type::iterator iter = bindings.begin();
+ iter != bindings.end() && cont; iter++) {
+ named_in_type *named_in = (named_in_type *)(*iter);
+ recver_type *recver = (recver_type *)named_in;
+ //for pull dispatchers, only send msgs to local receviers
+ if (named_in->type_ == named_in_type::member_local)
+ cont = recver->notify(msg->id_);
+ }
+ }
+ }
+
+ //recvers will call this to retrv/pull data
+ int pull(boost::shared_ptr<msg_type> & msg) {
+ if (!this->empty()) {
+ this->get(msg);
+ return 1;
+ }
+ return 0;
+ }
+
+ //--- api interface ---
+ //after sending, channel becomes owner
+ template <typename user_msg_type>
+ void send(user_msg_type *msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ notify (m);
+ }
+
+ //after sending: 1> channel becomes owner, if deleter does real deletion
+ // 2> sender still owns msg, if deleter does nothing
+ template <typename user_msg_type, typename deleter>
+ void send(user_msg_type *msg, deleter deler) {
+ boost::shared_ptr<void> m0(msg, deler);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ notify (m);
+ }
+
+ //user_msg is already smarter pointer, channel becomes owner
+ template <typename user_msg_type>
+ void send(boost::shared_ptr<user_msg_type> msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(name_->id_, m0));
+ notify (m);
+ }
+
+ //for channel internal use on wildcard named_out
+ template <typename user_msg_type>
+ void send(id_type id, boost::shared_ptr<user_msg_type> msg) {
+ boost::shared_ptr<void> m0(msg);
+ boost::shared_ptr<msg_type> m(new msg_type(id, m0));
+ notify (m);
+ }
+
+ };
+
+ //synchronous/blocking pull_recver
+ template <typename name_space, typename platform, template <class,class,class> class msg_que_type>
+ struct pull_recver_sample {
+ typedef typename name_space::id_type id_type;
+ typedef typename name_space::synch_policy synch_policy;
+ typedef typename name_space::executor executor;
+ typedef name<id_type,executor,synch_policy> name_type;
+ typedef message<id_type> msg_type;
+ typedef pull_sender_sample<name_space, platform, msg_que_type> sender_type;
+ typedef named_out<name_space, sender_type> named_out_type;
+ typedef typename name_type::binding_set_type binding_set_type;
+
+ name_type * name_;
+ typename synch_policy::mutex mutex_;
+ typename synch_policy::condition cond_;
+ int num_waiting_;
+
+ pull_recver_sample(name_type *n) :
+ name_(n), num_waiting_(0) {}
+
+ ~pull_recver_sample() {}
+
+ //recving thread will block here and wait for notify from senders
+ void recv(id_type & id, boost::shared_ptr<void> & msg) {
+ int st;
+ boost::shared_ptr<msg_type> mesg;
+ typename synch_policy::scoped_lock lock(mutex_);
+ while(1) {
+ st = pull(mesg);
+ if (st != 0) {
+ id = mesg->id_;
+ msg = mesg->data_;
+ return;
+ }
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ }
+ }
+
+ //if any thread block waiting here
+ bool notify(id_type id) {
+ typename synch_policy::scoped_lock lock(mutex_);
+ if (num_waiting_ > 0) {
+ cond_.notify_one();
+ return false;
+ }
+ else
+ return true;
+ }
+
+ //pull data from sender
+ int pull(boost::shared_ptr<msg_type> & msg) {
+ int st = 0;
+ //go-thru binding_set to pull from senders
+ typename synch_policy::scoped_lock lock(name_->bind_lock_);
+ binding_set_type &bindings = name_->bindings_;
+ if (!bindings.empty()) {
+ for(typename binding_set_type::iterator iter = bindings.begin();
+ iter != bindings.end() && st == 0; iter++) {
+ named_out_type *named_out = (named_out_type *)(*iter);
+ sender_type *sender = (sender_type *)(named_out);
+ st = sender->pull(msg);
+ }
+ }
+ return st;
+ }
+ };
+
+ }
+
+ template <typename name_space, typename platform, template <class,class,class> class queue_type = unbounded_que>
+ struct pull_dispatcher_sample {
+ typedef detail::pull_sender_sample<name_space,platform,queue_type> sender;
+ typedef detail::pull_recver_sample<name_space,platform,queue_type> recver;
+ };
+
+ }
+}
+
+#endif

Added: sandbox/channel/libs/channel/example/sample_dispatcher/sync_send_recv.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/example/sample_dispatcher/sync_send_recv.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,82 @@
+//
+// sync_send_recv.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+//
+// demo of sample buffered synchronous dispatcher: ie. recver is blocking waiting for data to arrive
+//
+
+#include <iostream>
+#include <string>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
+#include <boost/channel/channel.hpp>
+#include "./pull_dispatcher_sample.hpp"
+
+using namespace std;
+using namespace boost::channel;
+
+//instantiate event channel type, using string as id_type
+typedef linear_name_space<string,
+ abstract_executor,
+ mt_synch<boost_platform> > ns_type;
+typedef channel<
+ string,
+ boost_platform,
+ mt_synch<boost_platform>,
+ abstract_executor,
+ ns_type,
+ pull_dispatcher_sample<ns_type, boost_platform>
+> evt_chan;
+
+//event ids in name_space
+//sample events for sending text
+string evt_id = "_simple_event_to_send_text_";
+
+//a simple struct for event data
+struct evt_data {
+ string data_;
+ evt_data(const char *d) : data_(d) {}
+};
+
+//entry point function for recving thread; print out data
+void evt_recv(evt_chan::in & recver)
+{
+ string id;
+ boost::shared_ptr<void> p;
+ while (1) {
+ recver.recv(id, p);
+ cout << "recv event [id=" << id << "], [data=" << ((evt_data*)p.get())->data_ << "]\n";
+ }
+}
+
+int main(int, char **) {
+ //create event channel
+ evt_chan chan;
+
+ //bind event source to channel
+ evt_chan::out sender(chan, evt_id);
+
+ //bind event sink to channel
+ evt_chan::in recver(chan, evt_id);
+
+ //a separate thread to run recver
+ boost::thread t(boost::bind(evt_recv, boost::ref(recver)));
+
+ //main thread fire events
+ char msg[1024];
+ bool cont = true;
+ while (cont) {
+ cin.getline(msg, 1024);
+ sender.send(new evt_data(msg));
+ }
+
+ cout << "... exit ...\n";
+ return 0;
+}
+

Added: sandbox/channel/libs/channel/index.html
==============================================================================

Added: sandbox/channel/libs/channel/src/assoc_id_trait.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/src/assoc_id_trait.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,29 @@
+//
+// assoc_id_trait.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#define BOOST_CHANNEL_SOURCE
+
+#include <string>
+#include <boost/channel/name_spaces/assoc_id_trait.hpp>
+using namespace boost::channel;
+
+/// definitions of system messages for regex_id ids
+regex_id id_trait<regex_id>::channel_conn_msg = "_channel_conn_msg_";
+regex_id id_trait<regex_id>::channel_disconn_msg = "_channel_disconn_msg_";
+regex_id id_trait<regex_id>::init_subscription_info_msg = "_init_subscription_info_msg_";
+regex_id id_trait<regex_id>::connection_ready_msg = "_connection_ready_msg_";
+regex_id id_trait<regex_id>::subscription_info_msg = "_subscription_info_msg_";
+regex_id id_trait<regex_id>::unsubscription_info_msg = "_unsubscription_info_msg_";
+regex_id id_trait<regex_id>::publication_info_msg = "_publication_info_msg_";
+regex_id id_trait<regex_id>::unpublication_info_msg = "_unpublication_info_msg_";
+
+/// definitions of system messages for tuple_id ids
+int field_trait<int>::wildcard = -1010101; //should choose a better value
+float field_trait<float>::wildcard = -1010101.0101; //should choose a better value
+const char * field_trait<std::string>::wildcard = "-1010101"; //should choose a better value

Added: sandbox/channel/libs/channel/src/hierarchical_id_trait.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/src/hierarchical_id_trait.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,55 @@
+//
+// hierarchical_id_trait.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#define BOOST_CHANNEL_SOURCE
+
+#include <boost/channel/name_spaces/hierarchical_id_trait.hpp>
+#include <string>
+
+using namespace std;
+using namespace boost::channel;
+
+/// definitions of system messages for str_path_id<'/'> ids
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::channel_conn_msg = "/sys/channel_conn_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::channel_disconn_msg = "/sys/channel_disconn_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::init_subscription_info_msg = "/sys/init_subscription_info_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::connection_ready_msg = "/sys/connection_ready_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::subscription_info_msg = "/sys/subscription_info_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::unsubscription_info_msg = "/sys/unsubscription_info_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::publication_info_msg = "/sys/publication_info_msg";
+template <> str_path_id<'/'> id_trait<str_path_id<'/'> >::unpublication_info_msg = "/sys/unpublication_info_msg";
+template <> str_path_id<'/'>::value_type id_trait<str_path_id<'/'> >::root_token = "//";
+template <> str_path_id<'/'>::value_type id_trait<str_path_id<'/'> >::wildcard_token = "*";
+
+/// definitions of system messages for str_path_id<'|'> ids
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::channel_conn_msg = "|sys|channel_conn_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::channel_disconn_msg = "|sys|channel_disconn_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::init_subscription_info_msg = "|sys|init_subscription_info_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::connection_ready_msg = "|sys|connection_ready_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::subscription_info_msg = "|sys|subscription_info_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::unsubscription_info_msg = "|sys|unsubscription_info_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::publication_info_msg = "|sys|publication_info_msg";
+template <> str_path_id<'|'> id_trait<str_path_id<'|'> >::unpublication_info_msg = "|sys|unpublication_info_msg";
+template <> str_path_id<'|'>::value_type id_trait<str_path_id<'|'> >::root_token = "||";
+template <> str_path_id<'|'>::value_type id_trait<str_path_id<'|'> >::wildcard_token = "*";
+
+/// definitions of system messages for str_path_id<'\'> ids
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::channel_conn_msg = "\\sys\\channel_conn_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::channel_disconn_msg = "\\sys\\channel_disconn_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::init_subscription_info_msg = "\\sys\\init_subscription_info_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::connection_ready_msg = "\\sys\\connection_ready_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::subscription_info_msg = "\\sys\\subscription_info_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::unsubscription_info_msg = "\\sys\\unsubscription_info_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::publication_info_msg = "\\sys\\publication_info_msg";
+template <> str_path_id<'\\'> id_trait<str_path_id<'\\'> >::unpublication_info_msg = "\\sys\\unpublication_info_msg";
+template <> str_path_id<'\\'>::value_type id_trait<str_path_id<'\\'> >::root_token = "\\\\";
+template <> str_path_id<'\\'>::value_type id_trait<str_path_id<'\\'> >::wildcard_token = "*";
+
+
+

Added: sandbox/channel/libs/channel/src/linear_id_trait.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/src/linear_id_trait.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,58 @@
+//
+// linear_id_trait.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#define BOOST_CHANNEL_SOURCE
+
+#include <boost/channel/name_spaces/linear_id_trait.hpp>
+#include <string>
+
+using namespace std;
+using namespace boost::channel;
+
+null_id id_trait<null_id>::channel_conn_msg = null_id();
+null_id id_trait<null_id>::channel_disconn_msg = null_id();
+null_id id_trait<null_id>::init_subscription_info_msg = null_id();
+null_id id_trait<null_id>::connection_ready_msg = null_id();
+null_id id_trait<null_id>::subscription_info_msg = null_id();
+null_id id_trait<null_id>::unsubscription_info_msg = null_id();
+null_id id_trait<null_id>::publication_info_msg = null_id();
+null_id id_trait<null_id>::unpublication_info_msg = null_id();
+null_id id_trait<null_id>::app_msg_begin = null_id();
+
+///--- sys msg starts at 1000 ---
+int id_trait<int>::channel_conn_msg=1000;
+int id_trait<int>::channel_disconn_msg=1001;
+int id_trait<int>::init_subscription_info_msg=1002;
+int id_trait<int>::connection_ready_msg=1003;
+int id_trait<int>::subscription_info_msg=1004;
+int id_trait<int>::unsubscription_info_msg=1005;
+int id_trait<int>::publication_info_msg=1006;
+int id_trait<int>::unpublication_info_msg=1007;
+///--- app msg starts at 2000 ---
+int id_trait<int>::app_msg_begin=2000;
+
+/// definitions of system messages for string ids
+string id_trait<string>::channel_conn_msg = "_channel_conn_msg_";
+string id_trait<string>::channel_disconn_msg = "_channel_disconn_msg_";
+string id_trait<string>::init_subscription_info_msg = "_init_subscription_info_msg_";
+string id_trait<string>::connection_ready_msg = "_connection_ready_msg_";
+string id_trait<string>::subscription_info_msg = "_subscription_info_msg_";
+string id_trait<string>::unsubscription_info_msg = "_unsubscription_info_msg_";
+string id_trait<string>::publication_info_msg = "_publication_info_msg_";
+string id_trait<string>::unpublication_info_msg = "_unpublication_info_msg_";
+
+/// definitions of system messages for struct ids
+struct_id id_trait<struct_id>::channel_conn_msg = {system_message, 1};
+struct_id id_trait<struct_id>::channel_disconn_msg = {system_message, 2};
+struct_id id_trait<struct_id>::init_subscription_info_msg = {system_message, 3};
+struct_id id_trait<struct_id>::connection_ready_msg = {system_message, 4};
+struct_id id_trait<struct_id>::subscription_info_msg = {system_message, 5};
+struct_id id_trait<struct_id>::unsubscription_info_msg = {system_message, 6};
+struct_id id_trait<struct_id>::publication_info_msg = {system_message, 7};
+struct_id id_trait<struct_id>::unpublication_info_msg = {system_message, 8};

Added: sandbox/channel/libs/channel/src/name.cpp
==============================================================================
--- (empty file)
+++ sandbox/channel/libs/channel/src/name.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,22 @@
+//
+// name.cpp
+//
+// Copyright (c) 2005-2009 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#define BOOST_CHANNEL_SOURCE
+
+#include <boost/channel/name.hpp>
+
+short
+boost::channel::name_base::scope_checking_tbl_[][name_base::scope_number * name_base::member_number] = {
+ {1, 0, 1, 0, 0, 0},
+ {0, 0, 0, 1, 0, 0},
+ {1, 0, 1, 1, 0, 0},
+ {0, 1, 1, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0}
+};

Added: sandbox/join/boost/join/base/actor.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/base/actor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,1501 @@
+//
+// boost/join/actor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_ACTOR_HPP
+#define BOOST_JOIN_ACTOR_HPP
+
+#include <vector>
+#include <bitset>
+#include <algorithm>
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <boost/join/base/join_base.hpp>
+#include <boost/join/base/exceptions.hpp>
+
+namespace boost {
+ namespace join {
+
+ template <bool flag, typename T, typename U>
+ struct select { typedef T result; };
+ template <typename T, typename U>
+ struct select<false, T, U> { typedef U result; };
+
+ template <size_t size>
+ struct bitmap {
+ enum {
+ max_size = size
+ };
+ typedef typename select<(size<=32), unsigned int, std::bitset<size> >::result bitset_type;
+ bitset_type bitmap_;
+ bitmap(unsigned int val=0) : bitmap_(val) {}
+ void set(bitmap &t) { bitmap_ |= t.bitmap_; }
+ void clear(bitmap &t) { bitmap_ &= ~t.bitmap_; }
+ bool test(bitmap &t) { return (bitmap_ & t.bitmap_) != 0; }
+ bool match(bitmap &b) { return (~bitmap_ & b.bitmap_) == 0; }
+ bool operator==(bitmap &t) { return bitmap_ == t.bitmap_; }
+ size_t num_of_ones(void) {
+ size_t num = 0;
+ for(int i = 0; i<max_size; i++)
+ if (bitmap_ & (1<<i)) num++;
+ return num;
+ }
+ };
+
+ template <typename PortT>
+ typename PortT::var_type
+ top(PortT &p) {
+ return p.top();
+ }
+
+ template <typename PortT, size_t N>
+ boost::array<typename PortT::var_type,N>
+ top(boost::array<PortT,N> &vp) {
+ boost::array<typename PortT::var_type,N> vv;
+ for(size_t i=0; i<N; i++)
+ vv[i] = vp[i].top();
+ return vv;
+ }
+
+ template <typename PortT>
+ void pop_top(PortT &p) {
+ p.pop_top();
+ }
+
+ template <typename PortT, std::size_t N>
+ void pop_top(boost::array<PortT,N> &vp) {
+ for(size_t i=0; i<N; i++)
+ vp[i].pop_top();
+ }
+
+ template <typename PortT>
+ struct var_type {
+ typedef typename PortT::var_type result;
+ };
+
+ template <typename PortT, std::size_t N>
+ struct var_type<boost::array<PortT,N> > {
+ typedef boost::array<typename PortT::var_type,N> result;
+ };
+
+ template <typename PortT>
+ struct res_type {
+ typedef typename PortT::result_type result;
+ };
+
+ template <typename PortT, std::size_t N>
+ struct res_type<boost::array<PortT,N> > {
+ typedef void result;
+ };
+
+ //------- chord definitions ------
+
+ template <size_t max_size>
+ class chord_common : public chord_base {
+ public:
+ actor_base *actor_;
+ bitmap<max_size> mask_;// ports of this chord
+ size_t num_ports_; //for scheduling policy fire_as_much_as_possible
+ port *synch_p_;
+ int priority_; //sched priority of chord: 0 - max, the bigger the lower
+
+ chord_common(bitmap<max_size> &m, port *s, actor_base* a, int pri) :
+ actor_(a), mask_(m), synch_p_(s), priority_(pri) {
+ num_ports_ = m.num_of_ones();
+ }
+
+ chord_base * fire(port *caller_port) {
+ actor_->log.msg("a chord fired");
+ if(caller_port->type_ == port::synch) {//caller is sync
+ //invoke callback later in the same caller thread
+ return this;
+ }
+ else { //caller is async_p
+ //based on ports_, find any synch_port in this chord
+ //and transfer control to its thread and let its thread to run callback
+ if (synch_p_) {
+ (static_cast<synch_port*>(synch_p_))->transfer(this);
+ return 0;
+ }
+ else { //no sync ports in chord
+ if(actor_->has_spawn()) {
+ return this;
+ } else
+ throw no_executor_exception();
+ }
+ }
+ return 0;
+ }
+ };
+
+ template <size_t max_size, typename PortT, typename CallT>
+ class chord1 : public chord_common<max_size>, public chord_oper<typename res_type<PortT>::result> {
+ typedef typename res_type<PortT>::result result_type;
+ public:
+ PortT &port_;
+ CallT call_;
+ chord1(bitmap<max_size> &m, port *sp, actor_base* a, PortT &p, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port_(p), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port_));
+ pop_top(port_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename CallT>
+ class chord2 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ CallT call_;
+ chord2(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a, pri), port1_(p1), port2_(p2), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_));
+ pop_top(port1_);
+ pop_top(port2_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename PortT3, typename CallT>
+ class chord3 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ PortT3 &port3_;
+ CallT call_;
+ chord3(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, PortT3 &p3, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port1_(p1), port2_(p2), port3_(p3), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_), top(port3_));
+ pop_top(port1_);
+ pop_top(port2_);
+ pop_top(port3_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename CallT>
+ class chord4 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ PortT3 &port3_;
+ PortT4 &port4_;
+ CallT call_;
+ chord4(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port1_(p1), port2_(p2), port3_(p3), port4_(p4), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_), top(port3_), top(port4_));
+ pop_top(port1_);
+ pop_top(port2_);
+ pop_top(port3_);
+ pop_top(port4_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename CallT>
+ class chord5 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ PortT3 &port3_;
+ PortT4 &port4_;
+ PortT5 &port5_;
+ CallT call_;
+ chord5(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port1_(p1), port2_(p2), port3_(p3), port4_(p4), port5_(p5), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_), top(port3_), top(port4_), top(port5_));
+ pop_top(port1_);
+ pop_top(port2_);
+ pop_top(port3_);
+ pop_top(port4_);
+ pop_top(port5_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename CallT>
+ class chord6 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ PortT3 &port3_;
+ PortT4 &port4_;
+ PortT5 &port5_;
+ PortT6 &port6_;
+ CallT call_;
+ chord6(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port1_(p1), port2_(p2), port3_(p3), port4_(p4), port5_(p5), port6_(p6), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_), top(port3_), top(port4_), top(port5_), top(port6_));
+ pop_top(port1_);
+ pop_top(port2_);
+ pop_top(port3_);
+ pop_top(port4_);
+ pop_top(port5_);
+ pop_top(port6_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename CallT>
+ class chord7 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ PortT3 &port3_;
+ PortT4 &port4_;
+ PortT5 &port5_;
+ PortT6 &port6_;
+ PortT7 &port7_;
+ CallT call_;
+ chord7(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port1_(p1), port2_(p2), port3_(p3), port4_(p4), port5_(p5), port6_(p6), port7_(p7), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_), top(port3_), top(port4_), top(port5_), top(port6_), top(port7_));
+ pop_top(port1_);
+ pop_top(port2_);
+ pop_top(port3_);
+ pop_top(port4_);
+ pop_top(port5_);
+ pop_top(port6_);
+ pop_top(port7_);
+ }
+ };
+
+ template <size_t max_size, typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename PortT8, typename CallT>
+ class chord8 : public chord_common<max_size>, public chord_oper<typename res_type<PortT1>::result> {
+ typedef typename res_type<PortT1>::result result_type;
+ public:
+ PortT1 &port1_;
+ PortT2 &port2_;
+ PortT3 &port3_;
+ PortT4 &port4_;
+ PortT5 &port5_;
+ PortT6 &port6_;
+ PortT7 &port7_;
+ PortT8 &port8_;
+ CallT call_;
+ chord8(bitmap<max_size> &m, port *sp, actor_base* a, PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, PortT8 &p8, CallT c, int pri) :
+ chord_common<max_size>(m,sp,a,pri), port1_(p1), port2_(p2), port3_(p3), port4_(p4), port5_(p5), port6_(p6), port7_(p7), call_(c) {
+ }
+ void capture_arguments(boost::function0<result_type> &cb) {
+ cb = boost::bind(call_, top(port1_), top(port2_), top(port3_), top(port4_), top(port5_), top(port6_), top(port7_), top(port8_));
+ pop_top(port1_);
+ pop_top(port2_);
+ pop_top(port3_);
+ pop_top(port4_);
+ pop_top(port5_);
+ pop_top(port6_);
+ pop_top(port7_);
+ pop_top(port8_);
+ }
+ };
+
+ //------ schedulers ------
+
+ enum schedule_policy {
+ schedule_first_match, //(first match will fire)
+ schedule_longest_match, //(longest match will fire)
+ schedule_round_robin //(round robin)
+ };
+
+ template <size_t max_size>
+ struct sched_data_base {
+ port *port_;
+ bitmap<max_size> mask_;
+ sched_data_base() :
+ port_(0), mask_(0) {
+ }
+ };
+
+ //basic schedulers
+ template <size_t max_size>
+ struct sched_data : public sched_data_base<max_size> {
+ typedef chord_common<max_size> chord_type;
+ std::vector<chord_type*> chords_; //chords this port participates in
+ sched_data() : sched_data_base<max_size>() {}
+ void port_add_chord(chord_type *c, int) {
+ chords_.push_back(c);
+ }
+ void port_del_chord(chord_type *c, int) {
+ typename std::vector<chord_type*>::iterator iter;
+ if ((iter = std::find(chords_.begin(), chords_.end(), c)) != chords_.end())
+ chords_.erase(iter);
+ bool bound = false;
+ if(chords_.size() > 0) bound = true;
+ if (!bound) this->port_->reset();
+ }
+ };
+
+ template <size_t max_size>
+ struct sched_first_match : public sched_data<max_size> {
+ typedef bitmap<max_size> bitmap_t;
+ typedef chord_common<max_size> chord_type;
+ enum { policy = schedule_first_match };
+ chord_type * scan_chords(bitmap_t status_) {
+ chord_type *chord_ready= 0;
+ for (size_t i=0; i<this->chords_.size() && chord_ready == 0; i++) {
+ if (status_.match(this->chords_[i]->mask_))
+ chord_ready = this->chords_[i];
+ }
+ return chord_ready;
+ }
+ };
+
+ template <size_t max_size>
+ struct sched_longest_match : public sched_data<max_size> {
+ enum { policy = schedule_longest_match };
+ typedef bitmap<max_size> bitmap_t;
+ typedef chord_common<max_size> chord_type;
+ chord_type * scan_chords(bitmap_t status_) {
+ chord_type *chord_ready= 0;
+ size_t chord_size = 0;
+ for(size_t i=0; i<this->chords_.size(); i++) {
+ if(this->chords_[i]->num_ports_ > chord_size && status_.match(this->chords_[i]->mask_)) {
+ chord_ready = this->chords_[i];
+ chord_size = chord_ready->num_ports_;
+ }
+ }
+ return chord_ready;
+ }
+ };
+
+ template <size_t max_size>
+ struct sched_round_robin : public sched_data<max_size> {
+ enum { policy = schedule_round_robin };
+ typedef bitmap<max_size> bitmap_t;
+ typedef chord_common<max_size> chord_type;
+ int last_chord_fired_;
+ sched_round_robin() : sched_data<max_size>(), last_chord_fired_(-1) {}
+ chord_type * scan_chords(bitmap_t status_) {
+ chord_type *chord_ready= 0;
+ size_t min = last_chord_fired_+1;
+ for(size_t j=min; j<this->chords_.size() && chord_ready == 0; j++) {
+ if(status_.match(this->chords_[j]->mask_)) {
+ chord_ready = this->chords_[j];
+ last_chord_fired_ = (int)j;
+ }
+ }
+ if (chord_ready == 0 && min > 0)
+ for(size_t j=0; j<min && chord_ready == 0; j++) {
+ if(status_.match(this->chords_[j]->mask_)) {
+ chord_ready = this->chords_[j];
+ last_chord_fired_ = (int)j;
+ }
+ }
+ return chord_ready;
+ }
+ };
+
+ //simple priority based schedulers
+ template <size_t max_size>
+ struct sched_pri_data : public sched_data_base<max_size> {
+ typedef chord_common<max_size> chord_type;
+ std::vector<std::vector<chord_type*> > chords_; //chords this port participates in
+ sched_pri_data() : sched_data_base<max_size>() {
+ chords_.push_back(std::vector<chord_type*>());
+ }
+ void port_add_chord(chord_type *c, int priority) {
+ if(chords_.size() < ((size_t)priority+1))
+ for(size_t i=chords_.size(); i<((size_t)priority+1); i++) {
+ chords_.push_back(std::vector<chord_type*>());
+ }
+ chords_[priority].push_back(c);
+ }
+ void port_del_chord(chord_type *c, int priority) {
+ typename std::vector<chord_type*>::iterator iter;
+ if ((iter = std::find(chords_[priority].begin(), chords_[priority].end(), c)) != chords_[priority].end())
+ chords_[priority].erase(iter);
+ bool bound = false;
+ for(size_t i=0; i<chords_.size() && !bound; i++)
+ if(chords_[i].size() > 0) bound = true;
+ if (!bound) this->port_->reset();
+ }
+ };
+
+ template <size_t max_size>
+ struct sched_pri_first_match : public sched_pri_data<max_size> {
+ enum { policy = schedule_first_match };
+ typedef bitmap<max_size> bitmap_t;
+ typedef chord_common<max_size> chord_type;
+ chord_type * scan_chords(bitmap_t status_) {
+ chord_type *chord_ready= 0;
+ for(size_t i=0; i<this->chords_.size() && chord_ready == 0; i++)
+ for(size_t j=0; j<this->chords_[i].size() && chord_ready == 0; j++) {
+ if(status_.match(this->chords_[i][j]->mask_))
+ chord_ready = this->chords_[i][j];
+ }
+ return chord_ready;
+ }
+ };
+
+ template <size_t max_size>
+ struct sched_pri_longest_match : public sched_pri_data<max_size> {
+ enum { policy = schedule_longest_match };
+ typedef bitmap<max_size> bitmap_t;
+ typedef chord_common<max_size> chord_type;
+ chord_type * scan_chords(bitmap_t status_) {
+ chord_type *chord_ready= 0;
+ for(size_t i=0; i<this->chords_.size() && chord_ready == 0; i++) {
+ size_t chord_size = 0;
+ for(size_t j=0; j<this->chords_[i].size(); j++) {
+ if(this->chords_[i][j]->num_ports_ > chord_size) {
+ if(status_.match(this->chords_[i][j]->mask_)) {
+ chord_ready = this->chords_[i][j];
+ chord_size = chord_ready->num_ports_;
+ }
+ }
+ }
+ }
+ return chord_ready;
+ }
+ };
+
+ template <size_t max_size>
+ struct sched_pri_round_robin : public sched_pri_data<max_size> {
+ enum { policy = schedule_round_robin };
+ typedef bitmap<max_size> bitmap_t;
+ typedef chord_common<max_size> chord_type;
+ std::vector<int> last_chord_fired_; //for roundrobin dispatching
+ sched_pri_round_robin() : sched_pri_data<max_size>() {
+ last_chord_fired_.push_back(-1);
+ }
+ void port_add_chord(chord_type *c, int priority) {
+ if(this->chords_.size() < ((size_t)priority+1))
+ for(size_t i=this->chords_.size(); i<((size_t)priority+1); i++) {
+ this->chords_.push_back(std::vector<chord_type*>());
+ last_chord_fired_.push_back(-1);
+ }
+ this->chords_[priority].push_back(c);
+ }
+ void port_del_chord(chord_type *c, int priority) {
+ typename std::vector<chord_type*>::iterator iter;
+ if ((iter = std::find(this->chords_[priority].begin(), this->chords_[priority].end(), c)) != this->chords_[priority].end()) {
+ this->chords_[priority].erase(iter);
+ last_chord_fired_[priority] = -1;
+ }
+ bool bound = false;
+ for(size_t i=0; i<this->chords_.size() && !bound; i++)
+ if(this->chords_[i].size() > 0) bound = true;
+ if (!bound) this->port_->reset();
+ }
+ chord_type * scan_chords(bitmap_t status_) {
+ chord_type *chord_ready= 0;
+ for(size_t i=0; i<this->chords_.size() && chord_ready == 0; i++)
+ if(this->chords_[i].size()>0) {
+ size_t min = last_chord_fired_[i]+1;
+ for(size_t j=min; j<this->chords_[i].size() && chord_ready == 0; j++) {
+ if(status_.match(this->chords_[i][j]->mask_)) {
+ chord_ready = this->chords_[i][j];
+ last_chord_fired_[i] = (int)j;
+ }
+ }
+ if (chord_ready == 0 && min > 0)
+ for(size_t j=0; j<min && chord_ready == 0; j++) {
+ if(status_.match(this->chords_[i][j]->mask_)) {
+ chord_ready = this->chords_[i][j];
+ last_chord_fired_[i] = (int)j;
+ }
+ }
+ }
+ return chord_ready;
+ }
+ };
+
+ //------ actor definition ------
+
+ template <
+ typename exec_type=async_p<typename actor_base::callable>,
+ template <size_t> class scheduler=sched_first_match,
+ size_t max_size=32
+ >
+ class actor_t : public actor_base, private boost::noncopyable {
+ template <size_t> friend class chord_common;
+ friend class port;
+
+ public:
+ typedef bitmap<max_size> bitmap_t;
+ typedef scheduler<max_size> sched_type;
+ typedef typename actor_base::callable callable;
+ typedef async_p<typename actor_base::callable> default_executor;
+ typedef exec_type executor; //in fact this is a task que to a real executor
+ typedef chord_common<max_size> chord_type;
+ typedef sched_type port_data;
+
+ private:
+
+ executor *spawn_;
+ bitmap_t status_; //bitmap marking which port is active
+ int heartbeat_;
+ std::vector<port_data> ports_; //all unique ports in this actor, actor not owning
+ //them and will not destroy them, actor will destroy port_data
+ std::vector<boost::shared_ptr<chord_type> > chords_; //actor owns chords_ and will destroy them
+
+ public:
+ actor_t(executor *s = 0,
+ int hb = 0, //forever
+ const char *name = 0) :
+ actor_base(name), spawn_(s), status_(0), heartbeat_(hb) {}
+
+ ~actor_t() {
+ reset();
+ }
+
+ void reset() {
+ boost::mutex::scoped_lock lock(mutex_);
+ internal_reset();
+ }
+
+ bool has_spawn(void) { return spawn_ != 0; }
+ void spawn(callable c) {
+ (*spawn_)(c);
+ }
+
+ boost::function1<void, callable> get_spawn() {
+ return boost::function1<void, callable>(boost::ref(*spawn_));
+ }
+
+ schedule_policy my_scheduler(void) { return static_cast<schedule_policy>(sched_type::policy); }
+ executor *my_executor(void) { return spawn_; }
+
+ bool check_heartbeat(void) {
+ if (heartbeat_ > 0) {
+ heartbeat_--;
+ if (heartbeat_ == 0) {
+ internal_reset();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ void internal_reset() {
+ //reset all related ports
+ for(size_t i=0; i<ports_.size(); i++)
+ ports_[i].port_->reset();
+ ports_.clear();
+ chords_.clear();
+ status_ = bitmap_t(0);
+ }
+
+ //ports call this to notify that a new msg comes
+ //return: true - chord fired, false - chord not fired
+ chord_base * port_invoked(int ind) {
+ port_data &pd(ports_[ind]);
+ pd.port_->num_pending_++;
+ if(status_.test(pd.mask_)) {
+ //already set
+ //log.msg("port_invoked: a port add more pending calls");
+ log.stream() << "port_invoked: a port [" << ind << "] add more pending calls" << logger::endl;
+ //do nothing
+ } else {
+ status_.set(pd.mask_);
+ //log.msg("port_invoked: a empty port get a call");
+ log.stream() << "port_invoked: a empty port [" << ind << "] get a call" << logger::endl;
+ chord_type *c = pd.scan_chords(status_); //find chord to fire based on dispatch_policy
+ if(c != 0) {
+ //update msg arrival status first, mark msgs to be consumed as
+ //"unavailable", kinds of "reserve" these msgs
+ //so that thread-scheduling will not interfere: another thread may come in
+ //between try to take some of these msgs
+ update_status(c->mask_);
+ return c->fire(pd.port_);
+ }
+ }
+ return 0;
+ }
+
+ //one msg will be taken from each port in mask
+ //query these ports to see if any msg remaininf and
+ //if its bit in status_ should be flipped
+ void update_status(bitmap_t &chord_mask) {
+ for(size_t i=0; i<ports_.size(); i++)
+ if(chord_mask.test(ports_[i].mask_)) {
+ ports_[i].port_->num_pending_--;
+ if(ports_[i].port_->num_pending_ == 0)
+ status_.clear(ports_[i].mask_);
+ }
+ }
+
+ void port_revoked(int ind) {
+ port_data &pd(ports_[ind]);
+ pd.port_->num_pending_--;
+ if(pd.port_->num_pending_ == 0)
+ status_.clear(pd.mask_);
+ }
+
+ //
+ // utils methods for creating chords
+ //
+ template <typename PortT>
+ void add_port(PortT &p, bitmap_t &bmap) {
+ port *pp = &p;
+ port_data pd;
+ int ind = -1;
+ if(pp->actor_ != 0 && pp->actor_ != this)
+ throw double_association_exception();
+ for(size_t i=0; i<ports_.size() && ind == -1;i++)
+ if(pp == ports_[i].port_) {
+ ind = (int)i;
+ pd = ports_[i];
+ }
+ if (ind == -1) {
+ ind = (int)ports_.size();
+ if((size_t)ind >= max_size) {
+ log.msg("too_many_ports_exception thrown");
+ throw too_many_ports_exception();
+ }
+ pd.port_ = pp;
+ pd.mask_ = bitmap_t(1<<ind);
+ ports_.push_back(pd);
+ pp->actor_ = this;
+ pp->index_ = ind;
+ pp->num_pending_ = 0;
+ }
+ bmap.set(pd.mask_);
+ }
+ template <typename PortT, std::size_t N>
+ void add_port(boost::array<PortT,N> &vp, bitmap_t &bmap) {
+ for(size_t i=0; i<N; i++)
+ add_port(vp[i], bmap);
+ }
+ template <typename PortT>
+ bool find_port(PortT &p, bitmap_t &bmap) {
+ if(p.actor_ == 0 || p.actor_ != this)
+ return false;
+ bmap.set(ports_[p.index_].mask_);
+ return true;
+ }
+ template <typename PortT, std::size_t N>
+ bool find_port(boost::array<PortT,N> &vp, bitmap_t &bmap) {
+ for(size_t i=0; i<N; i++)
+ if(!find_port(vp[i], bmap))
+ return false;
+ return true;
+ }
+ template <typename PortT>
+ void port_add_chord(PortT &p, chord_type *c, int priority) {
+ port_data &pd(ports_[p.index_]);
+ pd.port_add_chord(c, priority);
+ }
+ template <typename PortT, std::size_t N>
+ void port_add_chord(boost::array<PortT,N> &vp, chord_type *c, int priority) {
+ for(size_t i=0; i<N; i++)
+ port_add_chord(vp[i], c, priority);
+ }
+ template <typename PortT>
+ void port_del_chord(PortT &p, chord_type *c, int priority) {
+ port_data &pd(ports_[p.index_]);
+ pd.port_del_chord(c, priority);
+ }
+ template <typename PortT, std::size_t N>
+ void port_del_chord(boost::array<PortT,N> &vp, chord_type *c, int priority) {
+ for(size_t i=0; i<N; i++)
+ port_del_chord(vp[i], c, priority);
+ }
+ bool find_chord(bitmap_t &bmap, boost::shared_ptr<chord_type> &cd) {
+ for(size_t i=0; i<chords_.size(); i++) {
+ if (chords_[i]->mask_ == bmap) {
+ cd = chords_[i];
+ return true;
+ }
+ }
+ return false;
+ }
+ bool del_chord(bitmap_t &bmap, boost::shared_ptr<chord_type> &cd) {
+ typename std::vector<boost::shared_ptr<chord_type> >::iterator iter;
+ for(iter = chords_.begin(); iter != chords_.end(); iter++) {
+ if ((*iter)->mask_ == bmap) {
+ cd = (*iter);
+ chords_.erase(iter);
+ return true;
+ }
+ }
+ return false;
+ }
+ void chord_data_validation(bitmap_t &bmap) {
+ if (static_cast<schedule_policy>(sched_type::policy) == schedule_first_match) {
+ //check_hidden_chord(bitmap_t &bmap)
+ for(size_t i=0; i<chords_.size(); i++) {
+ if (chords_[i]->mask_.match(bmap) || bmap.match(chords_[i]->mask_))
+ throw hidden_chord_exception();
+ }
+ }
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd))
+ throw hidden_chord_exception();
+ }
+
+ template <typename PortT>
+ typename port::port_type port_type(PortT &p) {
+ return p.type_;
+ }
+ template <typename PortT, std::size_t N>
+ typename port::port_type port_type(boost::array<PortT,N> &vp) {
+ if (vp[0].type_ == port::synch && N > 1)
+ throw single_synch_exception();
+ return vp[0].type_;
+ }
+
+ public:
+
+ //
+ // ***** "factory" methods to create chords ******
+ //
+ //--- chord with 1 port ---
+ template <typename PortT, typename CallT>
+ actor_t& chord(PortT &p, CallT c, int priority=0) {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p) == port::synch) sp = &p;
+ add_port(p, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord1<max_size,PortT,CallT>(bmap, sp, this, p, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT>
+ actor_t& chord_remove(PortT &p) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!find_port(p, bmap))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap,cd))
+ throw chord_remove_exception();
+ port_del_chord(p, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT, typename CallT>
+ actor_t& chord_override(PortT &p, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!find_port(p, bmap))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord1<max_size,PortT,CallT> *cdp = static_cast<chord1<max_size,PortT,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p, cdp, cdp->priority_);
+ port_add_chord(p, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT, typename ActorT, typename R, typename ArgT>
+ actor_t& chord(PortT &p,
+ R (ActorT::*c)(ArgT),
+ int priority=0) {
+ return chord(p, boost::bind(c, static_cast<ActorT*>(this), _1), priority);
+ }
+ template <typename PortT, typename ActorT, typename R, typename ArgT>
+ actor_t& chord_override(PortT &p,
+ R (ActorT::*c)(ArgT),
+ int priority=0) {
+ return chord_override(p, boost::bind(c, static_cast<ActorT*>(this), _1), priority);
+ }
+
+
+ // ---- chord with 2 ports ----
+ template <typename PortT1, typename PortT2, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord2<max_size,PortT1,PortT2,CallT>(bmap, sp, this, p1, p2, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord2<max_size,PortT1,PortT2,CallT>* cdp = static_cast<chord2<max_size,PortT1,PortT2,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename ActorT, typename R, typename ArgT1, typename ArgT2>
+ actor_t& chord(PortT1 &p1, PortT2 &p2,
+ R (ActorT::*c)(ArgT1, ArgT2), int priority=0) {
+ return chord(p1, p2, boost::bind(c, static_cast<ActorT*>(this), _1, _2), priority);
+ }
+ template <typename PortT1, typename PortT2, typename ActorT, typename R, typename ArgT1, typename ArgT2>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2,
+ R (ActorT::*c)(ArgT1, ArgT2), int priority=0) {
+ return chord_override(p1, p2, boost::bind(c, static_cast<ActorT*>(this), _1, _2), priority);
+ }
+
+ //---- chord with 3 ports ---
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch || port_type(p3) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ add_port(p3, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord3<max_size,PortT1,PortT2,PortT3,CallT>(bmap, sp, this, p1, p2, p3, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ port_add_chord(p3,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2, PortT3 &p3) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ port_del_chord(p3, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord3<max_size,PortT1,PortT2,PortT3,CallT>* cdp = static_cast<chord3<max_size,PortT1,PortT2,PortT3,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_del_chord(p3, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ port_add_chord(p3, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename PortT3, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3), int priority=0) {
+ return chord(p1, p2, p3, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3), priority);
+ }
+ template <typename PortT1, typename PortT2, typename PortT3, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3), int priority=0) {
+ return chord_override(p1, p2, p3, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3)), priority;
+ }
+
+ //----- chord with 4 ports -----
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch || port_type(p3) == port::synch || port_type(p4) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ add_port(p3, bmap);
+ add_port(p4, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord4<max_size,PortT1,PortT2,PortT3,PortT4,CallT>(bmap, sp, this, p1, p2, p3, p4, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ port_add_chord(p3,cd.get(),priority);
+ port_add_chord(p4,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ port_del_chord(p3, cd.get(), cd->priority_);
+ port_del_chord(p4, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord4<max_size,PortT1,PortT2,PortT3,PortT4,CallT>* cdp = static_cast<chord4<max_size,PortT1,PortT2,PortT3,PortT4,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_del_chord(p3, cdp, cdp->priority_);
+ port_del_chord(p4, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ port_add_chord(p3, cdp, priority);
+ port_add_chord(p4, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3, ArgT4), int priority=0) {
+ return chord(p1, p2, p3, p4, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4), priority);
+ }
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3, ArgT4), int priority=0) {
+ return chord_override(p1, p2, p3, p4, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4), priority);
+ }
+
+ //----- chord with 5 ports ----
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch || port_type(p3) == port::synch ||
+ port_type(p4) == port::synch || port_type(p5) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ add_port(p3, bmap);
+ add_port(p4, bmap);
+ add_port(p5, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord5<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,CallT>(bmap, sp, this, p1, p2, p3, p4, p5, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ port_add_chord(p3,cd.get(),priority);
+ port_add_chord(p4,cd.get(),priority);
+ port_add_chord(p5,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ port_del_chord(p3, cd.get(), cd->priority_);
+ port_del_chord(p4, cd.get(), cd->priority_);
+ port_del_chord(p5, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord5<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,CallT>* cdp = static_cast<chord5<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_del_chord(p3, cdp, cdp->priority_);
+ port_del_chord(p4, cdp, cdp->priority_);
+ port_del_chord(p5, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ port_add_chord(p3, cdp, priority);
+ port_add_chord(p4, cdp, priority);
+ port_add_chord(p5, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3, ArgT4, ArgT5), int priority=0) {
+ return chord(p1, p2, p3, p4, p5, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5), priority);
+ }
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3, ArgT4, ArgT5), int priority=0) {
+ return chord_override(p1, p2, p3, p4, p5, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5), priority);
+ }
+
+ //----- chord with 6 ports ----
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch || port_type(p3) == port::synch ||
+ port_type(p4) == port::synch || port_type(p5) == port::synch || port_type(p6) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ add_port(p3, bmap);
+ add_port(p4, bmap);
+ add_port(p5, bmap);
+ add_port(p6, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord6<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,CallT>(bmap, sp, this, p1, p2, p3, p4, p5, p6, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ port_add_chord(p3,cd.get(),priority);
+ port_add_chord(p4,cd.get(),priority);
+ port_add_chord(p5,cd.get(),priority);
+ port_add_chord(p6,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap) &&
+ find_port(p6, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ port_del_chord(p3, cd.get(), cd->priority_);
+ port_del_chord(p4, cd.get(), cd->priority_);
+ port_del_chord(p5, cd.get(), cd->priority_);
+ port_del_chord(p6, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap) &&
+ find_port(p6, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord6<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,CallT>* cdp = static_cast<chord6<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_del_chord(p3, cdp, cdp->priority_);
+ port_del_chord(p4, cdp, cdp->priority_);
+ port_del_chord(p5, cdp, cdp->priority_);
+ port_del_chord(p6, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ port_add_chord(p3, cdp, priority);
+ port_add_chord(p4, cdp, priority);
+ port_add_chord(p5, cdp, priority);
+ port_add_chord(p6, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5, typename ArgT6>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6), int priority=0) {
+ return chord(p1, p2, p3, p4, p5, p6, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5, _6), priority);
+ }
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5, typename ArgT6>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6,
+ R (ActorT::*c)(ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6), int priority=0) {
+ return chord_override(p1, p2, p3, p4, p5, p6, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5, _6), priority);
+ }
+
+
+ //----- chord with 7 ports ----
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch || port_type(p3) == port::synch || port_type(p4) == port::synch ||
+ port_type(p5) == port::synch ||port_type( p6) == port::synch || port_type(p7) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ add_port(p3, bmap);
+ add_port(p4, bmap);
+ add_port(p5, bmap);
+ add_port(p6, bmap);
+ add_port(p7, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord7<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,PortT7,CallT>(bmap, sp, this, p1, p2, p3, p4, p5, p6, p7, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ port_add_chord(p3,cd.get(),priority);
+ port_add_chord(p4,cd.get(),priority);
+ port_add_chord(p5,cd.get(),priority);
+ port_add_chord(p6,cd.get(),priority);
+ port_add_chord(p7,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap) &&
+ find_port(p6, bmap) &&
+ find_port(p7, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ port_del_chord(p3, cd.get(), cd->priority_);
+ port_del_chord(p4, cd.get(), cd->priority_);
+ port_del_chord(p5, cd.get(), cd->priority_);
+ port_del_chord(p6, cd.get(), cd->priority_);
+ port_del_chord(p7, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap) &&
+ find_port(p6, bmap) &&
+ find_port(p7, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord7<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,PortT7,CallT>* cdp = static_cast<chord7<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,PortT7,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_del_chord(p3, cdp, cdp->priority_);
+ port_del_chord(p4, cdp, cdp->priority_);
+ port_del_chord(p5, cdp, cdp->priority_);
+ port_del_chord(p6, cdp, cdp->priority_);
+ port_del_chord(p7, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ port_add_chord(p3, cdp, priority);
+ port_add_chord(p4, cdp, priority);
+ port_add_chord(p5, cdp, priority);
+ port_add_chord(p6, cdp, priority);
+ port_add_chord(p7, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5, typename ArgT6, typename ArgT7>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7,
+ R (ActorT::*c)(ArgT1,ArgT2,ArgT3,ArgT4,ArgT5,ArgT6,ArgT7), int priority=0) {
+ return chord(p1, p2, p3, p4, p5, p6, p7, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5, _6, _7), priority);
+ }
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5, typename ArgT6, typename ArgT7>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7,
+ R (ActorT::*c)(ArgT1,ArgT2,ArgT3,ArgT4,ArgT5,ArgT6,ArgT7), int priority=0) {
+ return chord_override(p1, p2, p3, p4, p5, p6, p7, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5, _6, _7), priority);
+ }
+
+
+ //----- chord with 8 ports ----
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename PortT8, typename CallT>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, PortT8 &p8, CallT c, int priority=0)
+ {
+ port *sp = 0;
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if (port_type(p1) == port::synch) sp = &p1;
+ if (port_type(p2) == port::synch || port_type(p3) == port::synch || port_type(p4) == port::synch ||
+ port_type(p5) == port::synch || port_type(p6) == port::synch || port_type(p7) == port::synch || port_type(p8) == port::synch)
+ throw synch_not_1st_exception();
+ add_port(p1, bmap);
+ add_port(p2, bmap);
+ add_port(p3, bmap);
+ add_port(p4, bmap);
+ add_port(p5, bmap);
+ add_port(p6, bmap);
+ add_port(p7, bmap);
+ add_port(p8, bmap);
+ chord_data_validation(bmap);
+ boost::shared_ptr<chord_type> cd(new chord8<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,PortT7,PortT8,CallT>(bmap, sp, this, p1, p2, p3, p4, p5, p6, p7, p8, c, priority));
+ chords_.push_back(cd);
+ port_add_chord(p1,cd.get(),priority);
+ port_add_chord(p2,cd.get(),priority);
+ port_add_chord(p3,cd.get(),priority);
+ port_add_chord(p4,cd.get(),priority);
+ port_add_chord(p5,cd.get(),priority);
+ port_add_chord(p6,cd.get(),priority);
+ port_add_chord(p7,cd.get(),priority);
+ port_add_chord(p8,cd.get(),priority);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename PortT8>
+ actor_t& chord_remove(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, PortT8 &p8) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap) &&
+ find_port(p6, bmap) &&
+ find_port(p7, bmap) &&
+ find_port(p8, bmap)))
+ throw chord_remove_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(!del_chord(bmap, cd))
+ throw chord_remove_exception();
+ port_del_chord(p1, cd.get(), cd->priority_);
+ port_del_chord(p2, cd.get(), cd->priority_);
+ port_del_chord(p3, cd.get(), cd->priority_);
+ port_del_chord(p4, cd.get(), cd->priority_);
+ port_del_chord(p5, cd.get(), cd->priority_);
+ port_del_chord(p6, cd.get(), cd->priority_);
+ port_del_chord(p7, cd.get(), cd->priority_);
+ port_del_chord(p8, cd.get(), cd->priority_);
+ return *this;
+ }
+
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename PortT8, typename CallT>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, PortT8 &p8, CallT c, int priority=0) {
+ bitmap_t bmap;
+ boost::mutex::scoped_lock lock(mutex_);
+ if(!(find_port(p1, bmap) &&
+ find_port(p2, bmap) &&
+ find_port(p3, bmap) &&
+ find_port(p4, bmap) &&
+ find_port(p5, bmap) &&
+ find_port(p6, bmap) &&
+ find_port(p7, bmap) &&
+ find_port(p8, bmap)))
+ throw chord_override_exception();
+ boost::shared_ptr<chord_type> cd;
+ if(find_chord(bmap, cd)) { //override chord
+ chord8<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,PortT7,PortT8,CallT>* cdp = static_cast<chord8<max_size,PortT1,PortT2,PortT3,PortT4,PortT5,PortT6,PortT7,PortT8,CallT>*>(cd.get());
+ cdp->call_ = c;
+ if (cdp->priority_ != priority) {
+ port_del_chord(p1, cdp, cdp->priority_);
+ port_del_chord(p2, cdp, cdp->priority_);
+ port_del_chord(p3, cdp, cdp->priority_);
+ port_del_chord(p4, cdp, cdp->priority_);
+ port_del_chord(p5, cdp, cdp->priority_);
+ port_del_chord(p6, cdp, cdp->priority_);
+ port_del_chord(p7, cdp, cdp->priority_);
+ port_del_chord(p8, cdp, cdp->priority_);
+ port_add_chord(p1, cdp, priority);
+ port_add_chord(p2, cdp, priority);
+ port_add_chord(p3, cdp, priority);
+ port_add_chord(p4, cdp, priority);
+ port_add_chord(p5, cdp, priority);
+ port_add_chord(p6, cdp, priority);
+ port_add_chord(p7, cdp, priority);
+ port_add_chord(p8, cdp, priority);
+ cdp->priority_ = priority;
+ }
+ }
+ else
+ throw chord_override_exception();
+ return *this;
+ }
+
+ //wrappers for pointers to member methods as chord body
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename PortT8, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5, typename ArgT6, typename ArgT7, typename ArgT8>
+ actor_t& chord(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, PortT8 &p8,
+ R (ActorT::*c)(ArgT1,ArgT2,ArgT3,ArgT4,ArgT5,ArgT6,ArgT7,ArgT8), int priority=0) {
+ return chord(p1, p2, p3, p4, p5, p6, p7, p8, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5, _6, _7, _8), priority);
+ }
+ template <typename PortT1, typename PortT2, typename PortT3, typename PortT4, typename PortT5, typename PortT6, typename PortT7, typename PortT8, typename ActorT, typename R, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4, typename ArgT5, typename ArgT6, typename ArgT7, typename ArgT8>
+ actor_t& chord_override(PortT1 &p1, PortT2 &p2, PortT3 &p3, PortT4 &p4, PortT5 &p5, PortT6 &p6, PortT7 &p7, PortT8 &p8,
+ R (ActorT::*c)(ArgT1,ArgT2,ArgT3,ArgT4,ArgT5,ArgT6,ArgT7,ArgT8), int priority=0) {
+ return chord_override(p1, p2, p3, p4, p5, p6, p7, p8, boost::bind(c, static_cast<ActorT*>(this), _1, _2, _3, _4, _5, _6, _7, _8), priority);
+ }
+
+ };
+
+ class actor : public actor_t<> {
+ public:
+ actor(executor *s = 0,
+ int hb = 0,
+ const char *name = 0) :
+ actor_t<>(s,hb,name) {}
+ };
+
+ //alias "actor" to "joint" for flow based programming
+ typedef actor joint;
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/base/exceptions.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/base/exceptions.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,110 @@
+//
+// boost/join/actor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_EXCEPTIONS_HPP
+#define BOOST_JOIN_EXCEPTIONS_HPP
+
+namespace boost {
+ namespace join {
+
+ class join_exception : public std::exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join-related exception";
+ }
+ };
+ class not_in_chord_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: async<>/synch<> methods not in chord (no method body) exception";
+ }
+ };
+ class double_association_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: async<>/synch<> methods associated with more than one actor exception";
+ }
+ };
+ class queue_overflow_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: queue overflow exception";
+ }
+ };
+ class missing_result_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: synch<> method missing result exception";
+ }
+ };
+ class no_executor_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: no executor exception";
+ }
+ };
+ class hidden_chord_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: hidden chord exception";
+ }
+ };
+ class too_many_ports_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: Too many ports defined in a actor";
+ }
+ };
+ class chord_override_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: Chord override failure, chord not found";
+ }
+ };
+ class chord_remove_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: Chord remove failure, chord not found";
+ }
+ };
+ class executor_missing_rr_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: executor's dynamic task queues are used, however non round robin scheduling is defined";
+ }
+ };
+ class synch_not_1st_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: synchronous method is used not as the first method of chord";
+ }
+ };
+ class single_synch_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: more than one synchronous methods are used";
+ }
+ };
+ class port_chord_reset_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: ports or actor are reset unexpectedly";
+ }
+ };
+ class synch_time_out_exception : public join_exception {
+ public:
+ virtual const char *what() const throw () {
+ return "Join: synchronous ports or methods time out unexpectedly";
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/base/join_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/base/join_base.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,101 @@
+//
+// boost/join/actor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_BASE_HPP
+#define BOOST_JOIN_BASE_HPP
+
+#include <string>
+#include <vector>
+#include <boost/thread.hpp>
+#include <boost/function.hpp>
+#include <boost/utility.hpp>
+#include <boost/join/base/utils.hpp>
+#include <boost/join/base/exceptions.hpp>
+#include <boost/array.hpp>
+
+
+namespace boost {
+ namespace join {
+
+ class chord_base;
+ class port;
+
+ class actor_base {
+ public:
+ typedef boost::function0<void> callable;
+ const char * name_;
+ logger log;
+ boost::mutex mutex_; // protects actor global status including ports and chords
+ actor_base(const char *n=0) : name_(n), log(n) {}
+ virtual ~actor_base() {}
+ virtual void reset() = 0;
+ virtual bool check_heartbeat() = 0;
+ virtual void spawn(callable c) = 0;
+ virtual bool has_spawn(void) = 0;
+ virtual boost::function1<void, callable> get_spawn() = 0;
+ virtual chord_base * port_invoked(int ind) = 0;
+ virtual void port_revoked(int ind) = 0;
+ };
+
+ class chord_base {
+ public:
+ virtual ~chord_base() {}
+ };
+
+ template <typename R>
+ class chord_oper {
+ public:
+ virtual void capture_arguments(boost::function0<R> &cb) = 0;
+ virtual ~chord_oper() {}
+ };
+
+ class port {
+ public:
+ enum port_type {
+ async,
+ synch
+ } ;
+ port_type type_;
+ actor_base * actor_; //pointer to owning actor
+ int index_; //my index in actor
+ unsigned int num_pending_; //pending calls/msgs at this port
+
+ port(port_type t=async) :
+ type_(t), actor_(0), index_(-1), num_pending_(0) {
+ }
+ //ports should be only destroyed after all its chords have been destroyed
+ //otherwise delete a port will delete the whole actor
+ virtual ~port() {
+ if (actor_ != 0)
+ actor_->reset();
+ }
+
+ //when detached from actor, need reset
+ //caled from actor destructor
+ virtual void reset(void) {
+ actor_ = 0;
+ index_ = -1;
+ num_pending_ = 0;
+ }
+
+ virtual void PUT(void) {}
+
+ chord_base * test_chord_fire(void) {
+ return actor_->port_invoked(index_);
+ }
+
+ void port_revoked(void) {
+ actor_->port_revoked(index_);
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/base/port.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/base/port.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,738 @@
+//
+// boost/join/port.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_PORT_HPP
+#define BOOST_JOIN_PORT_HPP
+
+#include <exception>
+#include <stdexcept>
+#include <deque>
+#include <iostream>
+#include <boost/shared_ptr.hpp>
+#include <boost/thread/condition.hpp> //for thread backward compatibility
+#include <boost/join/base/join_base.hpp>
+#include <boost/join/base/exceptions.hpp>
+
+namespace boost {
+ namespace join {
+
+ //common interface of async/synch ports to actor(owner)
+ //
+ class actor_base;
+ class chord_base;
+ template <typename ArgT> class async_v;
+ template <typename ResT, typename ArgT> class synch_v;
+ template <typename ArgT> class async_p;
+ template <typename ResT, typename ArgT> class synch_p;
+
+ template <>
+ class async_v<void> {
+ public:
+ ///hacks for compile
+ port *port_;
+ async_v(port *p) : port_(p) {}
+ void operator()(void) {
+ port_->PUT();
+ }
+ };
+
+ template <>
+ class synch_v<void, void> {
+ public:
+ ///hacks for compile
+ port *port_;
+ synch_v(port *p) : port_(p) {}
+ void operator()(void) {
+ port_->PUT();
+ }
+ };
+
+
+ template <typename ArgT>
+ class async_p : public port, private boost::noncopyable {
+ public:
+ typedef ArgT argument_type;
+ typedef void result_type;
+ typedef ArgT arg1_type;
+ typedef ArgT args_type;
+ typedef async_v<ArgT> var_type;
+
+ async_p(size_t sz=0) : port(port::async), max_size_(sz), arg1_(0) {//sz==0 means unlimited
+ }
+
+ void operator()(ArgT t) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ actor_->log.msg("async_p::operator(arg) enter");
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ chord_base *chd = 0;
+ if((chd = test_chord_fire()) != 0) { //notify actor about a new msg
+ arg1_ = &t; //setup my arg
+ boost::function0<void> cb;
+ dynamic_cast<chord_oper<void> *>(chd)->capture_arguments(cb);
+ actor_->log.msg("a new async task spawned");
+ boost::function1<void, actor_base::callable> spawn = actor_->get_spawn(); //spawn callback in executor
+ actor_->check_heartbeat();
+ //if check_heartbeat succeed, actor_ here should be reset to null
+ lock.unlock();
+ spawn(cb);
+ return;
+ }
+ else {
+ arg_.push_back(t);
+ actor_->log.msg("async_p::operator(arg) exit");
+ }
+ }
+ void put(ArgT t) {
+ operator()(t);
+ }
+ ArgT &get(void) {
+ if(arg1_ != 0)
+ return *arg1_;
+ else
+ return arg_.front();
+ }
+ void pop_top(void) {
+ if (arg1_ != 0)
+ arg1_ = 0;
+ else
+ arg_.pop_front();
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ void reset(void) {
+ port::reset();
+ arg_.clear();
+ arg1_ = 0;
+ }
+ private:
+ size_t max_size_;
+ std::deque<ArgT> arg_;
+ ArgT *arg1_;
+ };
+
+ template <>
+ class async_p<void> : public port, private boost::noncopyable {
+ public:
+ typedef void argument_type;
+ typedef void result_type;
+ typedef async_v<void> var_type;
+
+ async_p(size_t sz=0) : port(port::async), max_size_(sz) {
+ }
+
+ void operator()(void) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ actor_->log.msg("async_p::operator(void) enter");
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ chord_base *chd = 0;
+ if((chd = test_chord_fire()) != 0) {
+ boost::function0<void> cb;
+ dynamic_cast<chord_oper<void> *>(chd)->capture_arguments(cb);
+ actor_->log.msg("a new async task spawned");
+ boost::function1<void, actor_base::callable> spawn = actor_->get_spawn(); //spawn callback in executor
+ actor_->check_heartbeat();
+ //if check_heartbeat succeed, actor_ here will be null
+ lock.unlock();
+ spawn(cb);
+ return;
+ }
+ actor_->log.msg("async_p::operator(void) exit");
+ }
+ void put(void) {
+ operator()();
+ }
+ void PUT(void) {
+ operator()();
+ }
+ void pop_top(void) {
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ private:
+ size_t max_size_;
+ };
+
+ class synch_port : public port {
+ public:
+ synch_port() : port(port::synch), num_waiting_(0), fired_(0), reset_(false) {}
+
+ //async call will call this to transfer control
+ void transfer(chord_base* c) {
+ if (fired_ == 0)
+ fired_ = c;
+ else
+ fired_chords_.push_back(c);
+ if (num_waiting_ > 0)
+ cond_.notify_one();
+ actor_->log.msg("transfer");
+ }
+ chord_base * get_fired_chord(void) {
+ chord_base *cd = 0;
+ if (fired_ != 0) {
+ cd = fired_;
+ fired_ = 0;
+ }
+ else {
+ if (!fired_chords_.empty()) { //assigned to complete chord callback
+ cd = fired_chords_.front();
+ fired_chords_.pop_front();
+ }
+ }
+ return cd;
+ }
+
+ void reset(void) {
+ port::reset();
+ fired_ = 0;
+ fired_chords_.clear();
+ reset_ = true;
+ //tell all blocking threads to exit
+ if (num_waiting_ > 0)
+ cond_.notify_all();
+ //actor_->log.msg("reset");
+ }
+
+ protected:
+ boost::condition cond_;
+ size_t num_waiting_;
+ chord_base *fired_;
+ bool reset_;
+ std::deque<chord_base*> fired_chords_;
+ };
+
+ template <typename ResT, typename ArgT>
+ class synch_p : public synch_port, private boost::noncopyable {
+ public:
+ typedef ArgT argument_type;
+ typedef ResT result_type;
+ typedef synch_v<ResT, ArgT> var_type;
+
+ synch_p(size_t sz=0) : max_size_(sz), arg_(0) {//sz==0 means unlimited
+ }
+
+ ResT operator()(ArgT t) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<ResT, ArgT>::operator(t) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<resT,argT> wait");
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<resT,argT> fired");
+ arg_ = &t; //setup my arg
+ boost::function0<ResT> cb;
+ dynamic_cast<chord_oper<ResT> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //should not refer to actor_ after here, since check_hearbeat may reset it
+ lock.unlock();
+ return cb(); //invoke callback in my thread
+ }
+
+ ResT put(ArgT t) {
+ return operator()(t);
+ }
+
+ ResT operator()(ArgT t, const boost::xtime& timeout) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<ResT, ArgT>::operator(t, timeout) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<resT,argT> wait");
+ num_waiting_++;
+ if(!cond_.timed_wait(lock, timeout) && ((chd = get_fired_chord()) == 0)) {
+ port_revoked();
+ num_waiting_--;
+ actor_->log.msg("synch<resT,argT> timeout");
+ throw synch_time_out_exception();
+ }
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ if (chd == 0)
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<resT,argT> fired");
+ arg_ = &t; //setup my arg
+ boost::function0<ResT> cb;
+ dynamic_cast<chord_oper<ResT> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //should not refer to actor_ after here, since check_hearbeat may reset it
+ lock.unlock();
+ return cb(); //invoke callback in my thread
+ }
+
+ ResT put(ArgT t, const boost::xtime& w) {
+ return operator()(t, w);
+ }
+
+ ArgT &get(void) {
+ return *arg_;
+ }
+ void pop_top(void) {
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+
+ private:
+ size_t max_size_;
+ ArgT *arg_;
+ };
+
+
+ template <typename ArgT>
+ class synch_p<void, ArgT> : public synch_port, private boost::noncopyable {
+ public:
+ typedef ArgT argument_type;
+ typedef void result_type;
+ typedef synch_v<void, ArgT> var_type;
+
+ synch_p(size_t sz=0) : max_size_(sz), arg_(0) {//sz==0 means unlimited
+ }
+
+ void operator()(ArgT t) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<void, ArgT>::operator(t) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<void,argT> wait");
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<void, argT> fired");
+ arg_ = &t; //setup my arg
+ boost::function0<void> cb;
+ dynamic_cast<chord_oper<void> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //dont use actor after here
+ lock.unlock();
+ cb(); //invoke callback in my thread
+ return;
+ }
+
+ void put(ArgT t) {
+ operator()(t);
+ }
+
+ void operator()(ArgT t, const boost::xtime& timeout) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<void, ArgT>::operator(t, timeout) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<void,argT> wait");
+ num_waiting_++;
+ if(!cond_.timed_wait(lock, timeout) && ((chd = get_fired_chord()) == 0)) {
+ port_revoked();
+ num_waiting_--;
+ actor_->log.msg("synch<void,argT> timeout");
+ throw synch_time_out_exception();
+ }
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ if (chd == 0)
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<void, argT> fired");
+ arg_ = &t; //setup my arg
+ boost::function0<void> cb;
+ dynamic_cast<chord_oper<void> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //dont use actor after here
+ lock.unlock();
+ cb(); //invoke callback in my thread
+ return;
+ }
+
+ void put(ArgT t, const boost::xtime& w) {
+ operator()(t, w);
+ }
+
+ ArgT &get(void) {
+ return *arg_;
+ }
+ void pop_top(void) {
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+
+ private:
+ size_t max_size_;
+ ArgT *arg_;
+ };
+
+ template <typename ResT>
+ class synch_p<ResT,void> : public synch_port, private boost::noncopyable {
+ public:
+ typedef void argument_type;
+ typedef ResT result_type;
+ typedef synch_v<ResT, void> var_type;
+
+ synch_p(size_t sz=0) : max_size_(sz) {}
+
+ ResT operator()(void) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<ResT,void>::operator(void) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<resT,void> wait");
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<ResT,void> fired");
+ boost::function0<ResT> cb;
+ dynamic_cast<chord_oper<ResT> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //dont use actor after here
+ lock.unlock();
+ return cb(); //invoke callback in my thread
+ }
+
+ ResT put(void) {
+ return operator()();
+ }
+
+ ResT operator()(const boost::xtime& timeout) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<ResT,void>::operator(timeout) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<resT,void> wait");
+ num_waiting_++;
+ if(!cond_.timed_wait(lock, timeout) && ((chd = get_fired_chord()) == 0)) {
+ port_revoked();
+ num_waiting_--;
+ actor_->log.msg("synch<resT,void> timeout");
+ throw synch_time_out_exception();
+ }
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ if (chd == 0)
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<ResT,void> fired");
+ boost::function0<ResT> cb;
+ dynamic_cast<chord_oper<ResT> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //dont use actor after here
+ lock.unlock();
+ return cb(); //invoke callback in my thread
+ }
+
+ ResT put(const boost::xtime& w) {
+ return operator()(w);
+ }
+
+ void pop_top(void) {
+ }
+
+ var_type top(void) {
+ return var_type(this);
+ }
+ private:
+ size_t max_size_;
+ };
+
+
+ template <>
+ class synch_p<void, void> : public synch_port, private boost::noncopyable {
+ public:
+ typedef void argument_type;
+ typedef void result_type;
+ typedef synch_v<void, void> var_type;
+
+ synch_p(size_t sz=0) : max_size_(sz){}
+
+ void operator()(void) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<void,void>::operator(void) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<void,void> wait");
+ num_waiting_++;
+ cond_.wait(lock);
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<void,void> fired");
+ boost::function0<void> cb;
+ dynamic_cast<chord_oper<void> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //dont use actor after here
+ lock.unlock();
+ cb(); //invoke callback in my thread
+ return;
+ }
+
+ void put(void) {
+ operator()();
+ }
+ void PUT(void) {
+ operator()();
+ }
+
+ void operator()(const boost::xtime& timeout) {
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ boost::mutex::scoped_lock lock(actor_->mutex_);
+ if(actor_ == 0)
+ throw not_in_chord_exception();
+ if (max_size_> 0 && num_pending_ >= max_size_)
+ throw queue_overflow_exception();
+
+ actor_->log.msg("synch_p<void,void>::operator(timeout) enter");
+
+ chord_base *chd = test_chord_fire();
+ while (chd == 0) {
+ //no chord ready to fire
+ //block wait here till awaken by another msg
+ actor_->log.msg("synch<void,void> wait");
+ num_waiting_++;
+ if(!cond_.timed_wait(lock, timeout) && ((chd = get_fired_chord()) == 0)) {
+ port_revoked();
+ num_waiting_--;
+ actor_->log.msg("synch<void,void> timeout");
+ throw synch_time_out_exception();
+ }
+ num_waiting_--;
+ if (reset_) {
+ if (num_waiting_ == 0)
+ reset_ = false;
+ throw port_chord_reset_exception();
+ }
+ if (chd == 0)
+ chd = get_fired_chord();
+ }
+ actor_->log.msg("synch<void,void> fired");
+ boost::function0<void> cb;
+ dynamic_cast<chord_oper<void> *>(chd)->capture_arguments(cb);
+ actor_->check_heartbeat();
+ //dont use actor after here
+ lock.unlock();
+ cb(); //invoke callback in my thread
+ return;
+ }
+
+ void put(const boost::xtime& w) {
+ operator()(w);
+ }
+
+ void pop_top(void) {
+ }
+
+ var_type top(void) {
+ return var_type(this);
+ }
+
+ private:
+ size_t max_size_;
+ };
+
+
+ template <typename ArgT>
+ class async_v {
+ public:
+ async_p<ArgT> *port_;
+ ArgT arg1;
+ async_v(async_p<ArgT> *p) :
+ port_(p) {
+ if (port_ != 0)
+ arg1 = port_->get();
+ }
+ operator ArgT() {
+ return arg1;
+ }
+ ArgT &arg(void) {
+ return arg1;
+ }
+ void operator()(ArgT t) {
+ port_->put(t);
+ }
+ };
+
+ template <typename ResT, typename ArgT>
+ class synch_v {
+ public:
+ synch_p<ResT, ArgT> *port_;
+ ArgT arg1;
+ bool ret_flag_;
+ synch_v(synch_p<ResT, ArgT> *p) :
+ port_(p), ret_flag_(false) {
+ arg1 = port_->get();
+ }
+ operator ArgT(void) {
+ return arg1;
+ }
+ ArgT &arg(void) {
+ return arg1;
+ }
+ ResT operator()(ArgT t) {
+ return port_->put(t);
+ }
+ };
+
+ template <typename ArgT>
+ class synch_v<void, ArgT> {
+ public:
+ synch_p<void, ArgT> *port_;
+ ArgT arg1;
+ bool ret_flag_;
+ synch_v(synch_p<void, ArgT> *p) :
+ port_(p), ret_flag_(false) {
+ arg1 = port_->get();
+ }
+ operator ArgT(void) {
+ return arg1;
+ }
+ ArgT &arg(void) {
+ return arg1;
+ }
+ void operator()(ArgT t) {
+ port_->put(t);
+ }
+ };
+
+ template <typename ResT>
+ class synch_v<ResT, void> {
+ public:
+ synch_p<ResT, void> *port_;
+ bool ret_flag_;
+ synch_v(synch_p<ResT, void> *p) :
+ port_(p), ret_flag_(false) {}
+ ResT operator()(void) {
+ return port_->put();
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/base/port_sig.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/base/port_sig.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,1449 @@
+//
+// boost/join/port_sig.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_PORT_SIG_HPP
+#define BOOST_JOIN_PORT_SIG_HPP
+
+#include <boost/join/base/port.hpp>
+#include <boost/type_traits/function_traits.hpp>
+
+namespace boost {
+ namespace join {
+
+ template <typename Signature>
+ class async_o;
+
+ template <typename Signature>
+ class synch_o;
+
+ namespace detail {
+
+ //---- argument wrappers for async<>/synch<> methods
+ template <typename T1>
+ class args1 {
+ public:
+ T1 arg1;
+ args1(T1 a1): arg1(a1) {}
+ args1() {}
+ };
+
+ template <typename T1, typename T2>
+ class args2 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ args2(T1 a1, T2 a2): arg1(a1), arg2(a2) {}
+ args2() {}
+ };
+
+ template <typename T1, typename T2, typename T3>
+ class args3 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ T3 arg3;
+ args3(T1 a1, T2 a2, T3 a3): arg1(a1), arg2(a2), arg3(a3) {}
+ args3() {}
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4>
+ class args4 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ T3 arg3;
+ T4 arg4;
+ args4(T1 a1, T2 a2, T3 a3, T4 a4): arg1(a1), arg2(a2), arg3(a3), arg4(a4) {}
+ args4() {}
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ class args5 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ T3 arg3;
+ T4 arg4;
+ T5 arg5;
+ args5(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5): arg1(a1), arg2(a2), arg3(a3), arg4(a4), arg5(a5) {}
+ args5() {}
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+ class args6 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ T3 arg3;
+ T4 arg4;
+ T5 arg5;
+ T6 arg6;
+ args6(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6): arg1(a1), arg2(a2), arg3(a3), arg4(a4), arg5(a5), arg6(a6) {}
+ args6() {}
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+ class args7 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ T3 arg3;
+ T4 arg4;
+ T5 arg5;
+ T6 arg6;
+ T7 arg7;
+ args7(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7): arg1(a1), arg2(a2), arg3(a3), arg4(a4), arg5(a5), arg6(a6), arg7(a7) {}
+ args7() {}
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+ class args8 {
+ public:
+ T1 arg1;
+ T2 arg2;
+ T3 arg3;
+ T4 arg4;
+ T5 arg5;
+ T6 arg6;
+ T7 arg7;
+ T8 arg8;
+ args8(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8): arg1(a1), arg2(a2), arg3(a3), arg4(a4), arg5(a5), arg6(a6), arg7(a7), arg8(a8) {}
+ args8() {}
+ };
+
+
+ //---- for async methods ----
+
+ template <typename Signature>
+ class async0 : public async_p<void> {
+ public:
+ typedef void arg1_type;
+ typedef void args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<void> base_type;
+
+ async0(size_t sz=0) : base_type(sz) {}
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T, typename Signature>
+ class async1 : public async_p<args1<T> > {
+ public:
+ typedef T arg1_type;
+ typedef args1<T> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args1<T> > base_type;
+
+ async1(size_t sz=0) : base_type(sz) {}
+ void operator()(T a1) {
+ base_type::put(args_type(a1));
+ }
+ void put(T a1) {
+ base_type::put(args_type(a1));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T, typename Signature>
+ class async1_v : public args1<T> {
+ public:
+ typedef args1<T> args_type;
+ typedef async1<T, Signature> port_type;
+ port_type *port_;
+ async1_v(port_type *p): args_type(p->get().arg1), port_(p) {}
+ async1_v() {}
+ void operator()(T a1) {
+ port_->put(a1);
+ }
+ operator T() {
+ return this->arg1;
+ }
+ /* ???need redo for ref arg
+ T &arg(void) {
+ return this->arg1;
+ }
+ */
+ };
+
+
+ template <typename T1, typename T2, typename Signature>
+ class async2 : public async_p<args2<T1,T2> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef args2<T1,T2> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args2<T1,T2> > base_type;
+
+ async2(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2) {
+ base_type::put(args_type(a1,a2));
+ }
+ void put(T1 a1, T2 a2) {
+ base_type::put(args_type(a1,a2));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename Signature>
+ class async2_v : public args2<T1,T2> {
+ public:
+ typedef args2<T1,T2> args_type;
+ typedef async2<T1, T2, Signature> port_type;
+ port_type *port_;
+ async2_v(port_type *p): args_type(p->get().arg1, p->get().arg2), port_(p) {}
+ async2_v() {}
+ void operator()(T1 a1, T2 a2) {
+ port_->put(a1,a2);
+ }
+ };
+
+
+ template <typename T1, typename T2, typename T3, typename Signature>
+ class async3 : public async_p<args3<T1,T2,T3> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef args3<T1,T2,T3> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args3<T1,T2,T3> > base_type;
+
+ async3(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2, T3 a3) {
+ base_type::put(args_type(a1,a2,a3));
+ }
+ void put(T1 a1, T2 a2, T3 a3) {
+ base_type::put(args_type(a1,a2,a3));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename Signature>
+ class async3_v : public args3<T1,T2,T3> {
+ public:
+ typedef args3<T1,T2,T3> args_type;
+ typedef async3<T1, T2, T3, Signature> port_type;
+ port_type *port_;
+ async3_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3), port_(p) {}
+ async3_v() {}
+ void operator()(T1 a1, T2 a2, T3 a3) {
+ port_->put(a1,a2,a3);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename Signature>
+ class async4 : public async_p<args4<T1,T2,T3,T4> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef args4<T1,T2,T3,T4> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args4<T1,T2,T3,T4> > base_type;
+
+ async4(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4) {
+ base_type::put(args_type(a1,a2,a3,a4));
+ }
+ void put(T1 a1, T2 a2, T3 a3, T4 a4) {
+ base_type::put(args_type(a1,a2,a3,a4));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename Signature>
+ class async4_v : public args4<T1,T2,T3,T4> {
+ public:
+ typedef args4<T1,T2,T3,T4> args_type;
+ typedef async4<T1, T2, T3, T4, Signature> port_type;
+ port_type *port_;
+ async4_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4), port_(p) {}
+ async4_v() {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4) {
+ port_->put(a1,a2,a3,a4);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename Signature>
+ class async5 : public async_p<args5<T1,T2,T3,T4,T5> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef args5<T1,T2,T3,T4,T5> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args5<T1,T2,T3,T4,T5> > base_type;
+
+ async5(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ base_type::put(args_type(a1,a2,a3,a4,a5));
+ }
+ void put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ base_type::put(args_type(a1,a2,a3,a4,a5));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename Signature>
+ class async5_v : public args5<T1,T2,T3,T4,T5> {
+ public:
+ typedef args5<T1,T2,T3,T4,T5> args_type;
+ typedef async5<T1, T2, T3, T4, T5, Signature> port_type;
+ port_type *port_;
+ async5_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5), port_(p) {}
+ async5_v() {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ port_->put(a1,a2,a3,a4,a5);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename Signature>
+ class async6 : public async_p<args6<T1,T2,T3,T4,T5,T6> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef T6 arg6_type;
+ typedef args6<T1,T2,T3,T4,T5,T6> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args6<T1,T2,T3,T4,T5,T6> > base_type;
+
+ async6(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ base_type::put(args_type(a1,a2,a3,a4,a5,a6));
+ }
+ void put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ base_type::put(args_type(a1,a2,a3,a4,a5,a6));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename Signature>
+ class async6_v : public args6<T1,T2,T3,T4,T5,T6> {
+ public:
+ typedef args6<T1,T2,T3,T4,T5,T6> args_type;
+ typedef async6<T1, T2, T3, T4, T5, T6, Signature> port_type;
+ port_type *port_;
+ async6_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6), port_(p) {}
+ async6_v() {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ port_->put(a1,a2,a3,a4,a5,a6);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename Signature>
+ class async7 : public async_p<args7<T1,T2,T3,T4,T5,T6,T7> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef T6 arg6_type;
+ typedef T7 arg7_type;
+ typedef args7<T1,T2,T3,T4,T5,T6,T7> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args7<T1,T2,T3,T4,T5,T6,T7> > base_type;
+
+ async7(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7));
+ }
+ void put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename Signature>
+ class async7_v : public args7<T1,T2,T3,T4,T5,T6,T7> {
+ public:
+ typedef args7<T1,T2,T3,T4,T5,T6,T7> args_type;
+ typedef async7<T1, T2, T3, T4, T5, T6, T7, Signature> port_type;
+ port_type *port_;
+ async7_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6, p->get().arg7), port_(p) {}
+ async7_v() {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ port_->put(a1,a2,a3,a4,a5,a6,a7);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename Signature>
+ class async8 : public async_p<args8<T1,T2,T3,T4,T5,T6,T7,T8> > {
+ public:
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef T6 arg6_type;
+ typedef T7 arg7_type;
+ typedef T8 arg8_type;
+ typedef args8<T1,T2,T3,T4,T5,T6,T7,T8> args_type;
+ typedef async_o<Signature> var_type;
+ typedef async_p<args8<T1,T2,T3,T4,T5,T6,T7,T8> > base_type;
+
+ async8(size_t sz=0) : base_type(sz) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7,a8));
+ }
+ void put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7,a8));
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename Signature>
+ class async8_v : public args8<T1,T2,T3,T4,T5,T6,T7,T8> {
+ public:
+ typedef args8<T1,T2,T3,T4,T5,T6,T7,T8> args_type;
+ typedef async8<T1, T2, T3, T4, T5, T6, T7, T8, Signature> port_type;
+ port_type *port_;
+ async8_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6, p->get().arg7, p->get().arg8), port_(p) {}
+ async8_v() {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ port_->put(a1,a2,a3,a4,a5,a6,a7,a8);
+ }
+ };
+
+
+ //--- templates to help signature ---
+
+ //--- for async
+ template<int Arity, typename Signature>
+ class real_get_async_impl;
+
+ template<typename Signature>
+ class real_get_async_impl<0, Signature>
+ {
+ public:
+ typedef async0<Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<1, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async1<typename traits::arg1_type, Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<2, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async2<typename traits::arg1_type,
+ typename traits::arg2_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<3, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async3<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<4, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async4<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<5, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async5<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<6, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async6<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<7, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async7<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_impl<8, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async8<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ typename traits::arg8_type,
+ Signature> type;
+ };
+
+
+ template<typename Signature>
+ struct get_async_impl :
+ public real_get_async_impl<(function_traits<Signature>::arity),
+ Signature>
+ {
+ };
+
+ //--- for async_v
+ template<int Arity, typename Signature>
+ class real_get_async_v_impl;
+
+ template<typename Signature>
+ class real_get_async_v_impl<0, Signature>
+ {
+ public:
+ typedef async_v<void> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<1, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async1_v<typename traits::arg1_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<2, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async2_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<3, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async3_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<4, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async4_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<5, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async5_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<6, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async6_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<7, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async7_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_async_v_impl<8, Signature>
+ {
+ typedef function_traits<Signature> traits;
+
+ public:
+ typedef async8_v<typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ typename traits::arg8_type,
+ Signature> type;
+ };
+
+
+ template<typename Signature>
+ struct get_async_v_impl :
+ public real_get_async_v_impl<(function_traits<Signature>::arity),
+ Signature>
+ {
+ };
+
+
+ //--- for synch methods ---
+
+ template <typename R, typename Signature>
+ class synch0 : public synch_p<R,void> {
+ public:
+ typedef R result_type;
+ typedef void arg1_type;
+ typedef void args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R,void> base_type;
+
+ synch0(size_t sz=0) : base_type(sz) {}
+ R operator()(void) {
+ return base_type::put();
+ }
+ R put(void) {
+ return base_type::put();
+ }
+ R operator()(const boost::xtime& timeout) {
+ return base_type::put(timeout);
+ }
+ R put(const boost::xtime& timeout) {
+ return base_type::put(timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T, typename Signature>
+ class synch1 : public synch_p<R, T> {
+ public:
+ typedef R result_type;
+ typedef T arg1_type;
+ typedef T args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, T> base_type;
+
+ synch1(size_t sz=0) : base_type(sz) {}
+ R operator()(T a1) {
+ return base_type::put(a1);
+ }
+ R put(T a1) {
+ return base_type::put(a1);
+ }
+ R operator()(T a1, const boost::xtime& timeout) {
+ return base_type::put(a1, timeout);
+ }
+ R put(T a1, const boost::xtime& timeout) {
+ return base_type::put(a1, timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename Signature>
+ class synch2 : public synch_p<R, args2<T1,T2> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef args2<T1,T2> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args2<T1,T2> > base_type;
+
+ synch2(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2) {
+ return base_type::put(args_type(a1,a2));
+ }
+ R put(T1 a1, T2 a2) {
+ return base_type::put(args_type(a1,a2));
+ }
+ R operator()(T1 a1, T2 a2, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2), timeout);
+ }
+ R put(T1 a1, T2 a2, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename Signature>
+ class synch2_v : public args2<T1,T2> {
+ public:
+ typedef args2<T1,T2> args_type;
+ typedef synch2<R, T1, T2, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch2_v(port_type *p): args_type(p->get().arg1, p->get().arg2), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2) {
+ return port_->put(a1,a2);
+ }
+ };
+ template <typename T1, typename T2, typename Signature>
+ class synch2_v<void,T1,T2,Signature> : public args2<T1,T2> {
+ public:
+ typedef args2<T1,T2> args_type;
+ typedef synch2<void, T1, T2, Signature> port_type;
+ port_type *port_;
+ synch2_v(port_type *p): args_type(p->get().arg1, p->get().arg2), port_(p) {}
+ void operator()(T1 a1, T2 a2) {
+ port_->put(a1,a2);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename Signature>
+ class synch3 : public synch_p<R, args3<T1,T2,T3> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef args3<T1,T2,T3> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args3<T1,T2,T3> > base_type;
+
+ synch3(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2, T3 a3) {
+ return base_type::put(args_type(a1,a2,a3));
+ }
+ R put(T1 a1, T2 a2, T3 a3) {
+ return base_type::put(args_type(a1,a2,a3));
+ }
+ R operator()(T1 a1, T2 a2, T3 a3, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3), timeout);
+ }
+ R put(T1 a1, T2 a2, T3 a3, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename Signature>
+ class synch3_v : public args3<T1,T2,T3> {
+ public:
+ typedef args3<T1,T2,T3> args_type;
+ typedef synch3<R, T1, T2, T3, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch3_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2, T3 a3) {
+ return port_->put(a1,a2,a3);
+ }
+ };
+ template <typename T1, typename T2, typename T3, typename Signature>
+ class synch3_v<void,T1,T2,T3,Signature> : public args3<T1,T2,T3> {
+ public:
+ typedef args3<T1,T2,T3> args_type;
+ typedef synch3<void, T1, T2, T3, Signature> port_type;
+ port_type *port_;
+ synch3_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3), port_(p) {}
+ void operator()(T1 a1, T2 a2, T3 a3) {
+ port_->put(a1,a2,a3);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename Signature>
+ class synch4 : public synch_p<R, args4<T1,T2,T3,T4> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef args4<T1,T2,T3,T4> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args4<T1,T2,T3,T4> > base_type;
+
+ synch4(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4) {
+ return base_type::put(args_type(a1,a2,a3,a4));
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4) {
+ return base_type::put(args_type(a1,a2,a3,a4));
+ }
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4), timeout);
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename Signature>
+ class synch4_v : public args4<T1,T2,T3,T4> {
+ public:
+ typedef args4<T1,T2,T3,T4> args_type;
+ typedef synch4<R, T1, T2, T3, T4, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch4_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4) {
+ return port_->put(a1,a2,a3,a4);
+ }
+ };
+ template <typename T1, typename T2, typename T3, typename T4, typename Signature>
+ class synch4_v<void,T1,T2,T3,T4,Signature> : public args4<T1,T2,T3,T4> {
+ public:
+ typedef args4<T1,T2,T3,T4> args_type;
+ typedef synch4<void, T1, T2, T3, T4, Signature> port_type;
+ port_type *port_;
+ synch4_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4), port_(p) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4) {
+ port_->put(a1,a2,a3,a4);
+ }
+ };
+
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename Signature>
+ class synch5 : public synch_p<R, args5<T1,T2,T3,T4,T5> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef args5<T1,T2,T3,T4,T5> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args5<T1,T2,T3,T4,T5> > base_type;
+
+ synch5(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5));
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5));
+ }
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5), timeout);
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename Signature>
+ class synch5_v : public args5<T1,T2,T3,T4,T5> {
+ public:
+ typedef args5<T1,T2,T3,T4,T5> args_type;
+ typedef synch5<R, T1, T2, T3, T4, T5, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch5_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ return port_->put(a1,a2,a3,a4,a5);
+ }
+ };
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename Signature>
+ class synch5_v<void,T1,T2,T3,T4,T5,Signature> : public args5<T1,T2,T3,T4,T5> {
+ public:
+ typedef args5<T1,T2,T3,T4,T5> args_type;
+ typedef synch5<void, T1, T2, T3, T4, T5, Signature> port_type;
+ port_type *port_;
+ synch5_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5), port_(p) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) {
+ port_->put(a1,a2,a3,a4,a5);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename Signature>
+ class synch6 : public synch_p<R, args6<T1,T2,T3,T4,T5,T6> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef T6 arg6_type;
+ typedef args6<T1,T2,T3,T4,T5,T6> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args6<T1,T2,T3,T4,T5,T6> > base_type;
+
+ synch6(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6));
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6));
+ }
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6), timeout);
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename Signature>
+ class synch6_v : public args6<T1,T2,T3,T4,T5,T6> {
+ public:
+ typedef args6<T1,T2,T3,T4,T5,T6> args_type;
+ typedef synch6<R, T1, T2, T3, T4, T5, T6, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch6_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ return port_->put(a1,a2,a3,a4,a5,a6);
+ }
+ };
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename Signature>
+ class synch6_v<void,T1,T2,T3,T4,T5,T6,Signature> : public args6<T1,T2,T3,T4,T5,T6> {
+ public:
+ typedef args6<T1,T2,T3,T4,T5,T6> args_type;
+ typedef synch6<void, T1, T2, T3, T4, T5, T6, Signature> port_type;
+ port_type *port_;
+ synch6_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6), port_(p) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) {
+ port_->put(a1,a2,a3,a4,a5,a6);
+ }
+ };
+
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename Signature>
+ class synch7 : public synch_p<R, args7<T1,T2,T3,T4,T5,T6,T7> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef T6 arg6_type;
+ typedef T7 arg7_type;
+ typedef args7<T1,T2,T3,T4,T5,T6,T7> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args7<T1,T2,T3,T4,T5,T6,T7> > base_type;
+
+ synch7(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7));
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7));
+ }
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7), timeout);
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename Signature>
+ class synch7_v : public args7<T1,T2,T3,T4,T5,T6,T7> {
+ public:
+ typedef args7<T1,T2,T3,T4,T5,T6,T7> args_type;
+ typedef synch7<R, T1, T2, T3, T4, T5, T6, T7, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch7_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6, p->get().arg7), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ return port_->put(a1,a2,a3,a4,a5,a6,a7);
+ }
+ };
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename Signature>
+ class synch7_v<void,T1,T2,T3,T4,T5,T6,T7,Signature> : public args7<T1,T2,T3,T4,T5,T6,T7> {
+ public:
+ typedef args7<T1,T2,T3,T4,T5,T6,T7> args_type;
+ typedef synch7<void, T1, T2, T3, T4, T5, T6, T7, Signature> port_type;
+ port_type *port_;
+ synch7_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6, p->get().arg7), port_(p) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) {
+ port_->put(a1,a2,a3,a4,a5,a6,a7);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename Signature>
+ class synch8 : public synch_p<R, args8<T1,T2,T3,T4,T5,T6,T7,T8> > {
+ public:
+ typedef R result_type;
+ typedef T1 arg1_type;
+ typedef T2 arg2_type;
+ typedef T3 arg3_type;
+ typedef T4 arg4_type;
+ typedef T5 arg5_type;
+ typedef T6 arg6_type;
+ typedef T7 arg7_type;
+ typedef T8 arg8_type;
+ typedef args8<T1,T2,T3,T4,T5,T6,T7,T8> args_type;
+ typedef synch_o<Signature> var_type;
+ typedef synch_p<R, args8<T1,T2,T3,T4,T5,T6,T7,T8> > base_type;
+
+ synch8(size_t sz=0) : base_type(sz) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7,a8));
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7,a8));
+ }
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7,a8), timeout);
+ }
+ R put(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, const boost::xtime& timeout) {
+ return base_type::put(args_type(a1,a2,a3,a4,a5,a6,a7,a8), timeout);
+ }
+ var_type top(void) {
+ return var_type(this);
+ }
+ };
+
+ template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename Signature>
+ class synch8_v : public args8<T1,T2,T3,T4,T5,T6,T7,T8> {
+ public:
+ typedef args8<T1,T2,T3,T4,T5,T6,T7,T8> args_type;
+ typedef synch8<R, T1, T2, T3, T4, T5, T6, T7, T8, Signature> port_type;
+ port_type *port_;
+ bool ret_flag_;
+ synch8_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6, p->get().arg7, p->get().arg8), port_(p), ret_flag_(false) {}
+ R operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ return port_->put(a1,a2,a3,a4,a5,a6,a7,a8);
+ }
+ };
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename Signature>
+ class synch8_v<void,T1,T2,T3,T4,T5,T6,T7,T8,Signature> : public args8<T1,T2,T3,T4,T5,T6,T7,T8> {
+ public:
+ typedef args8<T1,T2,T3,T4,T5,T6,T7,T8> args_type;
+ typedef synch8<void, T1, T2, T3, T4, T5, T6, T7, T8, Signature> port_type;
+ port_type *port_;
+ synch8_v(port_type *p): args_type(p->get().arg1, p->get().arg2, p->get().arg3, p->get().arg4, p->get().arg5, p->get().arg6, p->get().arg7, p->get().arg8), port_(p) {}
+ void operator()(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) {
+ port_->put(a1,a2,a3,a4,a5,a6,a7,a8);
+ }
+ };
+
+
+ //--- templates to help signature ---
+
+ //--- for synch
+ template<int Arity, typename Signature>
+ class real_get_synch_impl;
+
+ template<typename Signature>
+ class real_get_synch_impl<0, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch0<typename traits::result_type, Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<1, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch1<typename traits::result_type,
+ typename traits::arg1_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<2, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch2<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<3, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch3<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<4, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch4<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<5, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch5<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<6, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch6<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<7, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch7<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_impl<8, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch8<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ typename traits::arg8_type,
+ Signature> type;
+ };
+
+
+ template<typename Signature>
+ struct get_synch_impl :
+ public real_get_synch_impl<(function_traits<Signature>::arity),
+ Signature>
+ {
+ };
+
+ //--- for synch_v
+ template<int Arity, typename Signature>
+ class real_get_synch_v_impl;
+
+ template<typename Signature>
+ class real_get_synch_v_impl<0, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch_v<typename traits::result_type, void> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_v_impl<1, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch_v<typename traits::result_type,
+ typename traits::arg1_type> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_v_impl<2, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch2_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_v_impl<3, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch3_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_v_impl<4, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch4_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ Signature> type;
+ };
+
+
+ template<typename Signature>
+ class real_get_synch_v_impl<5, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch5_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_v_impl<6, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch6_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ Signature> type;
+ };
+
+
+ template<typename Signature>
+ class real_get_synch_v_impl<7, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch7_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ Signature> type;
+ };
+
+ template<typename Signature>
+ class real_get_synch_v_impl<8, Signature>
+ {
+ typedef function_traits<Signature> traits;
+ public:
+ typedef synch8_v<typename traits::result_type,
+ typename traits::arg1_type,
+ typename traits::arg2_type,
+ typename traits::arg3_type,
+ typename traits::arg4_type,
+ typename traits::arg5_type,
+ typename traits::arg6_type,
+ typename traits::arg7_type,
+ typename traits::arg8_type,
+ Signature> type;
+ };
+
+
+ template<typename Signature>
+ struct get_synch_v_impl :
+ public real_get_synch_v_impl<(function_traits<Signature>::arity),
+ Signature>
+ {
+ };
+
+ }
+
+ template<typename Signature>
+ class synch :
+ public detail::get_synch_impl<Signature>::type
+ {
+ typedef typename detail::get_synch_impl<Signature>::type base_type;
+
+ public:
+ explicit synch(size_t sz=0) : base_type(sz) {}
+ };
+
+ template<typename Signature>
+ class synch_o :
+ public detail::get_synch_v_impl<Signature>::type
+ {
+ typedef typename detail::get_synch_v_impl<Signature>::type base_type;
+ typedef typename detail::get_synch_impl<Signature>::type port_type;
+
+ public:
+ explicit synch_o(port_type *p) : base_type(p) {}
+ };
+
+ template<typename Signature>
+ class async :
+ public detail::get_async_impl<Signature>::type
+ {
+ typedef typename detail::get_async_impl<Signature>::type base_type;
+
+ public:
+ explicit async(size_t sz=0) : base_type(sz) {}
+ };
+
+ template<typename Signature>
+ class async_o :
+ public detail::get_async_v_impl<Signature>::type
+ {
+ typedef typename detail::get_async_v_impl<Signature>::type base_type;
+ typedef typename detail::get_async_impl<Signature>::type port_type;
+
+ public:
+ explicit async_o(port_type *p) : base_type(p) {}
+ explicit async_o() : base_type() {}
+ };
+
+
+ }
+}
+
+
+#endif

Added: sandbox/join/boost/join/base/utils.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/base/utils.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,77 @@
+//
+// boost/join/actor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_UTILS_HPP
+#define BOOST_JOIN_UTILS_HPP
+
+#include <iostream>
+#include <string>
+#include <boost/thread.hpp>
+#include <sstream>
+
+namespace boost {
+ namespace join {
+
+ class logger : public std::ostringstream {
+ public:
+ const char *name_;
+ static boost::mutex mutex_;
+
+ logger(const char *n = 0) : name_(n) {
+ }
+
+ void msg(std::string str) {
+ if (name_ == 0) return;
+ boost::mutex::scoped_lock lock(mutex_);
+ std::cout << "[" << name_ << "] : " << str << std::endl;
+ }
+ std::ostringstream & stream(void) {
+ boost::mutex::scoped_lock lock(mutex_);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ return *(new logger(name_));
+#else
+ return *this;
+#endif
+ }
+ void flush(void) {
+ boost::mutex::scoped_lock lock(mutex_);
+ if(name_ != 0)
+ std::cout << "[" << name_ << "] " << this->str();
+ this->str("");
+ }
+ void flushl(void) {
+ boost::mutex::scoped_lock lock(mutex_);
+ if(name_ != 0)
+ std::cout << "[" << name_ << "] " << this->str() << std::endl;
+ this->str("");
+ }
+ typedef void func(logger &l);
+ static void end(logger &l) {
+ l.flush();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ delete &l;
+#endif
+ }
+ static void endl(logger &l) {
+ l.flushl();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ delete &l;
+#endif
+ }
+ };
+ std::ostream &operator << (std::ostream &os, logger::func *f) {
+ f((logger&)os);
+ return os;
+ }
+ boost::mutex logger::mutex_;
+ }
+}
+
+#endif
+

Added: sandbox/join/boost/join/idioms/asio_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/idioms/asio_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,34 @@
+//
+// boost/join/executor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_ASIO_EXECUTOR_HPP
+#define BOOST_JOIN_ASIO_EXECUTOR_HPP
+
+#include <boost/asio.hpp>
+#include <boost/join/join.hpp>
+
+namespace boost {
+ namespace join {
+
+ //integration with Boost.Asio
+ //submit async tasks to asio's completion_event queue to be executed by main thread
+ class asio_executor {
+ public:
+ boost::asio::io_service& io_service_;
+ asio_executor(boost::asio::io_service& io_service): io_service_(io_service) {}
+ template <typename task_type>
+ void operator()(task_type task) {
+ io_service_.post(task);
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/idioms/executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/idioms/executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,106 @@
+//
+// boost/join/executor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_SIMPLE_EXECUTOR_HPP
+#define BOOST_JOIN_SIMPLE_EXECUTOR_HPP
+
+#include <iostream>
+#include <map>
+#include <boost/thread.hpp>
+#include <boost/join/join.hpp>
+
+namespace boost {
+ namespace join {
+
+ template <template <size_t> class scheduler=sched_first_match, size_t sz=32>
+ class executor_t : public actor_t<async_p<typename actor_base::callable>, scheduler, sz> {
+ public:
+ typedef scheduler<sz> sched_type;
+ typedef actor_t<async_p<typename actor_base::callable>, scheduler, sz> actor_type;
+ typedef typename actor_type::callable task;
+
+ //api: one default task queue
+ async_p<task> execute;
+ synch_p<void,void> shutdown;
+
+ executor_t(int num, const char *name = 0) : actor_type(0, 0, name) {
+ chord(run, execute, &executor_t::exec_cb);
+ chord(run, stopped, &executor_t::stop_cb);
+ chord(shutdown, started, &executor_t::shutdown_cb);
+ chord(shutdown, stopped, &executor_t::stopped_cb);
+ num_threads_ = num;
+ for(int i=0; i<num; i++)
+ threads_.create_thread(boost::bind(&executor_t::main_loop, this));
+ started(); //init state
+ }
+ ~executor_t() {
+ shutdown();
+ }
+
+ private:
+ synch_p<bool,void> run;
+ //executor states
+ async_p<void> started;
+ async_p<void> stopped;
+ //thread pool
+ boost::thread_group threads_;
+ int num_threads_;
+
+ //entry func of each thread - a loop which exists when no tasks in execute queue and shutdown
+ void main_loop(void) {
+ this->log.msg("a thread starts...");
+ while(run()) {}
+ this->log.msg("a thread exits...");
+ }
+ bool exec_cb(synch_v<bool,void> run, async_v<task> exec) {
+ this->log.msg("start one task...");
+ try {
+ (exec.arg1)();
+ }
+ catch (join_exception &je) {
+ this->log.msg(je.what());
+ }
+ catch (...) {
+ this->log.msg("UNKNOWN exceptions happen inside a executor thread, ignore.");
+ }
+ this->log.msg("finish one task...");
+ return true; //worker thread continue
+ }
+ bool stop_cb(synch_v<bool,void> run, async_v<void> stopd) {
+ return false; //worker thread exit
+ }
+ void shutdown_cb(synch_v<void,void> shdn, async_v<void> started) {
+ this->log.msg("shutdown...");
+ for(int i=0; i<num_threads_; i++) //stop all threads in pool
+ stopped();
+ //waiting for the threads to exit
+ this->log.msg("wait...");
+ threads_.join_all();
+ this->log.msg("all threads exit, done...");
+ stopped(); //add one more stopped(), in case shutdown() is called more than once
+ }
+ void stopped_cb(synch_v<void,void> shdn, async_v<void> stopd) {
+ this->log.msg("stopped...");
+ stopped();
+ }
+ };
+
+ //define a default executor_t
+ class executor : public executor_t<> {
+ public:
+ executor(int num, const char *name = 0) :
+ executor_t<>(num, name)
+ {
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/idioms/rr_executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/idioms/rr_executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,126 @@
+//
+// boost/join/pri_executor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_RR_EXECUTOR_HPP
+#define BOOST_JOIN_RR_EXECUTOR_HPP
+
+#include <iostream>
+#include <map>
+#include <boost/thread.hpp>
+#include <boost/join/join.hpp>
+
+namespace boost {
+ namespace join {
+
+ template <template <size_t> class scheduler=sched_pri_round_robin, size_t sz=32>
+ class rr_executor_t : public actor_t<async<void(typename actor_base::callable)>, scheduler, sz> {
+ public:
+ typedef scheduler<sz> sched_type;
+ typedef actor_t<async<void(typename actor_base::callable)>, scheduler, sz> actor_type;
+ typedef typename actor_type::callable task;
+ typedef std::map<size_t, boost::shared_ptr<async<void(task)> > > que_map_type;
+
+ //static api: one default task queue
+ async<void(task)> execute;
+ synch<void(void)> shutdown;
+
+ //dynamic api: dynamically added task queues
+ async<void(task)> *task_queue(size_t i=0) {
+ //since rr_executor itself uses async/synch_p<> methods, we can have task
+ //queues [1-(sz-5)]
+ if (i>(sz-5)) i = i%(sz-5);
+ if(i==0) return &execute;
+ if(this->my_scheduler() != schedule_round_robin) {
+ return &execute;
+ }
+ typename que_map_type::iterator iter;
+ if ((iter=que_map_.find(i)) != que_map_.end())
+ return iter->second.get();
+ else {
+ this->log.msg(" creating task_queue ......");
+ boost::shared_ptr<async<void(task)> > nq(new async<void(task)>());
+ chord(run, *nq, &rr_executor_t::exec_cb);
+ que_map_[i] = nq;
+ return nq.get();
+ }
+ }
+
+ rr_executor_t(int num, const char *name = 0) :
+ actor_type(0, 0, name) {
+ chord(run, execute, &rr_executor_t::exec_cb);
+ chord(run, stopped, &rr_executor_t::stop_cb, 1);
+ chord(shutdown, started, &rr_executor_t::shutdown_cb, 1);
+ chord(shutdown, stopped, &rr_executor_t::stopped_cb, 1);
+ for(int i=0; i<num; i++)
+ threads_.create_thread(boost::bind(&rr_executor_t::main_loop, this));
+ started(); //init state
+ }
+ ~rr_executor_t() {
+ shutdown();
+ }
+
+ private:
+ synch<bool(void)> run;
+ //rr_executor states
+ async<void(void)> started;
+ async<void(void)> stopped;
+ boost::thread_group threads_;
+ //dynamic api: dynamically added task queues
+ que_map_type que_map_;
+
+ void main_loop(void) {
+ this->log.msg("a thread starts...");
+ while(run()) {}
+ this->log.msg("a thread exits...");
+ }
+ bool exec_cb(synch_o<bool(void)> run, async_o<void(task)> exec) {
+ this->log.msg("start one task...");
+ try {
+ (exec.arg1)();
+ }
+ catch (join_exception &je) {
+ this->log.msg(je.what());
+ }
+ catch (...) {
+ this->log.msg("UNKNOWN exceptions happen inside a rr_executor thread, ignore.");
+ }
+ this->log.msg("finish one task...");
+ return true; //worker thread continue
+ }
+ bool stop_cb(synch_o<bool(void)> run, async_o<void(void)> stopd) {
+ stopped();
+ return false; //worker thread exit
+ }
+ void shutdown_cb(synch_o<void(void)> shdn, async_o<void(void)> started) {
+ this->log.msg("shutdown...");
+ stopped();
+ //waiting for the threads to exit
+ this->log.msg("wait...");
+ threads_.join_all();
+ this->log.msg("all threads exit, done...");
+ }
+ void stopped_cb(synch_o<void(void)> shdn, async_o<void(void)> stopd) {
+ this->log.msg("stopped...");
+ stopped();
+ }
+ };
+
+ //define a default rr_executor_t taking 32 async / synch methods or at most 27 task queues
+ class rr_executor : public rr_executor_t<> {
+ public:
+ rr_executor(int num, const char *name = 0) :
+ rr_executor_t<>(num, name)
+ {
+ }
+ };
+
+ }
+}
+
+#endif

Added: sandbox/join/boost/join/join.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/boost/join/join.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,20 @@
+//
+// boost/join/join.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_HPP
+#define BOOST_JOIN_HPP
+
+#include <boost/join/base/port.hpp>
+#include <boost/join/base/port_sig.hpp>
+#include <boost/join/base/actor.hpp>
+#include <boost/join/idioms/executor.hpp>
+#include <boost/join/idioms/rr_executor.hpp>
+
+#endif
+

Added: sandbox/join/libs/join/doc/boost_join_design.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/boost_join_design.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,294 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Join Design</title>
+ <meta content="Yigong Liu" name="author">
+ <meta content="Join Design Doc" name="description">
+</head>
+<body>
+<h2 style="text-align: center;">Join - Asynchronous Message Based
+Concurrency
+Library
+Based on C&#969; and Join Calculus</h2>
+<div style="text-align: center;">
+<h2>Yigong Liu (2007-2008)</h2>
+<h4>yigongliu_at_[hidden]<br>
+</h4>
+<hr style="width: 100%; height: 2px;">
+<ol style="text-align: left;" id="mozToc">
+<!--mozToc h3 1--> <li>Introduction</li>
+ <li>License</li>
+ <li>Installation</li>
+ <li>Acknowlegments<br>
+ </li>
+ <li><a href="./staticjoin.html">Join Programming Model 1: Static
+Class Based (C&#969;
+Style)</a></li>
+ <li><a href="./dynamicjoin.html">Join Programming Model 2: Dynamic
+Flow Based (JoCaml
+and
+CCR Style)</a></li>
+ <li>Join Internals<br>
+ </li>
+ <li>Tutorials</li>
+ <li><a href="synopsis_func.html">Synopsis of Join Classes (Function
+Based API)<br>
+ </a></li>
+ <li><a href="synopsis_port.html">Synopsis of Join Classes (Port Based
+API)<br>
+ </a></li>
+ <li><a href="source_integration.html">Source
+Code Structures and Integration with Other Libraries</a></li>
+ <li><a href="./concur_design.html">OO Concurrency Designs Based on
+"Join"</a></li>
+ <li><a href="support_shared_state.html">Support for Shared
+State Concurrency<br>
+ </a></li>
+ <li><a href="support_message_passing.html">Support for Message
+Passing Concurrency</a></li>
+ <li>Compare Join with Futures/Promises<br>
+ </li>
+ <li><a href="./compare.html">Compare Join with C&#969;,
+C#.Joins
+and CCR</a></li>
+ <li>References</li>
+</ol>
+<hr style="width: 100%; height: 2px;"></div>
+<h3><a class="mozTocH3" name="mozTocId387457"></a>Introduction</h3>
+Join is an asynchronous, message based concurrency library based
+on Join calculus. It is applicable both to multithreaded applications
+and
+to the orchestration of asynchronous, event-based applications.<br>
+<br>
+Join follows the design and implementation of C&#969;[1][2] with
+slight derivation.&nbsp; C&#969; is an experimental language based on C#
+with a new compiler to support Join abstractions. <br>
+<br>
+Join supports asynchronous concurrency design with a few simple
+abstractions:<br>
+<ol>
+ <li>
+ <h4>&nbsp;asynchronous and synchronous "methods"/"channels" </h4>
+ </li>
+</ol>
+<div style="text-align: left;">
+<div style="margin-left: 40px;">These are function objects with
+function
+signatures which can either be invoked as normal methods and functions,
+or used as channels of message flows. Their semantics are different
+from normal methods.<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>&nbsp;&nbsp; <span style="font-weight: bold;">async&lt;void
+(T1, T2, ...)&gt;</span></li>
+</ul>
+<div style="margin-left: 80px;">A asynchronous function is one-way,
+no-result, non-blocking calls; essentially passing a message. A
+asynchronous call is guaranteed to return immediately; internally there
+could be a queue to buffer the arguments or message.<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>&nbsp;&nbsp; <span style="font-weight: bold;">synch&lt;R
+(T1, T2, ...)&gt;</span></li>
+</ul>
+<div style="margin-left: 80px;">A synchronous call is similar to normal
+method call, in that the calling thread will block till result is
+returned. However a normal method call just
+involve the calling thread, a synch&lt;&gt; call could involves
+multiple threads and synchronization<br>
+</div>
+</div>
+<ol start="2">
+ <li>
+ <h4>chords or "joined" method body definition</h4>
+ </li>
+</ol>
+<div style="margin-left: 40px;">A chord defines a method body for a
+joined set of function headers; or define message processing
+logic handling multiple incoming message flows.<br>
+</div>
+&nbsp; &nbsp;<br>
+<div style="margin-left: 40px;">In C&#969;, a thread-safe buffer can be
+defined as following:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">public
+class Buffer {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;
+&nbsp;&nbsp; public async Put(string s);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;
+&nbsp;&nbsp; public string Get() &amp; Put(string s) { return s; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">} </span><br>
+</div>
+Here a chord is defined with a synchronous Get and asynchronous Put;
+the calling of Get will block if no Put is called yet, otherwise the
+string sent by Put will be returned to Get.&nbsp; &nbsp;<br>
+<br>
+In Join, the class is defined as following:<br>
+<div style="margin-left: 40px;">class buffer: public actor {<br>
+public:<br>
+<span style="font-weight: bold;">&nbsp; async&lt;void(string)&gt; put;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;string(void)&gt; get;</span><br>
+&nbsp; buffer() {<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(get, put,
+&amp;buffer::chord_body);</span><br>
+&nbsp; }<br>
+<span style="font-weight: bold;">&nbsp; string
+chord_body(synch_o&lt;string(void)&gt; get, async_o&lt;void(string)&gt;
+put) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return put.arg1;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br>
+};<br>
+</div>
+</div>
+<div style="margin-left: 40px;">&nbsp;&nbsp; <br>
+</div>
+<div style="margin-left: 40px;">such a buffer can be safely used in
+multithread applications:<br>
+<div style="margin-left: 40px;">buffer
+b;<br>
+b.put("Hello");
+b.put("World");<br>
+cout &lt;&lt;
+b.get() &lt;&lt; b.get() &lt;&lt; endl;<br>
+</div>
+</div>
+<br>
+<div style="margin-left: 40px;">Difference of Join with C&#969; in
+Chord definitions:<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>C&#969;'s chord defintion is "static", declared in class definition,
+cannot change during runtime, can be optimized by compiler.</li>
+ <li>Join's chord definition is "dynamic", created by chord()
+functions, can be changed during runtime.</li>
+</ul>
+<div style="margin-left: 40px;">Since Join's chords are dynamically
+created during runtime, it can support dynamic join programming similar
+to CCR[4].<br>
+</div>
+<ol start="3">
+ <li>
+ <h4>actor (or "joint")<br>
+ </h4>
+ </li>
+</ol>
+<div style="margin-left: 40px;">All application code which use
+async/synch methods and chords to define concurrent behaviours should
+either inherit class actor or use an actor object as a "joint" to join
+message flows together. Actor maintains the internal state
+about the
+message
+arrivals and synchronization, and firing chords when all of their
+messages are available.<br>
+<br>
+</div>
+In Join based applications, with the help of simple thread-pool based
+executors built on top of Join's primitives, we can develop concurrent
+applications without
+explicit usage of threads (thread creation and synchronization);
+concurrency are mostly defined and controlled by chords with only
+async&lt;&gt; methods in header. This make it much easier to write
+efficient and
+scalable applications for today's multicore machines.<br>
+<div style="margin-left: 40px;"></div>
+<h3><a class="mozTocH3" name="mozTocId255758"></a>License</h3>
+Join is licensed under the <a
+ href="http://www.boost.org/LICENSE_1_0.txt">Boost Software License</a>.<br>
+<h3><a class="mozTocH3" name="mozTocId689036"></a>Installation<br>
+</h3>
+Join is continuously being developed and tested in Linux (Fedora
+Core &amp; Ubuntu) and Windows (WindowsXP and Visual C++ 2005 express).
+The
+implementation is solely based on standard boost facilities
+(Boost.Bind, Boost.Function, Boost.Shared_Ptr, etc.) which will be part
+of next C++ standard. <br>
+Download: http://channel.sourceforge.net<br>
+Installation: <br>
+Join is a header only library. There is no need to build the
+library itself to use it. Please following these steps:<br>
+<div style="margin-left: 40px;"><a
+ href="http://www.boost.org/more/getting_started.html">download or
+checkout boost distribution</a><br>
+download latest boost_join_x_x.tar.gz<br>
+tar xvzf boost_join_x_x.tar.gz<br>
+add boost's directory and Join's directory to compilers' include
+path<br>
+cd to &lt;boost_join_directory&gt;/libs/join/exmaple<br>
+bjam<br>
+</div>
+<h3><a name="ack"></a>Acknowlegement<br>
+</h3>
+The original theory and systems of Join Calculus / Jocaml are developed
+by C&eacute;dric Fournet, Georges
+Gonthier, Jean-Jacques L&eacute;vy, Luc Maranget and Didier R&eacute;my
+and others at MOSCOVA INRIA.<br>
+At Microsoft Research, C&#969; is developed by Nick Benton, Luca Cardelli,
+C&eacute;dric Fournet and others. Claudio Russo developed the C# Joins
+library which is an efficient combinator library for C&#969;-style join
+patterns, implemented in C# 2.0 generics and accessible from multiple
+.Net languages.<br>
+An earlier version of the Join library described here is based on
+both C&#969; and Jocaml
+which supports multiple synchronous methods per chord (join-pattern)
+and propagation of exceptions to all synchronous callers. <br>
+The current version
+is mostly based on C&#969;, supporting only one synchronous method per chord
+for simplicity and better performance.<br>
+Thanks Dr. Claudio Russo at Microsoft Research for many insightful
+email
+discussions, clarifying many of my questions about C&#969; internals and
+semantics, and many helpful links to other Join based projects.<br>
+Thanks Dr. Luc Maranget at Moscova INRIA for many kind advices and
+links to papers, for pointing out the advantages (simplification and
+optimization) of the single-synch per chord design.<br>
+The functional signature API of async / synch methods is modeled after
+Douglas Gregor's Boost.Signals.<br>
+In the earlier version of this Join library which supports multiple
+synchronous methods and exception propagation,&nbsp; the scheme of
+catching
+exceptions in one thread, and rethrowing it in another thread is
+based on Christopher M. Kohlhoff's idea and sample code posted in boost
+email
+list discussions.<br>
+<br>
+<h3><a href="staticjoin.html">Join Programming Model 1: Static Class
+Based (C&#969;
+Style)</a></h3>
+<h3><a href="dynamicjoin.html">Join Programming Model 2: Dynamic Flow
+Based
+(JoCaml
+and
+CCR Style)</a></h3>
+<h3><a style="font-weight: bold;" href="internals.html">Join Internals</a></h3>
+<h3>Tutorials</h3>
+<h3><a href="synopsis_func.html">Synopsis of Join Classes (Function
+Based API)<br>
+</a></h3>
+<h3><a href="synopsis_port.html">Synopsis of Join Classes (Port Based
+API)<br>
+</a></h3>
+<h3><a href="source_integration.html">Source
+Code Structures and Integration with Other Libraries</a></h3>
+<h3><a href="concur_design.html">OO Concurrency Designs Based on
+Join</a></h3>
+<h3><a href="support_shared_state.html">Support for Shared
+State Concurrency</a></h3>
+<h3><a href="support_message_passing.html">Support for Message Passing
+Concurrency</a></h3>
+<h3>Compare Join with Futures/Promises</h3>
+<h3><span style="text-decoration: underline;"></span><a
+ href="compare.html">Compare Join with C&#969;,
+C#.Joins
+and CCR</a></h3>
+<h3>References</h3>
+<br>
+<div style="margin-left: 40px;"></div>
+<span style="font-weight: bold;">
+</span>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/compare.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/compare.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,175 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Compare Join with C&#969; and CCR</title>
+</head>
+<body>
+<h2>Compare C&#969; and Join</h2>
+<ol>
+ <li>
+ <p>separation of synch&lt;&gt; methods from normal object methods</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">In C&#969;, there is no separate
+synch&lt;&gt; method. When normal object methods are used inside
+chords, they become synch&lt;&gt; methods.<br>
+</div>
+<ol start="2">
+ <li>dynamic Join programming<br>
+ </li>
+</ol>
+<div style="margin-left: 40px;">Join library described here supports
+dynamic flow based programming which C&#969;
+doesnt support<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>add new chords during runtime</li>
+ <li>override chord bodies during runtime</li>
+ <li>remove chords<br>
+ </li>
+ <li>reset all chords<br>
+ </li>
+</ul>
+<ol start="3">
+ <li>
+ <p>scheduling of chords-firing</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">In C&#969;, the scheduling policy of
+chords-firing is hidden from API and cannot be changed
+(default to as-soon-as-possible?). While in Join, three
+scheduling policies
+are supported, and can be configured when actors are constructed:<br>
+<ul>
+ <li>as-soon-as-possible (default)<br>
+ </li>
+ <li>round-robin</li>
+ <li>as-much-as-possible</li>
+</ul>
+</div>
+<div style="margin-left: 40px;">Chord priority: In Join, another
+way to control the scheduling of chords is by creating chords with
+proper priority. Chords with higher priorities (smaller numbers, 0 is
+the highest priority) will be checked and fired first.<br>
+</div>
+<ol start="4">
+ <li>chord override</li>
+</ol>
+<div style="margin-left: 40px;">C&#969; and Join have different rules
+for chord overriding.<br>
+</div>
+<ol start="5">
+ <li>
+ <p>separate executor from background</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">In C&#969;, the execution of chord body with
+only asynch&lt;&gt; methods are <span style="font-weight: bold;">defined</span>
+to execute in a separate thread (either newly spawned or from thread
+pool). But how it is done is hidden from API and thus hidden from user
+control. In Join, the execution strategy is exposed as a separate
+"executor" object (with which actors need to be associated) for the
+following reasons:<br>
+<ul>
+ <li>In many applications, we want to run application tasks in
+different OS scheduling priorities based on their real time response
+requirements. So we can create executors with different OS scheduling
+priorities and associate actors with proper executors based on their
+functionalities.</li>
+ <li>queue fairness: as mentioned in Prime Sieve Tutorial, there are
+many event/message producers and consumers in many applications. Some
+producers produce much
+more events/messages than others and much faster. To avoid the fast
+producers flooding the task queue and give slow producers a fair
+chance to run, one solution is to dispatch the jobs from different
+producers to different task queues and allow thread pool round-robin
+thru all task queues. Executors can wrap this solution easily.</li>
+ <li>easy support for different execution strategies, such as
+thread-per-request, thread-pool.<br>
+ </li>
+ <li>better integration with hosting / existing applications. We could
+define executors as thin "wrappers" to dispatch asynchronous tasks into
+existing applications' execution service, such as Boost.Asio networking
+libraries main event completion queues, run by the main threads.<br>
+ </li>
+</ul>
+</div>
+<ol start="6">
+ <li> error handling</li>
+</ol>
+<div style="margin-left: 40px;">
+<p>Since C&#969; is implemented as a new
+compiler, many errors related to the definitions of async&lt;&gt; /
+synch&lt;&gt; methods and chords can be caught during compilation, such
+as hidden_chord_exception (there is conflict between chord
+definitions), missing_result_exception (in chord body, failure to reply
+to one of synch method), multi_return_exception (in chord body, reply
+to the same synch method more than once).
+</p>
+<p>However since Join is implemented as a library, these
+errors can only be reported as exceptions and caught during runtime.</p>
+</div>
+<h3>Compare Join and CCR Style Abiters<br>
+</h3>
+The author has implemented simple CCR style arbiters in another
+framework (<a href="http://channel.sourceforge.net">Channel - Name
+Space Based C++
+Framework For Asynchronous, Distributed Message Passing and Event
+Dispatching</a>). Both synchronous and asynchronous arbiters have been
+implemented. We can have the following simple comparisons between Join
+and CCR style abiters:<br>
+<ol>
+ <li>In CCR, arbiters roughly correspond to chords in Join. However
+arbiters take more roles than chords:</li>
+ <ul>
+ <li>In Join, a chord simply defines one message synchronization
+pattern, while an actor (or joint) object is the unit of configuring
+join-patterns (adding chords), the unit of deciding how to dispatch
+async tasks (choose which executor to use) and very often the unit of
+life-time control of join-patterns (when the actor is out of scope or
+deleted, all join patterns destroyed).</li>
+ <li>In CCR, arbiters are recursive (some arbiters such as Choice
+can contain other arbiters). So simple Receiver and JoinedReceiver
+arbiters define one message synchronization pattern, while "containing"
+arbiters such as Choice and Interleave can contain other simple
+arbiters and often is the unit of configuration, the unit of dispatch
+and the unit of life-time control.<br>
+ </li>
+ </ul>
+ <li>In CCR, the decision about which arbiter (or chords in Join's
+term) will fire is done through a two-phase checking. When a port
+receive messages, it will invoke its registered receivers which in turn
+will invoke its parent arbiters; finally the top arbiter will come down
+and check if all involved ports have messages available. In Join, each
+actor (or joint) contains a bitmap about the message status of all
+involved async/synch&nbsp; methods or channels. So whenever a new
+messages arrive at a channel, a simple bitmap match can check which
+chord will be ready to fire.</li>
+ <li>In CCR, ports (the message channels) are totally independent from
+join-patterns or arbiters, instead arbiters are attached to ports.
+Ports can be used independently from arbiters as plain message queues.
+However in Join, the async&lt;&gt; / synch&lt;&gt; methods or channels
+must be attached to chords before they can be used (invoked), otherwise
+exceptions will be thrown. This is more consistent with original
+join-calculus and Jocaml.<br>
+ </li>
+</ol>
+<h3>Others Join based
+libraries</h3>
+Microsoft research also introduced another C# library to support Join
+abstractions:<br>
+<ul>
+ <li>C#.Joins[3] - a faithful implementation of C&#969;
+semantics in the form of C# lib.</li>
+</ul>
+<div style="margin-left: 40px;">The earlier versions of the Join
+library described here is more a follower of Jocaml and Cw, including
+support for multiple synchronous methods in a chord and attempt to
+implement "guards". The current version is more a C++
+counterpart of C#.Joins, with some additions to support flow based CCR
+style programming.<br>
+</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/compare_future.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/compare_future.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,283 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Compare Join with Futures/Promise</title>
+</head>
+<body>
+<h2><font size="+2"><b>Futures/Promises .vs. Join, is "future" a form
+of
+message passing?</b></font></h2>
+Futures (and Promises) is a simple and elegant tool for programming a
+specific class of concurrent applications: returning result from
+asynchronous operations or different threads. In Boost community, there
+are several proposals for Futures, among which <a
+ href="http://braddock.com/%7Ebraddock/future/">Braddock Gaskill's
+proposal</a> and <a
+ href="http://www.justsoftwaresolutions.co.uk/threading/updated-implementation-of-c++-futures-2.html">Anthony
+Williams proposal </a>are the most complete and famous.<br>
+<br>
+Here are the definitions of "Futures" in Braddock's and Anthony's
+proposals:<br>
+&nbsp;&nbsp;
+1&gt; in terms of Braddock's proposal: a special variable with
+undefined value at
+creation, can be set later by another thread, any attempt to get
+future's value will be blocked if it is not set yet. "future uses a
+split interface: the <code>promise&lt;T&gt;</code> class interface is
+used for creating and setting a future value, and the <code>future&lt;T&gt;</code>
+interface is used for obtaining and using a future value."<br>
+&nbsp;&nbsp; 2&gt; in terms of Anthony's (N2561) proposal: "... a kind
+of return
+buffer that takes a value (or an exception) in one (sub-)thread and
+provides the value in another (controlling) thread. This buffer
+provides essentially two interfaces:<br>
+&nbsp;&nbsp;&nbsp; * an interface to assign a value as class promise and<br>
+&nbsp;&nbsp;&nbsp;
+* an interface to wait for, query and retrieve the value (or exception)
+from the buffer as classes unique_future and shared_future."<br>
+<br>
+From both documents, Future has 2 interfaces with diff behaviours:<br>
+&nbsp;&nbsp; * the promise&lt;T&gt; interface is "asynchronous": the
+thread which sets the future's value will not wait for future's reader;
+it just sets the value and go<br>
+&nbsp;&nbsp;
+* the future&lt;T&gt; interface is "synchronous": the thread which
+gets/reads the future's value will block wait if the future is not set
+yet<br>
+<br>
+We can define these 2 interfaces with Join as following:<br>
+&nbsp;&nbsp;&nbsp; template&lt;typename T&gt;<br>
+&nbsp;&nbsp;&nbsp; class promise_intf {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async&lt;void(T)&gt; set;<br>
+&nbsp;&nbsp;&nbsp; };<br>
+&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>
+&nbsp;&nbsp;&nbsp; class future_intf {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; synch&lt;T()&gt; get;<br>
+&nbsp;&nbsp;&nbsp; }<br>
+<br>
+A Future class and its synchronization between promise_interface and
+future_interface can be defined as following:<br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>
+&nbsp;&nbsp;&nbsp; class future :&nbsp; public promise_intf&lt;T&gt;, <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public future_intf&lt;T&gt;,<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; public actor<br>
+&nbsp;&nbsp;&nbsp; {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; future() {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chord(get, set,
+&amp;future::get_result);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; private:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; T get_result(synch_o&lt;T()&gt; g,
+async_o&lt;void(T)&gt; s) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; return s.arg1;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp; <br>
+&nbsp;&nbsp;&nbsp; };<br>
+<br>
+Manually
+crafted Future is normally implemented using one mutex and one
+condition var. The rule to get the number of (mutex, cond) used by a
+Join class is simple: each actor holds a mutex which is shared by all
+code in async/synch/actor, each synch&lt;&gt; method holds a
+conditional var and async&lt;&gt; methods hold nothing. So the above
+future class use exactly one mutex and one conditional var, the same as
+manually crafted.<br>
+<br>
+To transfer both result value and exception, we need use a result
+holder and a diff promise interface:<br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T&gt; <br>
+&nbsp;&nbsp;&nbsp; class result {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+shared_ptr&lt;T&gt; value;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+exception_ptr except;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ...<br>
+&nbsp;&nbsp;&nbsp; };<br>
+&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T&gt; <br>
+&nbsp;&nbsp;&nbsp; class promise_intf {<br>
+&nbsp;&nbsp;&nbsp; protected:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+async&lt;void(result&lt;T&gt; r)&gt; set_result;<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; void set(T t) {
+set_result(result&lt;T&gt;(t)); }<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; void fail(exception_ptr e) {
+set_result(result&lt;T&gt;(e)); }<br>
+&nbsp;&nbsp;&nbsp; };<br>
+<br>
+The future class will be modified as following:<br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>
+&nbsp;&nbsp;&nbsp; class future : public promise_intf&lt;T&gt;, <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public future_intf&lt;T&gt;,<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public actor<br>
+&nbsp;&nbsp;&nbsp; {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; future() {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chord(get,
+set_result, &amp;future::get_result);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; private:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; T get_result(synch_o&lt;T()&gt; g,
+async_o&lt;void(result&lt;T&gt;)&gt; res) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; if(res.arg1.except)<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rethrow_exception(res.arg1<wbr>.except);<br>
+&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; return res.arg1.value;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp; <br>
+&nbsp;&nbsp;&nbsp; };<br>
+<br>
+Again this class uses one mutex and one cond var.<br>
+<br>
+If
+we step back from the mental image of treating "future" as "a special
+kind of variable" for now, we can treat promise (future-setter)
+interface as message sending interface, and treat future_intf
+(future-reader) interface as message receiving interface. Then "future"
+becomes a message passing channel between the thread which produces and
+sets future's value and the thread which consumes future's value.
+Message sending and promise have the same behavior (async, send and
+go); and message recving and future_intf have the same behaviour
+(blocking wait).<br>
+<br>
+Also the above first Future definition is exactly the same as the
+simplest message queue defined in Join:<br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br>
+&nbsp;&nbsp;&nbsp; class queue {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async&lt;void(T)&gt; send;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; synch&lt;T()&gt; recv;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; queue() {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; chord(recv, send,
+&amp;queue::forward);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; private:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; T forward(synch_o&lt;T()&gt; r,
+async_o&lt;void(T)&gt; s) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return s.arg1;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; };<br>
+<br>
+The following code is from Braddock's JobQueue:<br>
+&nbsp;&nbsp;&nbsp; template &lt;class T&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; future&lt;T&gt;
+schedule(boost::function&lt;T (void)&gt; const&amp; fn) {<br>
+&nbsp;&nbsp;&nbsp; boost::mutex::scoped_lock lck(mutex_);<br>
+&nbsp;&nbsp;&nbsp; promise&lt;T&gt; prom; // create promise<br>
+&nbsp;&nbsp;&nbsp; q_.push_back(future_wrapper&lt;T&gt;<wbr>(fn,
+prom)); //queue the job<br>
+&nbsp;&nbsp;&nbsp; condition_.notify_all(); // wake worker thread(s)<br>
+&nbsp;&nbsp;&nbsp; return future&lt;T&gt;(prom); // return a future
+created from the promise<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+This
+code presents a very interesting idiom: we first create Future (inside
+promise&lt;T&gt;'s constructor) - the message channel. Then we bundle
+the work item up with prom - the sending-interface of channel together,
+and pass this bundle to worker thread. (Asynchronously the worker
+thread will do the work and write the result to the sending-interface
+of channel). Finally we return future_intf - the receiving-interface of
+channel to the receiving thread. Here we have loose-coupling: worker
+thread don't care where the request come from and the receiver don't
+care who sends the result.<br>
+Bundling a response-channel with a request message is the normal way
+how function-call or RPC call are implemented in message passing
+systems. It also shows another intrinsic property of message passing:
+using channels to define interfaces between modules and threads to
+achieve loose-coupling.<br>
+<br>
+If we can wrap around our mind and think of "future" as a form of
+message passing, we can gain much freedom from traditional concept of
+"future", for example:<br>
+&nbsp;&nbsp; * we can simply bundle a
+reference to an async method (channel) with request; and worker thread
+will return result by invoking the async method when work item is done.<br>
+&nbsp;&nbsp; * the receiving thread can wait-for/handle the result
+differently:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . we can block the thread at the
+"getting" point, same as the current "future" implementation; <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+. Or if the system is already message passing based (we have a
+main-loop to receive and process messages), and the work item request
+is probably sent from a message handling function to worker threads,
+then we can simply create a new chord which adds the response channel
+(async method) to the set of channels handled by the main-loop and go
+back to blocking wait at and serve main-loop;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . Or if the application is driven by
+thread-pool, we can create a chord to dispatch the result from response
+channel to thread-pool to handle it asynchronously.<br>
+<br>
+Treating Future as message passing also make it easier to implement
+wait_any_future and wait_all_future.<br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T1, T2, T3...&gt;<br>
+&nbsp;&nbsp;&nbsp; class wait_all_future : public actor {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async(void(T1)&gt; promise1;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async(void(T2)&gt; promise2;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async(void(T3)&gt; promise3;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ...<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+synch&lt;tuple&lt;T1,T2,T3,...&gt;()&gt; wait;<br>
+<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; wait_all_future() {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; chord(wait, promise1, promise2,
+..., &amp;wait_all_future::proc);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; private:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; tuple&lt;T1,T2,T3,...&gt;
+proc(synch_o&lt;tuple&lt;T1,T2,T3,..<wbr>.&gt;()&gt; w,
+async_o&lt;void(T1)&gt; p1, async_o&lt;void(T2)&gt; p2, ...) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return
+tuple&lt;T1,T2,..&gt;(p1.arg1, p2.arg1,...);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; };<br>
+Applications
+can instantiate one wait_all instance, bundle its async response
+channels (promise1,promise2,...) with diff requests to diff worker
+threads, and then call wait(), blocking wait untill all results come
+back. <br>
+&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp; template &lt;typename T1, T2, T3...&gt;<br>
+&nbsp;&nbsp;&nbsp; class wait_any_future : public actor {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async(void(T1)&gt; promise1;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async(void(T2)&gt; promise2;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; async(void(T3)&gt; promise3;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ...<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; synch&lt;void()&gt; wait;<br>
+<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; wait_any_future() {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; chord(wait, promise1,
+&amp;wait_any_future::proc_future1<wbr>);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; chord(wait, promise2,
+&amp;wait_any_future::proc_future2<wbr>);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ...<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; private:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; void proc_future1(synch_o&lt;void()&gt;
+w, async_o&lt;void(T1)&gt; p1) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ... process p1.arg1 ...<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; void proc_future2(synch_o&lt;void()&gt;
+w, async_o&lt;void(T2)&gt; p2) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ... process p2.arg1 ...<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ...<br>
+&nbsp;&nbsp;&nbsp; };<br>
+Applications
+can instantiate one wait_any_future instance, bundle its async response
+channels (promise1,promise2,...) with diff requests to diff worker
+threads, and then call wait() in a loop, any results coming back will
+be processed in the order it arrives. <br>
+<font size="-1"><br>
+</font>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/concur_design.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/concur_design.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,268 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>OO Concurrency Designs Based on Join</title>
+</head>
+<body>
+<h2>OO Concurrency Designs Based on Join</h2>
+<ol>
+ <li>
+ <p>Chords(or join pattern) are the core of concurrent designs based
+on Join:</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">Traditional multi-threaded systems
+focus on managing threads and their synchronization. However
+there are many issues with using threads directly as program
+structuring tools, especially on today's multi-core machines:<br>
+<ul>
+ <li>Threads are still expensive resources on most systems.</li>
+ <li>It is difficult to partition application functionalties directly
+into correct number of threads: <span style="font-style: italic;">Undersubscription
+ </span>happens when there are not enough running threads to keep
+CPUs busy. <span style="font-style: italic;">Oversubscription </span>happens
+when there are more running threads than physical CPUs, which results
+in time-sliced scheduling of threads with the overhead of context
+switching, cache cooling etc.</li>
+ <li>Scalability: because of the above factors, creating more threads
+doesnt guarantee better performance, up to certain point, more threads
+can even slow applications.</li>
+</ul>
+</div>
+<div style="margin-left: 40px;">Newer concurrency systems are switching
+to task based designs, such as Java's executor framework and Intel's
+Threading Building Blocks library:<br>
+<ul>
+ <li>a task is a much lighter weight (compare to thread) logical unit
+of work; partition application functionalities into tasks</li>
+ <li>manage threads centrally (as pools); for CPU bound applications,
+typically spawn a thread per CPU.<br>
+ </li>
+ <li>mapping / dispatching tasks to threads in pool to execute;
+amortize the cost of threads management across all tasks</li>
+ <li>as long as application work is broken into small enough tasks,
+load balancing is automatically achieved in thread pool</li>
+</ul>
+In Join based applications (C&#969; and Join), chords play the core
+role of concurrency design:<br>
+</div>
+<ol>
+ <ul>
+ <li>chords define synchronization:</li>
+ </ul>
+</ol>
+<div style="margin-left: 80px;">synchronization only apply to
+async&lt;&gt; / synch&lt;&gt; methods which participate in the chords
+of same actor.</div>
+<ol>
+ <ul>
+ <li>chords define concurrency:</li>
+ </ul>
+</ol>
+<div style="margin-left: 80px;">In
+Join based systems (Join or <span style="font-weight: normal;">C&#969;)
+there is no explicit thread creation and synchronization or even no
+explicit
+task creation and dispatching to executor thread pool. </span>Chords
+with only
+async&lt;&gt;
+methods will implicitly (automatically) create a task for its body and
+dispatch it to the thread pool of the executor
+associated with the actor. <span style="font-weight: normal;">All
+concurrency and
+asynchroncy are defined and created by async&lt;&gt; methods and chords.</span><br>
+</div>
+<span style="font-weight: normal;"></span>
+<ol start="2">
+ <li>Programming model : orchestration of asynchronous activities:</li>
+</ol>
+<ul style="margin-left: 40px;">
+ <li>new ways to maintain object state and its integrity<br>
+ </li>
+</ul>
+<div style="margin-left: 80px;">In normal concurrent applications,
+member variables are used to represent the state of objects and locks
+are used to coordinate the shared access by multiple threads. In Join
+based design, async&lt;&gt; methods are used to represent the states of
+active objects, and chords with these "state-describing" async&lt;&gt;
+methods
+can define what behaviour (synch&lt;&gt; / async&lt;&gt; methods) are
+valid in different object states. Partial specialization of
+async&lt;&gt; template class reduce the overhead of async&lt;&gt;
+methods to minimum.<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>new usage of mutual exclusion</li>
+</ul>
+<div style="margin-left: 80px;">The synchronization design of Java and
+C# is based on monitor, where a object-wide lock is used to guarantee
+that only one of "synchronized" methods can be called at anytime and
+normally the lock is hold during the execution of the method body (a
+relatively long period).<br>
+In Join based systems, when a async&lt;&gt; / synch&lt;&gt; call or
+message arrives, a object-wide lock is only used to check if any chord
+is ready to fire (a really short while). More precisely, deciding
+whether any chord is enabled by a call and, if so, removing the other
+pending calls from the queues and scheduling the body for
+execution is an <span style="font-weight: bold;">atomic</span>
+operation. Apart
+from this atomicity guarantee, however, there is no monitor-like mutual
+exclusion between chord bodies. So when a chord
+does fire and
+during execution of chord body, there is no lock hold anymore. Any
+mutual exclusion that is required must be programmed explicitly in
+terms of synchronization conditions in <span style="font-weight: bold;">chord
+headers</span>.<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>new control flow:</li>
+</ul>
+<div style="margin-left: 80px;">In shared-state model, control flow
+thru objects: objects are passive, calling
+thread invoke objects' methods and execute the method body.<br>
+In Join based model, active objects are active in that they are
+responsible for maintaining the integrity of their own state. With
+async&lt;&gt; methods defining interface, control flow stops at object
+boundary/interface and data flow thru objects. Using async&lt;&gt;
+methods to represent object states, chords (join pattern) of these
+"state-describing" async&lt;&gt; methods and other
+async&lt;&gt; / synch&lt;&gt; methods can define what behaviour
+(synch&lt;&gt; / async&lt;&gt; methods) are
+valid in different object states.<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>new interface:</li>
+</ul>
+<div style="margin-left: 80px;">In shared-state model, the interface of
+concurrent behaviour is still normal objects methods (functions);
+synchronization among concurrent object behaviours (methods) is
+<span style="font-weight: bold;">indirectly programmed</span> using
+locks. In Join based model, the interface
+of concurrent behaviour consist of
+async&lt;&gt; / synch&lt;&gt; methods, and mostly async&lt;&gt; methods
+for a loosely coupled interface; and synchronization of concurrent
+object behaviours (methods) must be <span style="font-weight: bold;">explicitly
+specified</span> as join
+pattern in chord headers. Normal object methods are mostly used for
+internal implementation or non concurrency interface.<br>
+</div>
+<ol start="3">
+ <li>Inheritance based composition</li>
+</ol>
+<ul>
+ <ul>
+ <li>extension</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">In child class of "active" classes
+(classes with actor as base), the following extensions can be performed:<br>
+<ul>
+ <li>defining new async&lt;&gt; / synch&lt;&gt; methods</li>
+ <li>defining new chords with new or exisitng
+async&lt;&gt; / synch&lt;&gt; methods from different parent classes<br>
+ </li>
+</ul>
+</div>
+<ul>
+ <ul>
+ <li>interface / implementation, "abstract" active classes</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">Separating interface and implementation
+is a basic principle of OO design. In C++, interfaces are normally
+defined as abstract classes with pure virtual methods which have only
+headers/signatures and no body defined.<br>
+<p>In Join, an async&lt;&gt; / synch&lt;&gt; method is "pure
+virtual" (has no body) before chord() is called which associates it
+with a body. So in Join based OO concurrent designs, interfaces can be
+defined as "abstract" actor based classes which only define
+async&lt;&gt; / synch&lt;&gt; methods while the definitions
+of
+chords and bodies are deferred to children / implementation classes.<br>
+</p>
+<p>There is a difference in error handling: C++ compilers will prevent
+instantiations of abstract classes, and because Join is
+implemented as a library, compilers cannot prevent instantiation of
+"abstract active" classes, the only help are runtime "not_in_chord"
+exceptions which are thrown when such&nbsp; objects are used.</p>
+Please refer to "Active
+Objects Tutorial" and "
+Asynchronous
+Call and Return Patterns Tutorial" for examples of interface and
+extension.<br>
+</div>
+<ul>
+ <ul>
+ <li>overriding:</li>
+ </ul>
+</ul>
+<div style="margin-left: 80px;">In normal C++, a method can be declared
+"virtual" and can be overriden in child classes (the same header /
+signature are re-defined with a new body). <br>
+In Join, for async / synch methods, their bodies are chords which
+may be defined with multiple method headers. So in Join, we are talking
+about chord-overriding and when a chord is overriden, all its method
+headers are "overriden" in the sense of that they all exhibit new
+behaviour.<br>
+Join supports two kinds of overriding. The chords defined can be
+overriden
+with new bodies either thru "virtual" chord body methods or by calling
+chord_override():<br>
+<ul>
+ <li>static overriding</li>
+</ul>
+<div style="margin-left: 40px;">When we define async/synch methods and
+their chords, the chord "body" method can be declared "virtual". Then
+in child classes, this chord body can be overriden just as any other
+virtual methods. When an instance of this child class is used anywhere
+thru pointers or references to parent class (by calling its async/synch
+methods), the proper child class chord body method definition will be
+invoked.<br>
+</div>
+<ul>
+ <li>dynamic overriding</li>
+</ul>
+<div style="margin-left: 40px;">This refers to the capability that
+chord definitions can be changed by overriding or replacing chord body
+methods during runtime when code runs. For this purpose,
+chord_override() is called with the set of async / synch methods (same
+as the chord to be override) and the new chord body method. The
+identified chord will replace its chord body with the new method.
+</div>
+</div>
+<div style="margin-left: 40px;">
+<div style="margin-left: 40px;">
+<p>Please refer to "Chord Overriding Tutorial" for examples of both
+static and dynamic overriding.<br>
+</p>
+</div>
+</div>
+<ol start="4">
+ <li>Aggregation/delegation based composition</li>
+</ol>
+<div style="margin-left: 40px;">Aggregation and delegation promote a
+kind of software reuse design similar to circuit integration: creating
+large/outer/containing components (actors) by composing a network of
+smaller/inner components (actors). Outer/containing components / actors
+are defined thru the following ways:<br>
+<ul>
+ <li>"composing": create and manage the life time of inner components
+(actors) and set up the interactions among them.</li>
+ <li>"aliasing": expose interfaces of inner actors (their
+async&lt;&gt; / synch&lt;&gt; methods) <span style="font-weight: bold;">selectively</span>
+and <span style="font-weight: bold;">directly</span> to
+outside at outer/containing actors by C++ references (or pointers) to
+async&lt;&gt; / synch&lt;&gt; methods of inner actors.<br>
+ </li>
+ <li>"adapting": new interfaces (async&lt;&gt; / synch&lt;&gt;
+methods) can be defined at outer/containing actors which are
+implemented by invoking inner actors' methods.</li>
+</ul>
+Please refer to "Extending by Aggregation and Delegation Tutorial" for
+a sample.<br>
+<br>
+</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/dynamicjoin.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/dynamicjoin.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,281 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Dynamic Flow Based "Join" Programming (JoCaml and CCR Style)</title>
+</head>
+<body>
+<h2>Dynamic Flow Based "Join" Programming (JoCaml and CCR Style)</h2>
+<p>In the style of JoCaml and CCR, we attempt to use Join's features
+(async&lt;&gt; / synch&lt;&gt; / chords) to model the network of
+message flows:<br>
+</p>
+<ul>
+ <li>using async&lt;&gt; / synch&lt;&gt; to model the asynchronous and
+synchronous typed message channels.</li>
+ <li>using direct instantiation of class actor (which is also aliased
+"joint") to model the juncture
+points or "joints" where message flows meet.<br>
+ </li>
+ <li>using chords defined at "joints" to define the message processing
+logic.<br>
+ </li>
+</ul>
+Here the program composition is not based on class inheritance or
+compile time mechanisms; but direct composition of async&lt;&gt; /
+synch&lt;&gt; / chords.<br>
+<br>
+Take a simple example from JoCaml's manual:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; def apple() &amp;
+pie() = print_string "apple pie" ; 0</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+or raspberry() &amp; pie() = print_string "raspberry pie" ; 0</span><br
+ style="font-weight: bold;">
+Here three asynchronous channels are defined: apple(), raspberry() and
+pie(). The above definition contains two colocated (thru operator "or")
+join-patterns (chords) which defines what processing is done when
+messages arrive at these three channels.<br>
+<br>
+Using CCR, similar code can be expressed as following:<br>
+&nbsp;&nbsp;&nbsp;&nbsp; First we create dispatcher thread pool and
+queue:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; Dispatcher dp = new
+Dispatcher(...);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; DispatcherQueue dq
+= new DispatcherQueue(dp);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ...<br>
+&nbsp;&nbsp;&nbsp; </span>Here we define three async message channels:<span
+ style="font-weight: bold;"><br style="font-weight: bold;">
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+Port&lt;String&gt; apple = new Port&lt;String&gt;();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; Port&lt;String&gt;
+raspberry = new Port&lt;String&gt;();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; Port&lt;String&gt;
+pie = new Port&lt;String&gt;();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ...<br>
+</span>&nbsp;&nbsp;&nbsp; Then arbiters are defined to synchronize
+and process messages in the above three channels. In
+CCR, join-patterns are expressed by "JoinedReceive" arbiters. The
+processing of the messages is done by 2
+delegates which are dispatched to the dispatcher thread pool:<br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+Arbiter.Activate(dq,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+&nbsp;&nbsp; Arbiter.JoinedReceive&lt;string,string&gt;(true, apple,
+pie,</span><span style="font-family: monospace; font-weight: bold;"> </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; delegate(string b, string d){ Console.WriteLine("got
+apple pie"); }),</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; Arbiter.JoinedReceive&lt;string,string&gt;(true,
+raspberry, pie,</span><span
+ style="font-family: monospace; font-weight: bold;"> </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; delegate(string b, string d){ Console.WriteLine("got
+raspberry pie"); })</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+);</span><br style="font-weight: bold;">
+&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">...</span><br>
+&nbsp;&nbsp;&nbsp; Finally we send messages on channels:<br>
+&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">apple.Post("red");
+raspberry.Post("blue"); pie.Post("large");</span><br>
+<br>
+Using the Join library described here, this example can be expressed as
+following:<br>
+<div style="margin-left: 40px;">First we create an executor with 2
+threads in
+pool:<br style="font-weight: bold;">
+<span style="font-weight: bold;">executor exec(2);&nbsp; </span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+Then define async message channels:<br style="font-weight: bold;">
+<span style="font-weight: bold;">async&lt;void(string)&gt; apple;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">async&lt;void(string)&gt; raspberry;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">async&lt;void()&gt; pie;</span><br
+ style="font-weight: bold;">
+<br>
+Then we create "joints" which defines how messages are synchronized and
+processed. Each chord defines a join-pattern and the colocation/choice
+of
+join-patterns are expressed by concatenation. Please note that the real
+message
+processing code are function objects which could be plain functions or
+object/class
+methods (apple_pie, raspberry_pie) defined somewhere else:<br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">actor joins(&amp;exec.execute);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">joins.chord(apple, pie, apple_pie)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(raspberry, pie, raspberry_pie);</span><br
+ style="font-weight: bold;">
+<br>
+Now we send a few messages on channels<br style="font-weight: bold;">
+<span style="font-weight: bold;">pie(); pie();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">raspberry("green");</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">apple("red");</span><br>
+</div>
+<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Here are the message processing
+code:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">void
+apple_pie(async_o&lt;void(string)&gt; a, async_o&lt;void()&gt; p) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; cout &lt;&lt; a.arg1 &lt;&lt; "
+apple pie" &lt;&lt; endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">void
+raspberry_pie(async_o&lt;void(string)&gt; r, async_o&lt;void()&gt; p) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; cout &lt;&lt; r.arg1 &lt;&lt; "
+raspberry pie" &lt;&lt; endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">}<br>
+<br>
+</span></div>
+The complete sample code can be found <a
+ href="../examples/func_api/jocaml1.cpp">here.</a><br>
+<br>
+The following is another CCR sample with the translation by Join
+library.<br>
+<br>
+A common design idiom in CCR ( as in other message passing based
+systems ) is to use message channels as the interface between
+components. This <a href="../examples/func_api/ccr_service.cs">CCR
+sample</a> shows the typical design of CCR based service/server.<br>
+The server exposes 3 channels to accept requests from clients, which is
+defined as <span style="font-weight: bold;">PortSet&lt;Stop,
+UpdateState, GetState&gt;</span>.<br>
+Each request will include 2 channels to allow server send responses
+back to clients. The responses are either the results of calculation or
+exceptions, which is defined as <span style="font-weight: bold;">PortSet&lt;string,
+Exception&gt;</span>.<br>
+In server's constructor, the following arbiters are defined to trigger
+processing code based on incoming requests:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Arbiter.Activate(_taskQueue,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Arbiter.Receive&lt;UpdateState&gt;(true, _mainPort, UpdateHandler),</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Arbiter.Receive&lt;GetState&gt;(true, _mainPort, GetStateHandler)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+);</span><br style="font-weight: bold;">
+<br>
+In Join's code for this sample,
+the server's interface is defined as following class with 3
+asynchronous channels:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Service {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(Stop&amp;)&gt;
+stop;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+async&lt;void(UpdateState&amp;)&gt; update;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+async&lt;void(GetState&amp;)&gt; get;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+</div>
+Each request class (Stop/UpdateState/GetState) will inherit the
+following class with 2 response channels:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+ServiceResponse {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(string)&gt;
+result;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(exception*)&gt;
+failure;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+</div>
+In server's constructor, the following chords are defined for
+processing requests from clients:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+chord(update, &amp;SimpleService::UpdateHandler);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+chord(get,
+&amp;SimpleService::GetStateHandler);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+chord(stop, &amp;SimpleService::StopHandler);<br>
+<br style="font-weight: bold;">
+</span>In main() function, we first create an executor with a pool of 2
+threads. Secondly a server instance is instantiated and its interface
+with 3 channels is returned.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+executor exec(2);&nbsp; </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; shared_ptr&lt;Service&gt;
+ssrv(SimpleService::Create(&amp;exec.execute));</span><br
+ style="font-weight: bold;">
+</div>
+Then 2 kinds of client designs are demonstrated. <br>
+In the first part, chords are setup to asynchronously process response
+messages from server:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+joins.chord(g.result, async_print_result)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(g.failure, async_print_failure)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(u.result, async_print_result)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(u.failure, async_print_failure);<br>
+<br>
+</span></div>
+In the second part, we first create a synchronous message channel:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">synch&lt;void()&gt;
+recv;</span><br>
+</div>
+Then a new set of chords are defined to synchronously process the
+response messages from server:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+joins.chord(recv, g.result, synch_print_result)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(recv, g.failure, synch_print_failure)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(recv, u.result, synch_print_result)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+.chord(recv, u.failure, synch_print_failure);</span><br>
+</div>
+Why is it synchronous? Because the main thread is blocked at
+synchronous channel<span style="font-weight: bold;"> recv() </span>waiting
+for<span style="font-weight: bold;"> </span>responses from server as
+the following code:<br>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; for(int i=0;
+i&lt;runs; i++)<br>
+&nbsp;&nbsp;&nbsp; recv();<br>
+</div>
+The synchronous recv and processing part is different from the pure
+asynchronous style of CCR.<br>
+<br>
+The complete samples are here:<br>
+<ul>
+ <li>CCR sample</li>
+ <li>Join's implementation</li>
+</ul>
+<br>
+<h2></h2>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/internals.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/internals.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,317 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Internals</title>
+</head>
+<body>
+<h2 style="text-align: left;">Join Internals</h2>
+<h3>Architecture</h3>
+Join's internal design consists of 2 parts:<br>
+<ol>
+ <li>Low Level Resource Acquisition Core <br>
+ </li>
+</ol>
+<div style="margin-left: 40px;">The core of Join (and similarly
+JoCaml/Cw/C#.Joins) is a simple resource acquisiton (and contention
+management)
+manager which supports atomic acquisition of multiple resources:<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>use a bitmap to represent
+(global) resource-availability status:</li>
+</ul>
+<div style="margin-left: 40px;">
+<ul>
+</ul>
+</div>
+<div style="margin-left: 80px;">
+<ul>
+ <li>each bit is used for
+status of one resource (available/unavailable) or message
+(arrival/missing)</li>
+ <li>bitmap -
+represent the status of multiple resources</li>
+ <li>each acquisition
+(behaviour/pattern) is also represented as a bitmap (chord)</li>
+</ul>
+<ul>
+</ul>
+</div>
+<ul style="margin-left: 40px;">
+ <li>one
+acquisition can try to acquire multiple resources (chord bitmap
+contains
+multiple "1" bits)</li>
+ <li>applications can use
+multiple concurrent / competing acquisition behaviours(patterns) whose
+bitmaps overlap or which
+compete for the same global resources</li>
+ <li>fast
+dispatching / scheduling:</li>
+</ul>
+<ul style="margin-left: 40px;">
+</ul>
+<div style="margin-left: 80px;">whenever a new resource becomes
+available, the global status
+bitmap is updated, and the new global status
+bitmap is compared with chords' bitmaps; if a chord's bitmap
+matches (covered by) the global
+status bitmap, this acquisition can be satisfied (or chord is fired):
+one item is removed from each resource marked by the bits of chord's
+bitmap, and the global status bitmap is updated to reflect new
+status of resource availability.<br>
+If more than one chord can be fired, we can apply
+various scheduling algorithms: round robin, priority based<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li><span style="font-weight: bold;">a single mutex</span> is used to
+protect all
+these bitmaps and comparing logic</li>
+ <li>multiple threads can try
+concurrent acquisitions and contention/conflicts are resolved
+atomically and thread-safely&nbsp;&nbsp;
+&nbsp;<br>
+ </li>
+</ul>
+<ol start="2">
+ <li>High Level Messaging Semantics</li>
+</ol>
+<div style="margin-left: 40px;">On top of Join's core
+resource-acquisition manager, Join
+(Jocaml/Cw/C#.Joins) adds the following high level messaging based
+semantics :<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>each bit of global resource bitmap is "set" by a
+method/channel (the passed-in arguments / messages are the resources to
+be
+consumed), so each chord/acquisition-pattern is defined
+by a set of method/channels</li>
+ <li>each chord/pattern is associated with a callback
+(chord-body) which defines how the resources/messages&nbsp; (acquired
+by
+this chord from methods/channels) are consumed</li>
+</ul>
+<div style="margin-left: 40px;">Two types of method/channel give
+different semantics :<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>asynchronous: when an asynchronous channel is invoked, if no
+acqusition bitmaps is satisfied (no chord can fire), arguments/messages
+are buffered,
+global
+resource bitmap is updated and calling thread returns without blocking</li>
+ <li>synchronous: when a synchronous channel is invoked, if no
+acqusition bitmap
+is satisfied (no chord can fire), arguments/messages are kept at stack,
+global
+resource bitmap is updated and calling thread is blocked (<span
+ style="font-weight: bold;">a condition variable </span>is
+used)</li>
+</ul>
+<div style="margin-left: 40px;">If there exist a chord (acquisition
+pattern) which
+can fire, depending on the types of acquisition pattern (chord), there
+are 2 behaviours:<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>if the chord contains a synchronous
+method/channel, the blocked thread of synch-call is waked up and the
+chord-body
+callback is executed by/inside that thread</li>
+ <li>if the chord contains all async
+methods/channels, the chord-body callback is executed in
+"another/different"
+thread (which can be
+a new thread or from thread-pool), this is how "spawning" is done in
+Join</li>
+</ul>
+<h3>Some facts result from the architecture<br>
+</h3>
+<ol start="1">
+ <li>Join's usage of low level synchronization primitives<br>
+ </li>
+</ol>
+<div style="margin-left: 40px;">The rule to get the number of
+(mutex, condition variable)
+used by a
+Join class is simple: <br>
+<ul>
+ <li>each actor holds a mutex which is used to protect all
+code in async&lt;&gt;/synch&lt;&gt;/chord/actor, </li>
+ <li>each synch&lt;&gt; method holds a
+condition variable and </li>
+ <li>async&lt;&gt; methods hold no synchronization primitive<br>
+ </li>
+</ul>
+Although Join's primitives (async&lt;&gt; / synch&lt;&gt; / chord) are
+high level, the author's experience has shown that concurrent
+applications written with Join usually use almost the same number of
+low level synchronization primitives as manually crafted ones.<br>
+<br>
+</div>
+<div style="margin-left: 40px;">For example, a manually crafted thread
+safe message queue will use a mutex and a condition variable to provide
+an asynchronous send/push interface (send and go) and a synchronous
+receive/pop interface (blocking wait if no message available).<br>
+</div>
+<div style="margin-left: 40px;">In Join, a simple thread safe message
+queue can be defined as following:<br>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename msg_type&gt;</span><br>
+<span style="font-weight: bold;">class message_queue : public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+async&lt;void(msg_type)&gt; send;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+synch&lt;msg_type()&gt; recv;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+message_queue() {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; chord(recv,
+send,
+&amp;message_queue::forward);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; private:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+msg_type
+forward(synch_o&lt;msg_type()&gt; r,
+async_o&lt;void(msg_type)&gt; s) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; return s.arg1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+Based on the above rule, since this message_queue class inherits from
+actor class and has one synch&lt;&gt; method, it will use one mutex and
+one condition variable, using exactly the same number of low level
+synchronization primitives as manually crafted. &nbsp;&nbsp;
+&nbsp;&nbsp; </div>
+<ol start="2">
+ <li>Join's expressiveness<br>
+ </li>
+ <ol>
+ </ol>
+</ol>
+<div style="margin-left: 40px;">Join provides a generic framework to
+compose asynchronous and synchronous behaviours in thread safe manner.
+Join's special internal design makes it
+very expressive in creating concurrent applications:<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>Join is expressive in that it can be used to
+create most common concurrency / synchronization constructs with
+ease,&nbsp; such as monitor, read-write lock, or actors. See tutorials
+for detailed coding</li>
+ <ul>
+ </ul>
+ <li>Join is expressive in that it is common and easy to
+write
+concurrent (thread-safe) applications using solely Join's primitives
+(async/synch/chord) without using low level threads, mutex and
+condition variables. Again see tutorials for more samples. Please refer
+to this <a href="../../../boost/join/idioms/executor.hpp">Join based
+simple
+executor</a> implmented sole thru Join's primitives.<br>
+ </li>
+</ul>
+<ol start="2">
+ <ol>
+ </ol>
+</ol>
+<ol start="3">
+ <li>Since Join's core
+directly supports atomic acquisition of multiple resources, it helps
+nicely multithreaded applications which involve multiple resources:</li>
+</ol>
+<ul style="margin-left: 40px;">
+ <li>Multithreaded applications whose threads acquiring conflicting
+sets of multiple resources (or locks)&nbsp; are prone to
+dead-locks.&nbsp; The normal way to avoid dead-lock is by enforcing a
+consistent (global) order of acquiring resources (locks), as clearly
+explained in Herb Sutter's article <a
+ href="http://www.ddj.com/hpc-high-performance-computing/204801163">"Use
+Lock Hierarchies to Avoid Deadlock"</a>.</li>
+</ul>
+<div style="margin-left: 80px;">Join provides a natural solution to
+this issue. We can use async channels/methods to represent the
+availability status of resources. The existence of messages at these
+async channels represent that resources (locks) are available to be
+consumed. Each acquisition pattern is represented as a chord which has
+one synch channel/method and multiple async channels. For example, to
+resolve the conflicting acquisitions of resources from multiple
+threads, we can define the following resource manager:<br>
+<span style="font-weight: bold;">class resource_manager : actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async&lt;void()&gt;
+resource1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async&lt;void()&gt;
+resource2;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async&lt;void()&gt;
+resource3;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async&lt;void()&gt;
+resource4;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ......</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; synch&lt;void()&gt;
+acquire1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; synch&lt;void()&gt;
+acquire2;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; synch&lt;void()&gt;
+acquire3;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ......</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; resource_manager() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(acquire1, resource1, resource3, resource4,
+&amp;resource_manager::handle_acquire1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(acquire2, resource3, resource2, resource1,
+&amp;resource_manager::handle_acquire2);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(acquire3, resource2, resource4,
+&amp;resource_manager::handle_acquire3);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ......<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; resource1();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; resource2();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; resource3();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ......<br style="font-weight: bold;">
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br>
+The above 3 chords define 3 different acquisition patterns competing
+for the same set of resources. Initially a message will be sent on each
+of these async channels to mark resource1,2,3 are available. Different
+threads will call acquire1() / acquire2() / acquire3(), block waiting
+until all of its required resources are available. When a chord is
+fired in one thread, that thread will remove a messages from each of
+async channels marked in the chord pattern, meaning it consumes these
+resources. When this thread is finished with using these resources, it
+will call these async methods to mark the resources available again.
+Please note that the order of these async channels (resources) defined
+in chords are not relevant anymore; since all required async channels
+(resources) are acquired atomically.<br>
+</div>
+<ul style="margin-left: 40px;">
+ <li>In the Futures/Promises concurrency model, one common idiom
+(wait_for_all) is using a future to wait for results from multiple
+asynchronous computations. Join can also be used to implement Futures
+and its wait_for_any and wait_for_all idioms. Please refer to the
+following section on futures/promises
+for more detailed discussions.</li>
+</ul>
+&nbsp;<br>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/references.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/references.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,27 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>References</title>
+</head>
+<body>
+<h3>References</h3>
+<ol>
+ <li><a href="http://research.microsoft.com/Comega/">Comega: "Modern
+Concurrency Abstractions for C#"</a>.</li>
+ <li><a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorials_concurrency_extensions.htm">C&#969;
+Concurrency Introduction and Tutorials</a></li>
+ <li><a href="http://research.microsoft.com/%7Ecrusso/joins/index.htm">The
+Joins Concurrency Library</a></li>
+ <li><a
+ href="http://channel9.msdn.com/wiki/default.aspx/Channel9.ConcurrencyRuntime">Coordination
+and Concurrency Runtime (CCR)</a>;&nbsp;&nbsp; <a
+ href="https://urresearch.rochester.edu/retrieve/4818/singh.pdf">"An
+Asynchronous Messaging Library for C#"</a> <br>
+ </li>
+</ol>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/source_integration.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/source_integration.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,126 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Source Code Structures and Integration with Other Libraries</title>
+</head>
+<body>
+<h2>Source Code Structures and Integration with Other Libraries</h2>
+<h3>Souce code structures</h3>
+The Join library is implemented as three layers:<br>
+<ol>
+ <li>
+ <p>Base<br>
+ </p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">The following files under
+boost/join/base define the main logic of Join and also a port based
+API&nbsp; (passing&nbsp; singular argument) which is self complete:<br>
+<ul>
+ <li>port.hpp</li>
+</ul>
+<div style="margin-left: 40px;">includes the definitions of async and
+synch ports. For async ports there are two template specializations
+defined. For synch ports there are four template specializations
+defined.<br>
+</div>
+<ul>
+ <li>actor.hpp</li>
+</ul>
+<div style="margin-left: 40px;">include the definitions of chords and
+the logic for maintaining messaging / synchronization status, chord
+matching and firing.<br>
+</div>
+</div>
+<ol start="2">
+ <li>
+ <p>Functional wrapper</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">The file boost/join/base/port_sig.hpp
+provides a functional api wrapper over the above port based API, so
+that sending messages on async / synch ports becomes calling async /
+synch methods and the packing / unpacking of arguments are automatic
+and cleaner. The code follows the design of Douglas Gregor's
+Boost.Signals library, although in Signals most of the similar codes
+are macros, and here plain C++ code is used for easy desbugging.<br>
+</div>
+<ol start="3">
+ <li>
+ <p>Idioms</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">The files under boost/join/idioms
+define high level facilities for developing Join based asynchronous
+applications. These facilities could themselves be built with the basic
+/ core Join abstractions (async / synch methods, chords and actors).
+Currently one such facility is defined -&nbsp; a thread pool based
+executor.<br>
+</div>
+<br>
+The high level idioms / facilities are optional for Join based
+applications; for example when we use Join with another application
+framework and we want to dispatch tasks to the framework's execution
+service.<br>
+<h3>Integration with Other Libraries</h3>
+<ol>
+ <li>
+ <p>The fact that async methods are functional objects enable them
+to work with existing algorithms / libraries such as STL; and introduce
+asynchrony into these algorithms / libraries when appropriate. For
+example, STL's for_each algorithm applies a functor to a range of
+elements. We could use an async method as the functor so that calling
+std::for_each(...) will in fact spawn a group of tasks in thread pool
+and each task use an element in the range as input. Since async method
+is noncopyable, it could be used in either of the following ways: </p>
+ </li>
+ <ul>
+ <li>for_each(beg_iterator, end_iterator,
+boost::bind(boost::ref(async),_1)); or</li>
+ <li>for_each(beg_iterator, end_iterator,
+boost::function&lt;void(ArgT)&gt;(boost::ref(async)));</li>
+ </ul>
+</ol>
+<div style="margin-left: 40px;">Here is the <a
+ href="../../join/examples/func_api/with_stl.cpp">full
+source code</a> of a sample of this usage.<br>
+</div>
+<ol start="2">
+ <li>
+ <p>Different execution strategies</p>
+ </li>
+</ol>
+<div style="margin-left: 40px;">Join base asynchronous
+applications could be driven by
+executors with different execution strategies (thread-pool, a thread
+per request, etc) as long as the executors
+providing a functional / functor interface to spawn a task: <span
+ style="font-weight: bold;">void
+operator()(task t)</span>. <br>
+<p>When the Join library is used together with other frameworks, we
+could
+use "adapting" wrappers to dispatch asynchronous tasks into
+"hosting" frameworks' execution service,&nbsp;</p>
+<p>For example, if Join is used with <a
+ href="http://asio.sourceforge.net/">Boost.Asio</a> networking library,
+the
+following simple executor can be used to dispatch tasks to asio's main
+threads:</p>
+&nbsp;&nbsp;&nbsp; class asio_executor {<br>
+&nbsp;&nbsp;&nbsp; public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boost::asio::io_service&amp; io_service_;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+asio_executor(boost::asio::io_service&amp; io_service):
+io_service_(io_service) {}<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; template &lt;typename task_type&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void operator()(task_type task) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+io_service_.post(task);&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; };<br>
+<br>
+</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/staticjoin.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/staticjoin.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,277 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Static Class Based "Join" Programming (Cw Style)</title>
+</head>
+<body>
+<h2>Static Class Based "Join" Programming (C&#969; Style)</h2>
+<p>In Static/Cw style programming, we attempt to integrate Join's
+features (async&lt;&gt;/synch&lt;&gt;/chords) into OO
+programming language features:<br>
+</p>
+<ul>
+ <li>use async&lt;&gt; / synch&lt;&gt; as methods/functions, and
+asynchrony and buffering are introduced.<br>
+ </li>
+ <li>treat chords as defining method body, and a chord involves a
+joined set of function headers and synchronization among threads.</li>
+ <li>all "joined" classes should inherit class actor.</li>
+ <li>use inheritance for extension<br>
+ </li>
+</ul>
+<p> </p>
+<h2>
+</h2>
+<h3>Chord Definition</h3>
+<ol>
+</ol>
+<div style="margin-left: 40px;">In a normal function/method definition,
+there is 1-1 exact correspondence between a function header/signature
+and its body. In C&#969; and Join, a body can be associated with a set
+of (synchronous and/or asynchronous) methods/functions. Such a
+definition is
+called "chord". A particular async/synch method may appear in the
+header of several chords. The body of a chord can only execute when all
+the methods in its header have been called. <br>
+<br>
+In C&#969;, a thread-safe buffer can be
+defined as following:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">public
+class Buffer {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;
+&nbsp;&nbsp; public async Put(string s);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;
+&nbsp;&nbsp; public string Get() &amp; Put(string s) { return s; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">} </span><br>
+</div>
+<br>
+In Join, it is defined as following: <br>
+</div>
+<div style="margin-left: 40px;">
+<div style="margin-left: 40px;">class buffer: public actor {<br>
+public:<br>
+<span style="font-weight: bold;">&nbsp; async&lt;void(string)&gt; put;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;string(void)&gt; get;</span><br>
+&nbsp; buffer() {<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(get, put,
+&amp;buffer::chord_body);</span><br>
+&nbsp; }<br>
+<span style="font-weight: bold;">&nbsp; string
+chord_body(synch_o&lt;string(void)&gt; get, async_o&lt;void(string)&gt;
+put) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return put.arg1;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br>
+};<br>
+</div>
+<br>
+</div>
+<div style="margin-left: 40px;">
+</div>
+<div style="margin-left: 40px;">In both C&#969; and Join, we declare
+a asynchronous method "<span style="font-weight: bold;">put</span>"
+with its signature. In Join, we also define a synchronous method "<span
+ style="font-weight: bold;">get</span>" with its signature, which is
+not necessary in C&#969; because in C&#969; normal methods will become
+"synchronous" ones when they participate in chords. <br>
+<p>Chord definitions are different in C&#969; and Join:</p>
+</div>
+<ul>
+ <ul>
+ <li><span style="font-weight: normal;">In C</span><span
+ style="font-weight: normal;">&#969;, a chord definition such as "</span><span
+ style="font-weight: bold;">public string Get() &amp; Put(string s) {
+return s; }" </span><span style="font-weight: normal;">defines the
+following information in one piece:</span></li>
+ <ul>
+ <li><span style="font-weight: normal;">async&lt;&gt; /
+synch&lt;&gt; methods involved in this chord, joined by "&amp;"
+operator, such as "<span style="font-weight: bold;">Put</span>" and "<span
+ style="font-weight: bold;">Get</span>"<br>
+ </span></li>
+ <li><span style="font-weight: normal;">all actual arguments
+passed in
+thru async / synch methods, such as "</span><span
+ style="font-weight: bold;">string s". </span><span
+ style="font-weight: normal;">The names of arguments must be unique
+across the chord.</span></li>
+ <li><span style="font-weight: normal;">the body of code to be
+executed when all methods in header have been called,&nbsp; </span><span
+ style="font-weight: bold;">{
+return s; }</span></li>
+ </ul>
+ <li>
+ <p>Since Join is implemented as a library without changing C++
+compiler, the chord is defined as 2 separate pieces<span
+ style="font-weight: normal;">:</span></p>
+ </li>
+ <ul>
+ <li><span style="font-weight: normal;">chord() method call
+identifies all involved async&lt;&gt; / synch&lt;&gt; methods and
+associate them with a chord "body" method / function, </span><span
+ style="font-weight: bold;">chord(get, put, &amp;buffer::chord_body);</span></li>
+ <li><span style="font-weight: normal;">The chord "body" method /
+function:<br>
+ </span></li>
+ <ul>
+ <li><span style="font-weight: normal;">The arguments of this
+"body" method are objects (async_o&lt;&gt; / synch_o&lt;&gt;)
+representing async / synch methods involved in this chord, each of
+which contains the arguments passed in thru corresponding async / synch
+calls. In
+class buffer, "<span style="font-weight: bold;">put</span>" method has
+only one argument, which can be accessed
+inside chord body by put.arg1. For methods with more than one
+arguments, their arguments can be accessed as method_o.arg1, </span><span
+ style="font-weight: normal;">method_o</span><span
+ style="font-weight: normal;">.arg2, </span><span
+ style="font-weight: normal;">method_o</span><span
+ style="font-weight: normal;">.arg3, etc.</span></li>
+ <li><span style="font-weight: normal;">the return type of this
+"body" method should be the same as the return type of the first method
+of this chord;&nbsp; So if the first method is an async, the return
+type of chord body should be "void"; if the first method is synch, the
+return type of chord body should be the same as the return type of this
+synch method, such as "<span style="font-weight: bold;">string</span>"
+in the above buffer sample.<br>
+ </span></li>
+ <li><span style="font-weight: normal;">The "body" method are
+code to run when all methods in chord header are called.</span></li>
+ <li><span style="font-weight: normal;">The chord body can be
+defined as object method (as shown above), class (static) method or
+normal functions.<br>
+ </span></li>
+ </ul>
+ </ul>
+ </ul>
+</ul>
+<div style="margin-left: 40px;">Please note that in both <span
+ style="font-weight: normal;">C</span><span style="font-weight: normal;">&#969;
+and Join, there are the following facts for synchronous methods:<br>
+</span>
+<ul>
+ <li><span style="font-weight: normal;">For any given chord, there are
+at most one synchronous method involved. If we do need to synchronize /
+coordinate multiple synchronous calls, we can encode "asymmetric"
+rendezvous as described in C</span>&#969; paper <a
+ href="http://research.microsoft.com/Comega/">[1]</a>.<br>
+ </li>
+ <li><span style="font-weight: normal;">If any, the synchronous method
+must be the first method in chord. <br>
+ </span></li>
+ <li><span style="font-weight: normal;">The return type of the chord
+body method</span><span style="font-weight: normal;"> must be the same
+as return type of synchronous method (such as "string" for the above
+synchronous <span style="font-weight: bold;">"get"</span>)</span><span
+ style="font-weight: normal;"></span><span style="font-weight: normal;">;
+and inside chord body</span><span style="font-weight: normal;">, for
+non-void return-type, </span><span style="font-weight: normal;"> <span
+ style="font-weight: bold;">return</span> statement must return a value
+of the same type.<br>
+ </span></li>
+ <li><span style="font-weight: normal;">If there is a synchronous
+method, the chord body runs in the thread associated with a call to
+that method, and the value is returned to that call.</span></li>
+</ul>
+</div>
+<div style="margin-left: 40px;">
+</div>
+<div style="margin-left: 40px;">
+</div>
+<h3>Runtime semantics</h3>
+<ol start="2">
+</ol>
+<p style="margin-left: 40px;">Quoted and modified from <a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorials_concurrency_extensions.htm">C&#969;
+Concurrency Extensions Tutorials [2]</a>:</p>
+<p style="margin-left: 40px;">The body of a chord can only execute once
+<i>all</i> the methods in
+its header have been called. When a async&lt;&gt; / synch&lt;&gt;
+method
+is called there may be zero, one, or more chords which are enabled
+(ready to fire):</p>
+<ul style="margin-left: 40px;">
+ <li> If no chord is enabled then the method invocation is queued up.
+If the method is asynchronous, then this simply involves adding the
+arguments (the contents of the message) to a queue. If the method is
+synchronous, then the calling thread is blocked. </li>
+ <li> If there is a single enabled chord, then the arguments of the
+calls involved in the match are de-queued, any blocked thread involved
+in the match is awakened, and the body runs. </li>
+ <li> If there are several chords which are enabled then an
+unspecified one of them is chosen to run. </li>
+ <li> Similarly, if there are multiple calls to a particular method
+queued up, we do not specify which call will be de-queued when there is
+a match.</li>
+ <li>chord body execution:<br>
+ </li>
+ <ul>
+ <li> When a chord which involves only asynchronous methods runs,
+then it does so in a thread of executors' thread pool.</li>
+ </ul>
+ <ul>
+ <li>If a chord involves a single synch&lt;&gt; method, the chord
+body will execute in the thread which calls the synch&lt;&gt; method</li>
+ </ul>
+ <li><span style="font-weight: bold;">Exception handling</span>: if an
+exception is thrown inside a chord
+"body" method,</li>
+ <ul>
+ <li>if this chord only involves asynchronous methods, its body will
+run in a thread from executor's thread pool, and the exception thrown
+inside chord body will be caught and then simply dropped (in fact if
+executor's log is
+turned on, we'll see it in log), since the semantics of async calls are
+to return immediately with no result.<br>
+ </li>
+ <li>if this chord has a synchronous method, the chord body will
+execute in the calling thread of this synchronous method and this
+caller will also get the exception.<br>
+ </li>
+ </ul>
+</ul>
+<div style="margin-left: 40px;">In <a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_buffer.htm">C&#969;
+buffer tutorial</a>,&nbsp; there is the following detailed description
+of the concurrent behaviour of buffer during runtime:<br>
+"...assume that producer and consumer threads wish to communicate via
+an instance <code class="ce">b</code> of the class <code class="ce">Buffer</code>.
+Producers make calls to <code class="ce">b.Put()</code>, which, since
+the method is asynchronous, never block. Consumers make calls to <code
+ class="ce">b.Get()</code>, which, since the method is synchronous,
+will block until or unless there is a matching call to <code class="ce">Put()</code>.
+Once <code class="ce">b</code> has received both a <code class="ce">Put()</code>
+and a <code class="ce">Get()</code>, the body runs and the argument to
+the <code class="ce">Put()</code> is returned as the result of the
+call to <code class="ce">Get()</code>. Multiple calls to <code
+ class="ce">Get()</code> may be pending before a <code class="ce">Put()</code>
+is received to reawaken one of them, and multiple calls to <code
+ class="ce">Put()</code> may be made before their arguments are
+consumed by subsequent <code class="ce">Get()</code>s. Note that:
+<ul>
+ <li>The body of the chord runs in the (reawakened) thread
+corresponding to the matched call to <code class="ce">Get()</code>.
+Hence no new threads are spawned in this example.</li>
+ <li>The
+code which is generated by the class definition above is completely
+thread safe... for example, the argument to a particular call of <code
+ class="ce">Put()</code> cannot be delivered to two distinct calls to <code
+ class="ce">Get()</code>.
+Furthermore (though it makes little difference in this small example),
+the locking is fine-grained and brief - async&lt;&gt; / synch&lt;&gt;
+methods do not lock
+the whole object and are not executed with ``monitor semantics''.</li>
+ <li>The
+reader may wonder how we know which of the methods involved in a chord
+gets the returned value. The answer is that it is always the
+synchronous one..."<br>
+ </li>
+</ul>
+</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/support_message_passing.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/support_message_passing.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,367 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Support For Message Passing Concurrency</title>
+</head>
+<body>
+<h2>Support for Message Passing Concurrency<br>
+</h2>
+Join's async methods and chords provide strong support for
+asynchronous message based concurrency designs. <br>
+<h3>Compare to Erlang<br>
+</h3>
+Erlang's support for concurrency is based on a few primitives:<br>
+<ul>
+ <li>spawn - create very light weight process</li>
+ <li>Pid ! Message - send message to a process</li>
+ <li>receive ... end</li>
+</ul>
+A typical Erlang server contains a message processing main loop such as
+the following:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">loop()
+-&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; receive</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+{rectangle, Width, Ht} -&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; io:format("Area of rectangle is ~p~n", [Width * Ht]),</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; loop();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+{circle, R} -&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; io:format("Area of circle is ~p~n", [3.14159 * R * R]),</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; loop();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Other
+-&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; io:format("I dont know what the area of a ~p is ~n",
+[Other])</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; loop()</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; end.</span><br
+ style="font-weight: bold;">
+</div>
+<br>
+The same (synchronous) server code can be expressed in Join as
+following:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Server : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">private:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async&lt;void()&gt;
+activate;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; synch&lt;void()&gt;
+process;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; //the server will
+serve 2 messages:</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+async&lt;void(float, float)&gt; rectangle;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+async&lt;void(float)&gt; circle;</span><br style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; Server(executor
+*e): actor(e) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(activate, &amp;Server::main_loop);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(process, rectangle, &amp;Server::calc_rect_area);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(process, circle, &amp;Server::calc_circle_area);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+//start server thread</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+activate();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">private:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; //server main loop</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+main_loop(async_o&lt;void()&gt; act) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //all the next 2 message processing
+methods will run in this thread<br style="font-weight: bold;">
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+for(;;) </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; process();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+calc_rect_area(synch_o&lt;void()&gt; p, async&lt;void(float, float)&gt;
+rect) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; cout
+&lt;&lt; "Area of rectangle is " &lt;&lt; rect.arg1 * rect.arg2
+&lt;&lt; endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+calc_circle_area(synch_o&lt;void()&gt; p, async&lt;void(float)&gt;
+circ) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; cout
+&lt;&lt; "Area of circle is " &lt;&lt; 3.14159 * circ.arg1 * circ.arg1
+&lt;&lt; endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+</div>
+&nbsp;&nbsp;&nbsp; <br>
+We can do a comparison of the above 2 code snippets:<br>
+<ul>
+ <li>Both above codes implement synchronous servers; server will own
+its own thread/process and block waiting for incoming requests. Erlang'
+server is running in Erlang's light weight process while Join's server
+is running in a thread from executor's thread pool. Erlang's process is
+much cheaper than normal OS thread, so we can have thousands of Erlang
+servers running without bringing the machine down. To achieve similar
+benefit with Join and OS thread, we have to implement an asynchronous
+server as following code.</li>
+ <li>Erlang check messages types by pattern matching during runtime,
+if Erlang server
+receives a unexpected message, "Other -&gt; ..." section is invoked. In
+the above Join based server, the message types are defined at interface
+and
+checked by compiler. Because sending a message to Join based server is
+to invoke its async methods, so compiler can prevent invoking
+unsupported methods.</li>
+</ul>
+A purely asynchronous Join based server can be expressed as following:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Server : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; //the server will
+serve 2 messages:</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+async&lt;void(float, float)&gt; rectangle;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+async&lt;void(float)&gt; circle;</span><br style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; Server(executor
+*e): actor(e) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp; chord(rectangle, &amp;Server::calc_rect_area);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+chord(circle, &amp;Server::calc_circle_area);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+}</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">private:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+void calc_rect_area(async&lt;void(float, float)&gt; rect) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; cout
+&lt;&lt; "Area of rectangle is " &lt;&lt; rect.arg1 * rect.arg2
+&lt;&lt; endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+calc_circle_area(async&lt;void(float)&gt; circ) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; cout
+&lt;&lt; "Area of circle is " &lt;&lt; 3.14159 * circ.arg1 * circ.arg1
+&lt;&lt; endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+</div>
+All these asynchronous servers do not have their own threads, instead
+they share the threads from executor's thread pool, ie. their message
+processing methods will be dispatched to thread pool to be executed. So
+if the executor's thread pool contain enough threads, we should be able
+to use thousands of these async active objects.<br>
+<br>
+Of course we can develop traditional style message passing system in
+Join as following.<br>
+<br>
+Normally we'll have a generic
+message container:<br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; class message {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+int type;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+char *data;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; class server :
+public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+synch&lt;shared_ptr&lt;message&gt;()&gt; receive;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+async&lt;void(shared_ptr&lt;message&gt;)&gt; send;</span><br
+ style="font-weight: bold;">
+<div><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; server() {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chord(receive,
+send, &amp;server::forward);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new
+thread(bind(&amp;server::main_loop, this);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; private:<br style="font-weight: bold;">
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; void main_loop() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;for(;;)
+{</span><br style="font-weight: bold;">
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; shared_ptr&lt;message&gt;
+msg = receive();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;switch(msg-&gt;type) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; case type1:
+... handle msg type 1; break;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; case type2:
+... handle msg type 2; break;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+.......<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; default:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; cout &lt;&lt;
+"unknown msgs";<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }<br>
+</div>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; &nbsp;&nbsp; }</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+void forward(synch_o&lt;shared_ptr&lt;message&gt;()&gt; r,
+async_o&lt;void(shared_ptr</span><wbr style="font-weight: bold;"><span
+ style="font-weight: bold;">&lt;message&gt;)&gt;
+s) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+&nbsp; return s.arg1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; };</span><br>
+Here
+the message type resolution happens during runtime. Since C/C++ do not
+have pattern matching so we have to switch based on msg-&gt;type. The
+"default" case is similar to Erlang's "Other..." case and the 1st
+messages
+of message queue is always returned no matter what type it is, which is
+similar to
+Erlang's AnyMessage.<br>
+</div>
+<h3>Reactive Finite State Machines<br>
+</h3>
+One common asynchronous message based design is based on reactive
+finite state machine (FSM). Each entitiy in this design is an active
+object, communicating with each other thru asynchronous messages, and
+the behaviour of these entities are controlled by their state machines,
+normally encoded as a state transition table. One common encoding is a
+two dimensional table, some cells of it are valid and containing the
+following triplet:<br>
+<p>&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">&lt;state,
+message(event), action / next state&gt;<br>
+</span></p>
+<ul>
+ <li>state: the current state of entity</li>
+ <li>message (event): the message arrived or event happened when
+entity is in the above state</li>
+ <li>next state: the new state the entity will transition to when the
+event happened</li>
+ <li>action: the processing the entity will carry out during transition<br>
+ </li>
+</ul>
+With Join's async methods and chords, we can directly define the above
+state transition table in a declarative manner. The following rules are
+applied:<br>
+<ul>
+ <li>using async methods to represent states</li>
+ <li>using async methods to represent messages / events</li>
+ <li>using chords to define actions and valid transitions </li>
+</ul>
+For example, the state machine of a light can be encoded as the
+following Join based class:<br>
+<div style="margin-left: 40px; font-weight: bold;">class light : public
+actor {<br>
+public:<br>
+&nbsp;&nbsp;&nbsp; //using async methods to represent states<br>
+&nbsp;&nbsp;&nbsp; async&lt;void()&gt; on;<br>
+&nbsp;&nbsp;&nbsp; async&lt;void()&gt; off;<br>
+&nbsp;&nbsp;&nbsp; //using async methods to represent messages / events<br>
+&nbsp;&nbsp;&nbsp; async&lt;void()&gt; switch;<br>
+&nbsp;&nbsp;&nbsp; light(executor *e) : actor(e) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //in constructor, using chords to
+define valid actions and transitions<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; chord(on, switch, &amp;light::dark);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; chord(off, switch, &amp;light::bright);<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //initialize the state of light to
+"off"&nbsp; by
+calling async method<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; off();<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; void dark(async_o&lt;void()&gt; on,
+async&lt;void()&gt; switch) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //do some transition actions here<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //then transition to the next state
+"off" by
+calling async method<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; off();<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; void bright(async_o&lt;void()&gt; off,
+async&lt;void()&gt; switch) {<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //do some transition actions here<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //then transition to the next state
+"on" by
+calling async method<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; on();<br>
+&nbsp;&nbsp;&nbsp; }<br>
+};<br>
+</div>
+<br>
+Join really shines when more complicated state machines are handled.
+For example, the state transition is triggered by combination of events:<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&lt;state,
+event1 &amp; event2 &amp; event3, action / next state&gt;</span></div>
+<br>
+Apart from the advantage of encoding the state machine declaratively,
+the above state machine is multi-thread safe and the transition actions
+executes asynchronously (and could concurrently if the logic allows) in
+executor's thread
+pool. If the executor is an adaptor to other framework's execution
+service (such as Boost.Asio's event completion queue), the transition
+actions will be executed there. Many entities and their FSMs can share
+the same thread pool.<br>
+By defining a synchronous <span style="font-weight: bold;">process() </span>method,
+and adding it to the above chords, we can easily define an "active"
+state machine with its own thread (or so called reactive iterative
+server), similar to the above synchronous Join server.<br>
+<font size="-1"><br>
+</font>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/support_shared_state.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/support_shared_state.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,114 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Support For Shared State Concurrency</title>
+</head>
+<body>
+<h2>Support for Shared State Concurrency<br>
+</h2>
+<font>Join's support for shared state concurrency is different from
+Java / C# monitor based model.<br>
+<br>
+Java/C#'s model is based
+on "monitor", the whole object state (all application data too) is the
+critical region protected by an object-wide lock, if a synchronized
+method is
+called, the lock is held during the execution of method body till the
+end of body or released explicitly in middle when using synchronized
+statement, the
+callings of all other synchronized methods will be blocked till the
+first calling returns.
+<br>
+</font>
+<p><font>In Join, the object-wide lock is only used to protect the
+synchronization state of the object, embedded in actor /
+async&lt;&gt; / synch&lt;&gt; members. When a async / synch method is
+invoked, the lock is only held for checking if
+any chords are ready to fire (all its messages have arrived) and </font><font>buffering
+messages and </font><font>then
+it is released. When chord bodies execute (either in calling thread of
+a synch&lt;&gt; method or a task in thread pool), this lock is not held
+anymore.
+</font></p>
+<font>We can explore the implications of this difference in the
+following
+directions:<br>
+</font>
+<ol>
+ <li><font>Join's object-wide lock is only held during checking
+internal synchronization status which is a very short period. Java's
+object-wide lock is held for executing application code which could be
+relatively long period if I/O is involved or other objects' methods are
+invoked.<br>
+ </font></li>
+</ol>
+<font></font>
+<ol start="2">
+ <li>
+ <p><font>Join's object-wide lock is not used to synchronize access
+to
+application code, instead this synchronization should be specified
+explicitly in chords or join-patterns. For example, if two methods may
+access / modify an internal data (data_A) concurrently, we could define
+an async method data_A_lock() to synchronize the access: </font></p>
+ </li>
+</ol>
+<div style="margin-left: 40px;"><font>&nbsp;&nbsp; chord(method1,
+data_A_lock, chord_body1);</font><br>
+<font>&nbsp;&nbsp; chord(method2, data_A_lock, chord_body2);</font><br>
+<font>By
+calling data_A_lock(), data_A is unlocked. Then the calling of
+method1/chord_body1 and method2/chord_body2 are synchronized regarding
+to data_A.
+</font><br>
+</div>
+<font></font>
+<ol start="3">
+ <li><font>Join's synchronization is more fine-grained. In Java/C#
+model, calling a synchronized method will lock the whole object. For
+some object, its synchronized methods could be divided into diff groups
+because they depends on diff resources or states. Theoretically, one
+method from each of these diff groups should be able to run
+concurrently without interfering. In Java we cannot do it since the
+whole object is locked. To do it we need to split the original object
+into smaller objects, one for each group, to use different locks. This
+issue can be easily resolved in Join (with one lock) by defining a
+separate async&lt;&gt; method for each group and diff methods can join
+with a proper async&lt;&gt; method to acquire the exclusive access to
+the resource it needs. </font></li>
+</ol>
+<font></font>
+<ol start="4">
+ <li><font>Join's model can be thought as a generic contention manager
+or synchronization framework which can be used to code any customized
+contention
+management / synchronization requirements (as shown in many tutorials)
+and avoid some
+important cases of
+dead-locks. For example, in some applications, actions need exclusive
+access to multiple resources.
+Traditionally we need first lock all these resources one by one and
+then perform the action. This is problematic design, since some other
+actions may need exclusive access to (some of) these resources too. We
+have to make sure all these resources / locks are acquired in the same
+order otherwise dead-lock will occur. </font></li>
+</ol>
+<div style="margin-left: 40px;"><font>In Join, we can resolve this
+issue by defining an
+async method (lock1(), lock2(),...)&nbsp; for each resource and
+defining chord to join the action method with the set of async methods
+represents the set of resources it requires:
+</font><br>
+<font>&nbsp;&nbsp; chord(action1, lock1, lock2, lock3,..., chord_body);</font><br>
+<font>Please note that when message arrive, Join will check the
+availablity
+of all resources (lock1, lock2, ...) in one "atomic" transaction, so
+the order of how lock1(), lock2(),... are called are not relevant or
+important anymore.</font><br>
+</div>
+<font size="-1"><br>
+</font>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/synopsis_func.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/synopsis_func.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,658 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Synopsis of Join Classes</title>
+</head>
+<body>
+<h2>Synopsis of Join Classes (Function Based API)<br>
+</h2>
+In this API, the asynchronous and synchronous channels are modeled as
+functions/methods, which can take multiple arguments indentified by
+arg1,arg2, arg3,.... Function based API is built on top of <a
+ href="./synopsis_port.html">port based
+API</a>.<br>
+<ol>
+ <li>classes</li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">namespace
+boost {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; namespace join {<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+template &lt;void (T1, T2,
+...)&gt;&nbsp; class async;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;R (T1, T2,
+...)&gt;&nbsp; class synch;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;void (T1, T2,
+...)&gt;&nbsp; class async_o;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;R (T1, T2,
+...)&gt;&nbsp; class synch_o;</span><br style="font-weight: bold;">
+<br>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+template &lt;typename executor, size_t max_size&gt;
+class actor;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+class executor;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br>
+</div>
+<ol start="2">
+ <li>Asynchronous methods<br>
+ <span style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename
+Signature&gt;&nbsp;&nbsp; //Signature : void
+(T1, T2, ...)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class async {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef
+T1 arg1_type;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef
+T2 arg2_type;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef
+async_o&lt;Signature&gt;
+var_type;</span><br style="font-weight: bold;">
+&nbsp;
+<span style="font-weight: bold;"></span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+async(size_t sz=0) : base_type(sz) {}</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+operator()(T1 a1, T2 a2, ...)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+<br>
+Asynchronous method objects are not copyable or assignable, since they
+contain state for on-going messaging. We can only pass around pointers
+and references to them.<br>
+<br>
+<span style="font-weight: bold;">async(size_t sz=0):<br>
+Effect: </span>initialize a asynchronous method with underlying
+argument / message queue.
+The queue size <span style="font-weight: bold;">sz</span> is specified
+for flow control; the default value 0 means
+unlimited queue size. Internally there are 2 implementations for this
+class. If the signature is async&lt;void(void)&gt;, there is no
+message/arguments to be passed, and template specialization will choose
+a proper implementation without a queue (and its overhead) while
+maintaining the
+same semantics.<span style="font-weight: bold;"><br>
+Throw:<br>
+<br>
+</span><span style="font-weight: bold;">void operator()(T1 a1, T2 a2,
+...): </span><br>
+<span style="font-weight: bold;">Effect:</span> the functional api to
+send asynchronous messages; calling threads will return immediately.
+Since async calls will return immediately, and arguments may be
+buffered in queues, the arguments cannot be references or pointers to
+variables on calling stacks which will be unwound when async calls
+return.<br>
+<span style="font-weight: bold;">Throws</span>: not_in_chord_exception,
+queue_overflow_exception, no_executor_exception<br>
+</div>
+<ol start="3">
+ <li>Synchronous methods<span style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename
+Signature&gt;&nbsp;&nbsp; //Signature : R
+(T1, T2, ...)<br>
+class synch {<br>
+public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef R result_type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef T1 arg1_type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef T2 arg2_type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef synch_o&lt;Signature&gt;
+var_type;<br>
+&nbsp;
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synch(size_t sz=0) : base_type(sz) {}<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; R operator()(T1 a1, T2 a2, ...);<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+R operator()(T1 a1, T2 a2, ..., boost::xtime &amp;timeout);<br>
+</span><span style="font-weight: bold;">&nbsp;};<br>
+<br>
+</span>Synchronous method objects are not copyable or assignable, since
+they contain state for on-going messaging. We can only pass around
+pointers and references to them.<br>
+<br>
+<span style="font-weight: bold;">synch(size_t sz=0):<br>
+Effect: </span>initialize a synchronous method with underlying thread
+waiting queue.
+The queue size <span style="font-weight: bold;">sz</span> is specified
+for flow control; the default value 0 means
+unlimited queue size. Internally there are four implementations and
+template specialization help choose the most efficient one.<span
+ style="font-weight: bold;"><br>
+Throw:<br>
+<br>
+</span><span style="font-weight: bold;">R operator()(T1 a1, T2 a2, ...):</span><br>
+<span style="font-weight: bold;">Effect: </span>the functional
+interface to send a synchronous message;
+calling thread will block here till a reply is available. Since the
+call will block till a result is returned, the arguments can be
+anything just as normal function calls, including pointers or
+references to variables on stack.<br>
+<span style="font-weight: bold;">Throws: </span>not_in_chord_exception,
+queue_overflow_exception, missing_result_exception,&nbsp;
+application_specific_exceptions_raised_inside_chord_body<br>
+<br>
+<span style="font-weight: bold;">R operator()(</span><span
+ style="font-weight: bold;">T1 a1, T2 a2, ...</span><span
+ style="font-weight: bold;">, boost::xtime
+&amp;timeout):</span><br>
+<span style="font-weight: bold;">Effect: </span>this is a variant of
+the above interface with a timeout. The call will return either the
+result is available or return with a "synch_time_out_exception" when
+the timeout is reached.<br>
+<span style="font-weight: bold;">Throws:</span><span
+ style="font-weight: bold;"></span> not_in_chord_exception,
+queue_overflow_exception, synch_time_out_exception,&nbsp;
+application_specific_exceptions_raised_inside_chord_body<br>
+</div>
+<ol start="4">
+ <li>wrapper objects for asynchronous
+methods (used as arguments of chord body)<span
+ style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template&lt;typename
+Signature&gt;&nbsp;&nbsp; //Signature : void
+(T1, T2, ...)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class async_o {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T1 arg1;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T2 arg2;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+.......</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp; void
+operator()(T1 a1, T2 a2, ...)<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; //for async methods with single
+argument, the following are defined:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span style="font-weight: bold;">operator
+T();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span style="font-weight: bold;">T
+&amp;arg(void)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+async_o is a wrapper of asynchronous methods, used as the arguments of
+chord body functions. Its main purpose is to represent the
+arguments/message passed in by asynchronous methods, specifically the
+arguments or message at the top of queue.<br>
+<br>
+<span style="font-weight: bold;">arg1, arg2 ,...: </span>arguments of
+the associated asynchronous method<span style="font-weight: bold;"><br>
+<br>
+</span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">void operator()(</span><span
+ style="font-weight: bold;">T1 a1, T2 a2, ...</span><span
+ style="font-weight: bold;">):</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>invoke the associated
+asynchronous method.<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws: </span>not_in_chord_exception,
+queue_overflow_exception, no_executor_exception<br>
+<br>
+The following two convenience methods are defined for async methods
+with single argument:<br>
+<span style="font-weight: bold;">operator T(): </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>a conversion function,
+so that async_o can be used as an argument of type T<br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">T &amp;arg(void):</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>retrieve the
+argument/message explicitly. This is necessary in situation where the
+implicit conversion cannot be applied<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br>
+<span style="font-weight: bold;"></span></div>
+<ol start="5">
+ <li>wrapper objects for synchronous
+methods (used as arguments of
+chord body)<span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">template&lt;typename
+Signature&gt;&nbsp;&nbsp;&nbsp; //Signature : R
+(T1, T2, ...)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class synch_o {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T1 arg1;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T2 arg2;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+.......<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp; R
+operator()(T1 a1, T2 a2, ...)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp; //for synch methods with single argument</span><span
+ style="font-weight: bold;">, the following are defined</span><span
+ style="font-weight: bold;">:<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span style="font-weight: bold;">operator
+T();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span style="font-weight: bold;">T
+&amp;arg(void)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">};</span><br>
+synch_o is a wrapper of synchronous methods, used as the arguments of
+chord body functions. It serves two purposes:<br>
+<ul>
+ <li>representing
+the
+argument/message passed in by synchronous methods, specifically the
+arguments or message at the top of queue; <br>
+ </li>
+ <li>allowing replying to
+the synchronous methods.</li>
+</ul>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">arg1,
+arg2 ,...: </span>arguments of the associated synchronous method<br>
+<br>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">R
+operator()(T1 a1, T2 a2, ...)</span><span style="font-weight: bold;">:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>invoke the associated
+synchronous method.<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws: </span>not_in_chord_exception,
+queue_overflow_exception, missing_result_exception,&nbsp;
+application_specific_exceptions_raised_inside_chord_body<br>
+<span style="font-weight: bold;"><br>
+</span>The following two convenience methods are defined for synch
+methods
+with single argument:<br>
+<span style="font-weight: bold;">operator T(): </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>a conversion function,
+so that synch_o can be used as an argument of type T<br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">T &amp;arg(void):</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>retrieve the
+argument/message explicitly. This is necessary in situation where the
+implicit conversion cannot be applied<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br>
+</div>
+<ol start="6">
+ <li>actor</li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;</span><span style="font-weight: bold;">typename executor =</span><span
+ style="font-weight: bold;"> async&lt;task&gt;</span><span
+ style="font-weight: bold;">, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+template &lt;size_t&gt; scheduler = sched_first_match,<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; size_t
+max_size = 32&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+actor(executor *execute = NULL, const char
+*name = NULL);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+template
+&lt;typename PortT1, typename PortT2,
+......, typename CallT&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void chord(PortT1
+&amp;p1, PortT2 &amp;p2, ......, CallT c, int priority=0)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+template
+&lt;typename PortT1, typename PortT2, </span><span
+ style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">typename CallT&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+chord_override(PortT1 &amp;p1, PortT2 &amp;p2, </span><span
+ style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">CallT c</span><span
+ style="font-weight: bold;">, int priority=0</span><span
+ style="font-weight: bold;">)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+template
+&lt;typename PortT1, typename PortT2,
+......&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+chord_remove(PortT1
+&amp;p1, PortT2 &amp;p2, ......)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+......</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+Actor is the parent class of all classes which use
+async&lt;&gt; / synch&lt;&gt; methods and chords to define concurrent
+activities. Actor maintains the status of message arrival and
+synchronization. Actors are not copyable or assignable. We can only
+pass around pointers and references to them.<br>
+<br>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">typename
+executor:</span> <br>
+&nbsp;&nbsp;&nbsp; the type of execution service used to drive Join
+based asynchronous applications. It could be the async "execute" method
+of the following thread pool based executor, or it could be a adaptor
+to existing applications execution service, as long as it provides a
+functional / functor interface to spawn a task:<br>
+&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">void
+operator()(task t);<br>
+<br>
+</span><span style="font-weight: bold;">max_size:</span> <br>
+&nbsp;&nbsp;&nbsp; defines the capacity
+of actor, ie. how many async&lt;&gt; / synch&lt;&gt; methods can be
+defined in this actor. When max_size &lt;= 32, integer bitmask is used
+to maintain status; while for "larger" actor, std::bitset&lt;&gt; is
+used for status.<br>
+<br>
+<span style="font-weight: bold;">scheduling_policy: </span><br>
+&nbsp;&nbsp;&nbsp; actor
+supports three kinds of scheduling policies that decide which chord
+will fire when multiple chords become ready at the same time:<br>
+<ul>
+ <li><span style="font-weight: bold;">sched_first_match</span>: fire
+the first chord which is ready to
+fire</li>
+ <li><span style="font-weight: bold;">sched_longest_match</span>: when
+multiple chords are ready to fire,
+fire the one defined with most async&lt;&gt; / synch&lt;&gt; methods.</li>
+ <li><span style="font-weight: bold;">sched_round_robin</span>:
+internally the last chord fired is
+remembered and chords are fired in round-robin style.</li>
+</ul>
+<span style="font-weight: bold;">actor(executor *execute =
+NULL, const char *name = NULL):<br>
+</span>&nbsp;&nbsp;&nbsp; an actor is constructed with the following
+two settings:<br>
+<ul>
+ <li>executor *execute: the asynchronous method to spawn a new task
+(from a function object <span style="font-weight: bold;">function&lt;void()&gt;</span>).
+It could be an adaptor to spawn tasks into existing applications main
+threads (and it must be non-blocking and returns immediately), or the
+execute method of the following executor (thread pool),
+ie.
+the task waiting queues. In Join based applications, there is no
+explicit usage of threads (creation / synchronization), concurrency are
+generated by
+chords with only async&lt;&gt; methods whose body will run as a task in
+executor thread pool.<br>
+ </li>
+ <li>const char *name: the name of actor; it is used as a flag to turn
+on/off debug messages, when it is set to a non-NULL value, debugging
+message will be printed out.<br>
+ </li>
+</ul>
+<span style="font-weight: bold;">template
+&lt;typename PortT1, typename PortT2,
+......, typename CallT&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">void chord(PortT1 &amp;p1, PortT2
+&amp;p2, ......, CallT c, int priority=0)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">Effect:
+</span>overloaded chord()
+functions to create chords with different number of
+async&lt;&gt; / synch&lt;&gt; methods. By default actor has just eight
+overloaded chord() functions to create chords for one to eight
+async&lt;&gt; / synch&lt;&gt; methods,&nbsp; because any of these
+async&lt;&gt; methods can be a array&lt;async&lt;&gt;&gt;, so in fact
+chords can be created for unlimited number of
+async&lt;&gt; methods, while each chord can have at most one
+synchronous method:<br>
+<ul>
+ <li>PortT &amp;p, &amp;p1, ... &amp;pn: async&lt;&gt; / synch&lt;&gt;
+methods which are in the header of chord body; only one of them can be
+synchronous and if we do have one, it must the first method.<br>
+ </li>
+ <li>CallT c: a function, class-method, or object-method which can be
+used as the chord body</li>
+ <li>int priority: the scheduling priority of this chord; the
+default value 0 has the highest priority, the greater the number, the
+lower the priority. During scheduling, the chords with higher priority
+will be scanned and scheduled first.</li>
+</ul>
+<span style="font-weight: bold;">Throws: </span>hidden_chord_exception,
+too_many_ports_exception<br>
+<br>
+<span style="font-weight: bold;">template &lt;typename PortT1, typename
+PortT2, </span><span style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">typename CallT&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">void chord_override(PortT1 &amp;p1,
+PortT2 &amp;p2, </span><span style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">CallT c</span><span
+ style="font-weight: bold;">, int priority=0</span><span
+ style="font-weight: bold;">)</span><span style="font-weight: bold;"></span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect:&nbsp; </span>allow overriding
+an existing chord (the chord body is replaced with the new one).
+It is mostly used in child class to override a chord defined in parent
+class. The overridden chord is identified by the set of async&lt;&gt; /
+synch&lt;&gt; methods in its header. It uses the same arguments as
+normal chord() functions. <br>
+<span style="font-weight: bold;">Throws:&nbsp; </span>chord_override_exception
+(chord not found)<br>
+<br>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename PortT1, typename PortT2,
+......&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">void chord_remove(PortT1
+&amp;p1, PortT2 &amp;p2, ......)</span><br style="font-weight: bold;">
+</div>
+<div style="margin-left: 40px;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">Effect:&nbsp; </span>remove the chord
+identified by the set of async / synch methods. <br>
+<span style="font-weight: bold;">Throws:&nbsp; </span>chord_remove_exception
+(chord not found)<br>
+<span style="font-weight: bold;"></span></div>
+<ol start="7">
+ <li>executor</li>
+</ol>
+<div style="margin-left: 40px; font-weight: bold;">template
+&lt;template &lt;size_t&gt; class scheduler=sched_first_match, size_t
+sz=32&gt;<br>
+class executor :
+public actor {<br>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+executor(int
+num_threads, const char *name = NULL);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async_p&lt;task&gt;
+execute;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+synch_p&lt;void,void&gt; shutdown;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">};</span><br>
+Chords with only
+async&lt;&gt; methods will run its body as an asynchronous task,
+either in a newly spawned thread, , or in the thread
+pool of executor, or in exisiting applications' execution services
+(such as Boost.Asio's
+main threads). So executor is the "engine" of Join based
+applications. Different execution strategies can be used, such as a
+thread per request or thread pool, as long as it provides a
+functional / functor interface to spawn a task: <span
+ style="font-weight: bold;">void
+operator()(task t). </span><br>
+Here the default executor class is thread
+pool based and defined using
+async&lt;&gt; / synch&lt;&gt; methods and chords,&nbsp; and is a good
+sample
+of
+Join.<br>
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">executor(int num_threads, const char
+*name = NULL)</span>: <br>
+<ul>
+ <li>int num_threads: number of worker threads in executor's thread
+pool</li>
+ <li>const char *name: name of executor, a flag to turn on/off
+debugging messages<br>
+ </li>
+</ul>
+<span style="font-weight: bold;">async&lt;task&gt; execute</span>: an
+asynchronous method for applications to submit tasks; never block; it
+is the default <span style="font-weight: bold;">task queue</span> of
+executor.<br>
+<span style="font-weight: bold;">synch&lt;void()&gt; shutdown</span>:
+a synchronous method for application code to wait for executor to
+shutdown (and its threads to exit). All chords defined with <span
+ style="font-weight: bold;">shutdown</span> have a low priority (1)
+than normal (0), so shutdown will return when all submited tasks have
+been finished and all worker threads exit.<br>
+</div>
+<ol start="8">
+ <li>support of group/bundle of async&lt;&gt; methods:</li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">boost::array&lt;async&lt;</span><span
+ style="font-weight: bold;">void
+(T1, T2, ...)</span><span style="font-weight: bold;">&gt;, N&gt;<br>
+</span><span style="font-weight: bold;">boost::array</span><span
+ style="font-weight: bold;">&lt;async_o&lt;</span><span
+ style="font-weight: bold;">void
+(T1, T2, ...)</span><span style="font-weight: bold;">&gt;, N&gt;<br>
+</span><span style="font-weight: bold;"></span>In C&#969;&nbsp; the chords
+are defined with a&nbsp; few async/synch methods with distinct names.
+What if
+we want to
+define chords with a group / array of asynchronous message channels
+(methods) with the same signatures? Inspired by
+similar abstractions in CCR[4] and C#.Joins[3], Join allows the
+definition of an array of async methods and their participation
+in chord as a whole. Since there are at most one synch method per
+chord, so there is no support for array of synch methods. Also
+because async method functors are noncopyable and non-assignable, we
+cannot use STL containers (such as vectors) to contain them, we have to
+use boost::array. Correspondingly, their arguments are represented
+as an array of async_o. Please refer to the Group of Asynchronous
+Channel
+tutotail (join_many.cpp) for their usage. <span
+ style="font-weight: bold;"></span></div>
+<ol start="9">
+ <li>exceptions</li>
+</ol>
+<div style="margin-left: 40px;">
+<p>In C&#969; , many of the following errors related to the definitions of
+async/synch methods and chords will be found by the compiler. Since
+Join is implemented as a library, these errors can only be
+reported as the following exceptions during runtime:</p>
+<p><span style="font-weight: bold;">class
+join_exception : public
+std::exception</span></p>
+<p style="margin-left: 40px;"><span style="font-weight: bold;"></span>the
+base class of all Join related exceptions</p>
+<p><span style="font-weight: bold;">class not_in_chord_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When a async / synch method is declared
+and no chord include it, this method has no body defined similar
+to&nbsp; pure virtual method in C++ abstract classes (pure virtual
+methods have only signature / declaration, no body). When this class is
+instantiated and client code calls this method, not_in_chord_exception
+will be thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class double_association_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">Every async / synch method should only
+be associated with one actor. When attempting to use the method in the
+chords of more than one actors, this exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class
+queue_overflow_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">For basic flow control, async / synch
+method can be constructed with a limited queue size. When the buffered
+(unprocessed) messages exceed the queue size, this exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class no_executor_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When an actor contains chords with only
+async methods but without an executor associated, this exception is
+thrown.<br>
+</div>
+<p><span style="font-weight: bold;">class hidden_chord_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When actor's scheduling policy is
+fire_as_soon_as_possible (default), if the definition of a new chord
+contains all the ports of another chord, or vice versa, this exception
+will be thrown.<br>
+</div>
+<p><span style="font-weight: bold;">class too_many_ports_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When defining a new chord, the total
+number of async / synch methods (accumulated thru all the defined
+chords) exceeds the max_size of actor, this exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span></p>
+<p><span style="font-weight: bold;">class chord_override_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When chord_override() is called and no
+existing chord found with the same set of async / synch methods, this
+exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;">class chord_remove_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When chord_remove() is called and no
+existing chord found with the same set of async / synch methods, this
+exception is thrown.<br>
+<br>
+</div>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+synch_not_1st_exception : public join_exception </span><br
+ style="font-weight: bold;">
+</div>
+<p style="margin-left: 80px;">When chords are defined with synchronous
+method, however the synchronous method is not used as the first method
+of chord, this exception is thrown.<br>
+</p>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"> class
+single_synch_exception : public
+join_exception </span><br>
+</div>
+<p style="margin-left: 80px;">When chords are defined with more than
+one synchronous methods, this exception is thrown.<br>
+</p>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"> class
+synch_time_out_exception :
+public
+join_exception </span><br>
+<div style="margin-left: 40px;">The call of a synchronous port is timed
+out</div>
+</div>
+<div style="margin-left: 40px;"></div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/synopsis_port.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/synopsis_port.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,639 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Synopsis of Join Classes</title>
+</head>
+<body>
+<h2>Synopsis of Join Classes (Port Based API)<br>
+</h2>
+In this API, the asynchronous and synchronous channels are modeled as
+"ports", which can take only one argument - the message type passed
+thru channels/ports. Function based API
+is built on top of port based
+API.
+<ol>
+ <li>classes</li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">namespace
+boost {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; namespace join {</span><br>
+</div>
+<div style="margin-left: 40px;">&nbsp;&nbsp;<span
+ style="font-weight: bold;">&nbsp; &nbsp;&nbsp;&nbsp; template
+&lt;typename MsgT&gt; class async_p;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;typename ResT, typename MsgT&gt; class synch_p;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;typename MsgT&gt; class async_v;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;typename ResT, typename MsgT&gt; class synch_v;</span><br>
+</div>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp; <br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+template &lt;typename executor, size_t max_size&gt;
+class actor;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+class executor;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br>
+</div>
+<ol start="2">
+ <li>Asynchronous ports<br>
+ <span style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename MsgT&gt;&nbsp; </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class async_p {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef
+MsgT argument_type;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+......</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+typedef
+async_v&lt;MsgT&gt;
+var_type;</span><br style="font-weight: bold;">
+&nbsp;
+<span style="font-weight: bold;"></span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+async_p(size_t sz=0) : ... { ... }</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
+operator()(MsgT msg)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+<br>
+Asynchronous port objects are not copyable or assignable, since they
+contain state for on-going messaging. We can only pass around pointers
+and references to them.<br>
+<br>
+<span style="font-weight: bold;">async_p(size_t sz=0):<br>
+Effect: </span>initialize a asynchronous port with underlying
+message queue.
+The queue size <span style="font-weight: bold;">sz</span> is specified
+for flow control; the default value 0 means
+unlimited queue size. Internally there are 2 implementations for this
+class. If the signature is async&lt;void&gt;, there is no
+message to be passed, and template specialization will choose
+a proper implementation without a queue (and its overhead) while
+maintaining the
+same semantics.<span style="font-weight: bold;"><br>
+Throw:<br>
+<br>
+</span><span style="font-weight: bold;">void operator()(MsgT msg): </span><br>
+<span style="font-weight: bold;">Effect:</span> the port api to
+send asynchronous messages; calling threads will return immediately.
+Since async calls will return immediately, and <span
+ style="font-weight: bold;">msg</span> argument may be
+buffered in queues, the <span style="font-weight: bold;">msg</span>
+argument cannot be references or pointers to
+variables on calling stacks which will be unwound when async calls
+return.<br>
+<span style="font-weight: bold;">Throws</span>: not_in_chord_exception,
+queue_overflow_exception, no_executor_exception<br>
+</div>
+<ol start="3">
+ <li>Synchronous ports<span style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename ResT, typename MsgT&gt; <br>
+class synch_p {<br>
+public:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef MsgT argument_type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef ResT result_type;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; typedef synch_v&lt;ResT, MsgT&gt;
+var_type;<br>
+&nbsp;
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synch(size_t sz=0) : ... { ... }<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ResT operator()(MsgT msg);<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ResT operator()(MsgT msg, boost::xtime &amp;timeout);<br>
+</span><span style="font-weight: bold;">};<br>
+<br>
+</span>Synchronous ports are not copyable or assignable, since
+they contain state for on-going messaging. We can only pass around
+pointers and references to them.<br>
+<br>
+<span style="font-weight: bold;">synch_p(size_t sz=0):<br>
+Effect: </span>initialize a synchronous port with underlying thread
+waiting queue.
+The queue size <span style="font-weight: bold;">sz</span> is specified
+for flow control; the default value 0 means
+unlimited queue size. Internally there are four implementations and
+template specialization help choose the most efficient one.<span
+ style="font-weight: bold;"><br>
+Throw:<br>
+<br>
+</span><span style="font-weight: bold;">ResT operator()(MsgT msg):</span><br>
+<span style="font-weight: bold;">Effect: </span>the port
+interface to send a synchronous message;
+calling thread will block here till a reply is available. Since the
+call will block till a result is returned, the <span
+ style="font-weight: bold;">msg</span> argument can be
+anything just as normal function calls, including pointers or
+references to variables on stack.<br>
+<span style="font-weight: bold;">Throws: </span>not_in_chord_exception,
+queue_overflow_exception,&nbsp;
+application_specific_exceptions_raised_inside_chord_body<br>
+<br>
+<span style="font-weight: bold;">ResT operator()(MsgT msg, boost::xtime
+&amp;timeout):</span><br>
+<span style="font-weight: bold;">Effect: </span>this is a variant of
+the above interface with a timeout. The call will return either the
+result is available or return with a "synch_time_out_exception" when
+the timeout is reached.<br>
+<span style="font-weight: bold;">Throws:</span><span
+ style="font-weight: bold;"></span> not_in_chord_exception,
+queue_overflow_exception, synch_time_out_exception,&nbsp;
+application_specific_exceptions_raised_inside_chord_body<span
+ style="font-weight: bold;"> </span>
+</div>
+<ol start="4">
+ <li>wrapper objects for asynchronous ports (used as arguments of
+chord body)<span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template&lt;typename
+MsgT&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class async_v {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+MsgT arg1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+.......</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp; void
+operator()(MsgT msg)<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span style="font-weight: bold;">operator
+MsgT();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span style="font-weight: bold;">MsgT
+&amp;arg(void)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+async_v is a wrapper of asynchronous ports, used as the arguments of
+chord body functions. Its main purpose is to represent the
+arguments/message passed in by asynchronous ports, specifically the
+argument or message at the top of queue.<br>
+<br>
+<span style="font-weight: bold;">arg1: </span>message/argument of
+the associated asynchronous port<span style="font-weight: bold;"><br>
+<br>
+</span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">void operator()(</span><span
+ style="font-weight: bold;">MsgT msg</span><span
+ style="font-weight: bold;">):</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>invoke the associated
+asynchronous port.<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws: </span>not_in_chord_exception,
+queue_overflow_exception, no_executor_exception<br>
+<br>
+The following two convenience methods are defined for fetching
+message/argument:<br>
+<span style="font-weight: bold;">operator MsgT(): </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>a conversion function,
+so that async_v can be used as an argument of type T<br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">MsgT &amp;arg(void):</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>retrieve the
+argument/message explicitly. This is necessary in situation where the
+implicit conversion cannot be applied<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br>
+<span style="font-weight: bold;"></span></div>
+<ol start="5">
+ <li>wrapper objects for synchronous ports (used as arguments of
+chord body)<span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span></li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">template&lt;typename ResT, typename
+MsgT&gt; </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class synch_v {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MsgT
+arg1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+.......<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp; ResT
+operator()(MsgT msg)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; </span><span
+ style="font-weight: bold;">operator
+MsgT();<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Msg</span><span
+ style="font-weight: bold;">T
+&amp;arg(void)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">};</span><br>
+synch_v is a wrapper of synchronous ports, used as the arguments of
+chord body functions. It serves two purposes:<br>
+<ul>
+ <li>representing
+the
+argument/message passed in by synchronous ports, specifically the
+arguments or message at the top of queue; <br>
+ </li>
+ <li>allowing replying to
+the synchronous ports.</li>
+</ul>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">arg1:
+</span>arguments of the associated synchronous port<br>
+<br>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">ResT
+operator()(MsgT msg)</span><span style="font-weight: bold;">:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>invoke the associated
+synchronous port.<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws: </span>not_in_chord_exception,
+queue_overflow_exception,&nbsp;
+application_specific_exceptions_raised_inside_chord_body<br>
+<span style="font-weight: bold;"><br>
+</span>The following two convenience methods are defined for fetching
+message/argument passed in ports:<br>
+<span style="font-weight: bold;">operator T(): </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>a conversion function,
+so that synch_v can be used as an argument of type T<br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">T &amp;arg(void):</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect: </span>retrieve the
+argument/message explicitly. This is necessary in situation where the
+implicit conversion cannot be applied<br style="font-weight: bold;">
+<span style="font-weight: bold;">Throws:</span><br>
+</div>
+<ol start="6">
+ <li>actor</li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;</span><span style="font-weight: bold;">typename executor =</span><span
+ style="font-weight: bold;"> async&lt;task&gt;</span><span
+ style="font-weight: bold;">, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+template &lt;size_t&gt; scheduler = sched_first_match,<br>
+</span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; size_t
+max_size = 32&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+actor(executor *execute = NULL, const char
+*name = NULL);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+template
+&lt;typename PortT1, typename PortT2,
+......, typename CallT&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void chord(PortT1
+&amp;p1, PortT2 &amp;p2, ......, CallT c, int priority=0)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+template
+&lt;typename PortT1, typename PortT2, </span><span
+ style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">typename CallT&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+chord_override(PortT1 &amp;p1, PortT2 &amp;p2, </span><span
+ style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">CallT c</span><span
+ style="font-weight: bold;">, int priority=0</span><span
+ style="font-weight: bold;">)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+template
+&lt;typename PortT1, typename PortT2,
+......&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; void
+chord_remove(PortT1
+&amp;p1, PortT2 &amp;p2, ......)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+......</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+Actor is the parent class of all classes which use
+async&lt;&gt; / synch&lt;&gt; methods and chords to define concurrent
+activities. Actor maintains the status of message arrival and
+synchronization. Actors are not copyable or assignable. We can only
+pass around pointers and references to them.<br>
+<br>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">typename
+executor:</span> <br>
+&nbsp;&nbsp;&nbsp; the type of execution service used to drive Join
+based asynchronous applications. It could be the async "execute" method
+of the following thread pool based executor, or it could be a adaptor
+to existing applications execution service, as long as it provides a
+functional / functor interface to spawn a task:<br>
+&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">void
+operator()(task t);<br>
+<br>
+</span><span style="font-weight: bold;">max_size:</span> <br>
+&nbsp;&nbsp;&nbsp; defines the capacity
+of actor, ie. how many async&lt;&gt; / synch&lt;&gt; methods can be
+defined in this actor. When max_size &lt;= 32, integer bitmask is used
+to maintain status; while for "larger" actor, std::bitset&lt;&gt; is
+used for status.<br>
+<br>
+<span style="font-weight: bold;">scheduling_policy: </span><br>
+&nbsp;&nbsp;&nbsp; actor
+supports three kinds of scheduling policies that decide which chord
+will fire when multiple chords become ready at the same time:<br>
+<ul>
+ <li><span style="font-weight: bold;">sched_first_match</span>: fire
+the first chord which is ready to
+fire</li>
+ <li><span style="font-weight: bold;">sched_longest_match</span>: when
+multiple chords are ready to fire,
+fire the one defined with most async&lt;&gt; / synch&lt;&gt; methods.</li>
+ <li><span style="font-weight: bold;">sched_round_robin</span>:
+internally the last chord fired is
+remembered and chords are fired in round-robin style.</li>
+</ul>
+<span style="font-weight: bold;">actor(executor *execute =
+NULL, const char *name = NULL):<br>
+</span>&nbsp;&nbsp;&nbsp; an actor is constructed with the following
+two settings:<br>
+<ul>
+ <li>executor *execute: the asynchronous method to spawn a new task
+(from a function object <span style="font-weight: bold;">function&lt;void()&gt;</span>).
+It could be an adaptor to spawn tasks into existing applications main
+threads (and it must be non-blocking and returns immediately), or the
+execute method of the following executor (thread pool),
+ie.
+the task waiting queues. In Join based applications, there is no
+explicit usage of threads (creation / synchronization), concurrency are
+generated by
+chords with only async&lt;&gt; methods whose body will run as a task in
+executor thread pool.<br>
+ </li>
+ <li>const char *name: the name of actor; it is used as a flag to turn
+on/off debug messages, when it is set to a non-NULL value, debugging
+message will be printed out.<br>
+ </li>
+</ul>
+<span style="font-weight: bold;">template
+&lt;typename PortT1, typename PortT2,
+......, typename CallT&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">void chord(PortT1 &amp;p1, PortT2
+&amp;p2, ......, CallT c, int priority=0)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">Effect:
+</span>overloaded chord()
+functions to create chords with different number of
+async&lt;&gt; / synch&lt;&gt; methods. By default actor has just eight
+overloaded chord() functions to create chords for one to eight
+async&lt;&gt; / synch&lt;&gt; methods,&nbsp; because any of these
+async&lt;&gt; methods can be a array&lt;async&lt;&gt;&gt;, so in fact
+chords can be created for unlimited number of
+async&lt;&gt; methods, while each chord can have at most one
+synchronous method:<br>
+<ul>
+ <li>PortT &amp;p, &amp;p1, ... &amp;pn: async&lt;&gt; / synch&lt;&gt;
+methods which are in the header of chord body; only one of them can be
+synchronous and if we do have one, it must the first method.<br>
+ </li>
+ <li>CallT c: a function, class-method, or object-method which can be
+used as the chord body</li>
+ <li>int priority: the scheduling priority of this chord; the
+default value 0 has the highest priority, the greater the number, the
+lower the priority. During scheduling, the chords with higher priority
+will be scanned and scheduled first.</li>
+</ul>
+<span style="font-weight: bold;">Throws: </span>hidden_chord_exception,
+too_many_ports_exception<br>
+<br>
+<span style="font-weight: bold;">template &lt;typename PortT1, typename
+PortT2, </span><span style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">typename CallT&gt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">void chord_override(PortT1 &amp;p1,
+PortT2 &amp;p2, </span><span style="font-weight: bold;">......, </span><span
+ style="font-weight: bold;">CallT c</span><span
+ style="font-weight: bold;">, int priority=0</span><span
+ style="font-weight: bold;">)</span><span style="font-weight: bold;"></span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">Effect:&nbsp; </span>allow overriding
+an existing chord (the chord body is replaced with the new one).
+It is mostly used in child class to override a chord defined in parent
+class. The overridden chord is identified by the set of async&lt;&gt; /
+synch&lt;&gt; methods in its header. It uses the same arguments as
+normal chord() functions. <br>
+<span style="font-weight: bold;">Throws:&nbsp; </span>chord_override_exception
+(chord not found)<br>
+<br>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename PortT1, typename PortT2,
+......&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">void chord_remove(PortT1
+&amp;p1, PortT2 &amp;p2, ......)</span><br style="font-weight: bold;">
+</div>
+<div style="margin-left: 40px;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">Effect:&nbsp; </span>remove the chord
+identified by the set of async / synch methods. <br>
+<span style="font-weight: bold;">Throws:&nbsp; </span>chord_remove_exception
+(chord not found)<br>
+<span style="font-weight: bold;"></span></div>
+<ol start="7">
+ <li>executor</li>
+</ol>
+<div style="margin-left: 40px; font-weight: bold;">template
+&lt;template &lt;size_t&gt; class scheduler=sched_first_match, size_t
+sz=32&gt;<br>
+class executor :
+public actor {<br>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+executor(int
+num_threads, const char *name = NULL);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; async_p&lt;task&gt;
+execute;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+synch_p&lt;void,void&gt; shutdown;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">};</span><br>
+Chords with only
+async&lt;&gt; methods will run its body as an asynchronous task,
+either in a newly spawned thread, , or in the thread
+pool of executor, or in exisiting applications' execution services
+(such as Boost.Asio's
+main threads). So executor is the "engine" of Join based
+applications. Different execution strategies can be used, such as a
+thread per request or thread pool, as long as it provides a
+functional / functor interface to spawn a task: <span
+ style="font-weight: bold;">void
+operator()(task t). </span><br>
+Here the default executor class is thread
+pool based and defined using
+async&lt;&gt; / synch&lt;&gt; methods and chords,&nbsp; and is a good
+sample
+of
+Join.<br>
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">executor(int num_threads, const char
+*name = NULL)</span>: <br>
+<ul>
+ <li>int num_threads: number of worker threads in executor's thread
+pool</li>
+ <li>const char *name: name of executor, a flag to turn on/off
+debugging messages<br>
+ </li>
+</ul>
+<span style="font-weight: bold;">async&lt;task&gt; execute</span>: an
+asynchronous method for applications to submit tasks; never block; it
+is the default <span style="font-weight: bold;">task queue</span> of
+executor.<br>
+<span style="font-weight: bold;">synch&lt;void()&gt; shutdown</span>:
+a synchronous method for application code to wait for executor to
+shutdown (and its threads to exit). All chords defined with <span
+ style="font-weight: bold;">shutdown</span> have a low priority (1)
+than normal (0), so shutdown will return when all submited tasks have
+been finished and all worker threads exit.<br>
+</div>
+<ol start="8">
+ <li>support of group/bundle of async&lt;&gt; methods:</li>
+</ol>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">boost::array&lt;async_p&lt;</span><span
+ style="font-weight: bold;">MsgT</span><span style="font-weight: bold;">&gt;,
+N&gt;<br>
+</span><span style="font-weight: bold;">boost::array</span><span
+ style="font-weight: bold;">&lt;async_v&lt;</span><span
+ style="font-weight: bold;">MsgT</span><span style="font-weight: bold;">&gt;,
+N&gt;<br>
+</span><span style="font-weight: bold;"></span>In C&#969;&nbsp; the chords
+are defined with a&nbsp; few async/synch methods with distinct names.
+What if
+we want to
+define chords with a group / array of asynchronous message channels
+(methods) with the same signatures? Inspired by
+similar abstractions in CCR[4] and C#.Joins[3], Join allows the
+definition of an array of async methods and their participation
+in chord as a whole. Since there are at most one synch method per
+chord, so there is no support for array of synch methods. Also
+because async method functors are noncopyable and non-assignable, we
+cannot use STL containers (such as vectors) to contain them, we have to
+use boost::array. Correspondingly, their arguments are represented
+as an array of async_o. Please refer to the Group of Asynchronous
+Channel
+tutotail (join_many.cpp) for their usage. <span
+ style="font-weight: bold;"></span></div>
+<ol start="9">
+ <li>exceptions</li>
+</ol>
+<div style="margin-left: 40px;">
+<p>In C&#969; , many of the following errors related to the definitions of
+async/synch methods and chords will be found by the compiler. Since
+Join is implemented as a library, these errors can only be
+reported as the following exceptions during runtime:</p>
+<p><span style="font-weight: bold;">class
+join_exception : public
+std::exception</span></p>
+<p style="margin-left: 40px;"><span style="font-weight: bold;"></span>the
+base class of all Join related exceptions</p>
+<p><span style="font-weight: bold;">class not_in_chord_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When a async / synch method is declared
+and no chord include it, this method has no body defined similar
+to&nbsp; pure virtual method in C++ abstract classes (pure virtual
+methods have only signature / declaration, no body). When this class is
+instantiated and client code calls this method, not_in_chord_exception
+will be thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class double_association_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">Every async / synch method should only
+be associated with one actor. When attempting to use the method in the
+chords of more than one actors, this exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class
+queue_overflow_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">For basic flow control, async / synch
+method can be constructed with a limited queue size. When the buffered
+(unprocessed) messages exceed the queue size, this exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class no_executor_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When an actor contains chords with only
+async methods but without an executor associated, this exception is
+thrown.<br>
+</div>
+<p><span style="font-weight: bold;">class hidden_chord_exception :
+public
+join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When actor's scheduling policy is
+fire_as_soon_as_possible (default), if the definition of a new chord
+contains all the ports of another chord, or vice versa, this exception
+will be thrown.<br>
+</div>
+<p><span style="font-weight: bold;">class too_many_ports_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When defining a new chord, the total
+number of async / synch methods (accumulated thru all the defined
+chords) exceeds the max_size of actor, this exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;"></span></p>
+<p><span style="font-weight: bold;">class chord_override_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When chord_override() is called and no
+existing chord found with the same set of async / synch methods, this
+exception is thrown.<br>
+</div>
+<p><span style="font-weight: bold;">class chord_remove_exception :
+public join_exception<br>
+</span></p>
+<div style="margin-left: 40px;">When chord_remove() is called and no
+existing chord found with the same set of async / synch methods, this
+exception is thrown.<br>
+<br>
+</div>
+</div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+synch_not_1st_exception : public join_exception </span><br
+ style="font-weight: bold;">
+<p style="margin-left: 40px;">When chords are defined with synchronous
+method, however the synchronous method is not used as the first method
+of chord, this exception is thrown.<br>
+</p>
+<span style="font-weight: bold;"> class single_synch_exception : public
+join_exception </span><br>
+<p style="margin-left: 40px;">When chords are defined with more than
+one synchronous methods, this exception is thrown.<br>
+</p>
+<span style="font-weight: bold;"> class synch_time_out_exception :
+public
+join_exception </span><br>
+<p style="margin-left: 40px;">The call of a synchronous port is timed
+out.<br>
+</p>
+</div>
+<div style="margin-left: 40px;"></div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,311 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Join Tutorials</title>
+</head>
+<body>
+<h2>Tutorials</h2>
+<dl>
+ <dt>The following are some tutorials to demonstrate the usage of
+Join.&nbsp;</dt>
+</dl>
+Basic Concurrency Idioms<br>
+<a href="#difference">Tutorials Showing the Differences between
+Join and C&#969;</a><br>
+OO Concurrency Design and Extensions Tutorials<br>
+Applications<br>
+<h3><a name="basic"></a>Basic Concurrency Idioms:</h3>
+<div style="margin-left: 40px;">Most of the following tutorials are
+adapted
+from <a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorials_concurrency_extensions.htm">C&#969;
+Concurrency Extensions Tutorials[2]</a> to
+demonstrate
+how to encode common concurrency idioms using Join. <br>
+<br>
+Buffer
+Tutorial<br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration defining an
+thread-safe unbounded buffer. <br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_buffer.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="./tutorials/buffer_tutorial.html">Join buffer tutorial</a>,
+<a href="../examples/func_api/buffer.cpp">example translated using
+Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;">One-Place
+Buffer Tutorial<br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of a one-place
+buffer.<br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_one_place_buffer.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="tutorials/one_place_buffer_tutorial.html">Join tutorial</a>,
+<a href="../examples/func_api/one_place_buffer.cpp">example
+translated using Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;">Spawning
+Threads Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of spawning
+threads using asynchronous
+methods. <br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_spawning_threads.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="tutorials/spawn_tutorial.html">Join tutorial</a>, <a
+ href="../examples/func_api/spawner1.cpp">example translated using
+Join.</a><br>
+Another <a href="../examples/func_api/spawner2.cpp">simpler spawning
+sample</a> using Join executor directly.<br>
+<br>
+</div>
+<div style="margin-left: 40px;">Using
+Asynchronous Messages For State Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of using
+asynchronous messages to carry
+state across method calls. <br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_using_asynchronous_messages.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="tutorials/async_msg_state_tutorial.html">Join tutorial</a>,
+<a href="../examples/func_api/counter.cpp">example translated using
+Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;">Reader-Writer
+Lock Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of how to
+program a
+Reader/Writer-lock. <br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_reader_writer_lock.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="../examples/func_api/rwlock.cpp">example translated using
+Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;">Bounded
+Buffer Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple example of defining a bounded
+buffer.<br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_bounded_buffer.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="../examples/func_api/bounded_buffer.cpp">example translated
+using Join.</a><br>
+</div>
+<dl style="margin-left: 40px;">
+ <dt>
+ <p>The previous samples described how private asynchronous messages
+may be used to carry state. The following samples show how to
+orchestrate asynchronous messages between different objects: </p>
+ </dt>
+</dl>
+<div style="margin-left: 40px;">Semaphores
+Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of how to encode
+semaphores.<br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_semaphores.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="../examples/func_api/semaphore.cpp">example translated using
+Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;">Asynchronous
+Call and Return Patterns Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of how to return
+values from
+asynchronous calls. This sample also demonstrate how to define
+"interfaces" in Join. Class IService defines an interface in that it
+defines an async&lt;&gt; method (Service) without chord, so this method
+has no body defined yet, same as the pure virtual method in C++
+abstract classes. Child implmentation classes (MyService) "implements"
+this interface by defining a chord (thus method body) for this method.<br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_asynchronous_call_and_return.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="tutorials/async_call_ret_tutorial.html">Join tutorial</a>,
+<a href="../examples/func_api/async_call_ret.cpp">example translated
+using Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;">Active
+Objects Tutorial <br>
+</div>
+<div style="margin-left: 80px;">a simple demonstration of how to define
+active objects
+(agents). This sample also demonstrate how to define "interfaces" in
+Join. Class EventSink defines an async&lt;&gt; method (Post) without
+chord and body. Class Distributor and class Subscriber "implement" this
+interface by defining chord and method_body for Post().<br>
+<a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_active_objects.htm">the
+original C&#969; tutorial page and example</a> and <a
+ href="tutorials/act_obj_tutorial.html">Join tutorial</a>, <a
+ href="../examples/func_api/active_object.cpp">example translated
+using Join.</a><br>
+<br>
+</div>
+<div style="margin-left: 40px;"><a href="tutorials/future_tut.html">Future
+Tutorial</a> and sample code<br>
+</div>
+<div style="margin-left: 80px;">Future is a abstraction
+representing the value of a concurrent computation. Creating a future
+initiates a concurrent computation in another thread (in the executor
+thread pool) and then initiating thread is
+free to perform other tasks. When initiator needs the value of
+computation, it can call the future's get() method to synchronize with
+the computing thread and wait until/unless the computation is done.
+This sample shows a simple implementation of future using Join;
+adapted from sample in the C#.Joins library [3].<br>
+</div>
+<div style="margin-left: 80px;">
+</div>
+<h3><a name="difference"></a><span style="font-weight: bold;">Tutorials
+Showing the Differences between Join and C&#969;:</span></h3>
+<div style="margin-left: 40px;"><a href="tutorials/dyn_chord_tut.html">Array
+of Asynchronous Channel Tutorial</a> and <a
+ href="../examples/func_api/join_many.cpp">sample
+code</a><br>
+</div>
+<div style="margin-left: 80px;">a sample of how to define an array of
+async channels (methods) and chords. The
+class join_many is a "merger" which merges the results from an array of
+input streams (async&lt;void(T)&gt;) and return as&nbsp; a whole. This
+sample is adapted from the C# Joins library.<br>
+<br>
+</div>
+<div style="margin-left: 40px;"><a href="tutorials/exe_tut.html">Executor
+And Dynamic Chord Tutorial</a>
+and code<br>
+</div>
+<div style="margin-left: 80px;">Executors are the "engine" of
+Join based applications - the body of all chords with only / pure
+async methods will run in the thread pool of executor. As the first
+application of Join, totally defined with async / synch methods
+and chords, class executor is also a good sample of using dynamically
+created async methods and chords.<br>
+</div>
+<div style="margin-left: 80px;"><br>
+</div>
+<div style="margin-left: 40px;"><a href="tutorials/prime_sieve_tut.html">Multi
+Task Queue and Round
+Robin Scheduling Tutorial</a> and <a
+ href="../examples/func_api/prime_sieve.cpp">sample code</a><br>
+</div>
+<div style="margin-left: 80px;">In concurrent applications, there are
+many event/message producers and consumers. Some producers produce much
+more events/messages than others and much faster. If the handling of
+all events/messages are dispatched to the same task queue, the fast
+producer will flood the task queue while the events/messages from slow
+producer wont get a fair chance to be processed. The executor of
+Join solve this problem with multiple task queues and round-robin
+scheduling which are implemented using dynamic async methods and
+chords. <br>
+Prime_sieve.cpp is a simple application for finding prime numbers using
+a
+chain of concurrent tasks. <a href="http://swtch.com/%7Ersc/thread/">The
+original design</a> is based on CSP style channels. In this sample,
+each of tasks is assigned a separate task_queue and
+executor's thread pool
+round-robin through all task queues so that all tasks get a fair chance
+to run.<br>
+</div>
+<h3><span style="font-weight: bold;">OO
+Concurrency Design and Extensions:</span></h3>
+<div style="margin-left: 40px;"><a href="tutorials/override_tut.html">Chord
+Overriding Tutorial</a> and
+sample code<br>
+</div>
+<div style="margin-left: 80px;">Join supports two kinds of chord
+overriding: <br>
+<ul>
+ <li>static-overriding - the chord body method can be a C++ virtual
+method and overriden in child class to provide polymorphic behaviour.</li>
+ <li>dynamic-overriding - chord_override() method can be called with
+the set of async / synch methods of a existing chord and a new body
+method; the identified chord will replace its body with the new body
+method.</li>
+</ul>
+</div>
+<div style="margin-left: 40px;"><a href="tutorials/aggreg_tut.html">Extending
+by
+Aggregation and Delegation Tutorial</a> and <a
+ href="../examples/func_api/logged_buffer.cpp">sample code</a><br>
+<div style="margin-left: 40px;">The design of Integrated Circuit (IC)
+is thru aggregation: composing smaller components into larger ones.
+Join support this kind of design in software. Two basic methods
+of aggregation are "aliasing" and "adapting". This logged_buffer sample
+demonstrates how to extend the "buffer" sample thru aggregation:<br>
+</div>
+</div>
+<div style="margin-left: 40px;">
+<ul>
+ <ul>
+ <li>composing: logged_buffer maintains a inner actor: buffer<br>
+ </li>
+ <li>aliasing: the interface of inner actor buffer (put(), get()) is
+exposed <span style="font-weight: bold;">directly</span> at
+logged_buffer by C++ references to these methods of
+inner buffer.<br>
+ </li>
+ <li>adapting: a new async&lt;&gt; method logged_put() is defined by
+invoking inner buffer's put() with the addition of logging.</li>
+ </ul>
+</ul>
+</div>
+<h3><a name="application"></a><span style="font-weight: bold;">Applications:</span></h3>
+<div style="margin-left: 40px;"><a href="tutorials/events_tut.html">Thread
+Safe Events Tutorial</a><a
+ href="../examples/func_api/chord_override.cpp"></a><br>
+<div style="margin-left: 40px;">Join allow us to experiment with
+some interesting designs of thread safe
+events dispatching with the following design considerations:<br>
+<ul>
+ <li>Allow subscribing / unsubscribing to events concurrently from
+different threads; events data structures must be thread safe.</li>
+ <li>Allow callback code to invoke the event
+interface again, change / delete event subscription or post a new
+event during the process of event dispatching / handling. This is
+difficult to
+handle with the "synchronous" semantics of
+normal method calls.
+Join's async methods provide an alternative to solve these issues.<br>
+ </li>
+ <li>When applications run on multi-core machines, we may want the
+callbacks to execute concurrently for better performance.</li>
+</ul>
+</div>
+Data Parallel Programming Tutorial<br>
+<div style="margin-left: 40px;">How to harness the computing power of
+multi-core computers and make applications
+scalable for more CPUs is a challenging task. Data Parallel paradigm is
+particularly suitable for
+parallelizing computationally intensive work, allowing multiple tasks
+concurrently working on different parts of data. Data parallel
+programming scales well to larger number of processors by dividing the
+data collection into smaller pieces. Program performance increases as
+you add more processors.<br>
+<br>
+Join's toolset (async / synch methods and chords) provides a good
+foundation for data parallel programming. In this tutoral we discuss
+how to implement parallel loops and parallel map-reduce algorithm in
+Join.</div>
+<br>
+</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/act_obj_tutorial.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/act_obj_tutorial.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,242 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Active Object Tutorial</title>
+</head>
+<body>
+<h2>Join Active Object Tutorial</h2>
+<h4 style="font-weight: normal;" class="dtH4">This tutorial shows a
+simple demonstration of how to define
+active objects
+(agents). This sample also demonstrate how to define "interfaces" or
+"abstract classes" in
+Join.&nbsp;
+</h4>
+<span style="font-weight: normal;">Active objects have their own
+threads and communicate with each other thru asynchronous
+messages.<br>
+First we define an "abstract" base class which all active objects will
+inherit. <br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+ActiveObject : public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">protected:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; bool done;<br>
+</span></div>
+Here we declare a synch method without defining its chord (body). So
+this is a pure virtual method and this class is abstract. Child classes
+should "implement" it by providing chords (thus body and real
+functionality) for it.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;void()&gt; ProcessMessage;<br>
+</span></div>
+Next we define a async method to "activate" the active object -&nbsp;
+starting its own thread.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; Start;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+</div>
+In constructor, we initialize the parent actor with the
+executor and define a chord for the above async "Start" method. Since
+this chord has only async method, its body will run in a thread from
+executor's thread pool. At end of constructor, we call async method
+Start() to start the active object's thread.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+ActiveObject(executor *e) : actor(e), done(false) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(Start,
+&amp;ActiveObject::main_loop);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; Start();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the main loop of active object's thread, just repeatedly call
+synch method ProcessMessage to do real job. Since ProcessMessage has no
+chord/body defined yet, it is a pure virtual method; So we are using
+the "template method" design pattern here.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void main_loop(async_o&lt;void()&gt; s) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.msg("Active
+object thread starts");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; while(!done)
+ProcessMessage();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}; </span><br
+ style="font-weight: bold;">
+</div>
+<br>
+In the following code, we use the active object class to
+implement a event distribution service.<br>
+<br>
+First we define a "interface" / "abstract" class for all event
+consumers / sinks, which delcares a async post() method without chord /
+body.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+EventSink {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(std::string)&gt;
+Post;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br>
+</div>
+The event Distributor is both an active object (having its own thread
+and do real job thru ProcessMessage method) and event sink (clients can
+submit event by calling its "Post" method).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Distributor : public ActiveObject, public EventSink {<br>
+</span></div>
+Here is Distributor's state: all subscribers and its name.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+std::vector&lt;EventSink*&gt; subscribers;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; std::string name;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+Here we define a async method for subscribers to subscribe (register to
+be notified).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(EventSink*)&gt;
+Subscribe;<br>
+</span></div>
+Here we define a async method for shutting down the distributor.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; Close;</span><br style="font-weight: bold;">
+</div>
+In constructor, we define multiple chords for ProcessMessage method,
+each of which will be activated when different async messages
+arrive/exist, ie when the distributor is in different states. So in
+fact we are declaratively defining a state-machine
+for Distributor here.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+Distributor(std::string n, executor *e) : ActiveObject(e), name(n) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(ProcessMessage, Subscribe, &amp;Distributor::sub_cb);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(ProcessMessage, Post, &amp;Distributor::post_cb);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(ProcessMessage, Close, &amp;Distributor::close_cb, 1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+</div>
+Here is the chord body for <span style="font-weight: bold;">ProcessMessage()
+&amp; Subscribe()</span>.<span style="font-weight: bold;"> </span>The
+event sink objects passed in thru <span style="font-weight: bold;">Subscribe()</span>
+are added to the vector of subscribers.<span style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void
+sub_cb(synch_o&lt;void()&gt; P, async_o&lt;void(EventSink*)&gt; S) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+subscribers.push_back(S.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the chord body for <span style="font-weight: bold;">ProcessMessage()
+&amp; Post(). </span>Messages passed in thru <span
+ style="font-weight: bold;">Post()</span> will be distributed to all
+subscribers.<span style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void
+post_cb(synch_o&lt;void()&gt; P, async_o&lt;void(std::string)&gt; M) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(size_t i=0;
+i&lt;subscribers.size(); i++) </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+subscribers[i]-&gt;Post(name+" : "+M.arg1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+The chord body of <span style="font-weight: bold;">ProcessMessage()
+&amp; Close(): </span>here we set done=true to notify actor's thread
+to exit.<span style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void
+close_cb(synch_o&lt;void()&gt; P, async_o&lt;void()&gt; C) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; done = true;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+Class subscriber implements "interface" EventSink by defining a
+chord/body for async method Post(), inside&nbsp; which the distributed
+messages are printed out.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Subscriber : public EventSink,
+public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; std::string name;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Subscriber(std::string n,
+executor *e) : actor(e), name(n) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(Post,
+&amp;Subscriber::post_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+post_cb(async_o&lt;void(std::string)&gt; M) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; name &lt;&lt; " got message " &lt;&lt; M.arg1 &lt;&lt;
+logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+In main(), we create an executor with two threads. Then create a
+Distributor object "D" and a few subscribers with the executor. Let
+subscribers to subscribe to distributor. Post some messages to
+distributor and see them received and printed out at subscribers.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">int
+main(int argc, char **argv) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; executor exec(2);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Distributor d("D",
+&amp;exec.execute);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Subscriber a("a",
+&amp;exec.execute);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Subscribe(&amp;a);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Post("First message");</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Subscriber b("b",
+&amp;exec.execute);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Subscribe(&amp;b);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Post("Second message");</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Subscriber c("c",
+&amp;exec.execute);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Subscribe(&amp;c);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Post("Third message");</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; d.Close();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; log1.msg("Main thread waits for
+exit...");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; exec.shutdown();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}<br>
+<br>
+</span></div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/aggreg_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/aggreg_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,206 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Extending by Aggregation and Delegation Tutorial</title>
+</head>
+<body>
+<h2>Join Extending by
+Aggregation and Delegation Tutorial</h2>
+This tutorial shows how Join supports aggregation and delegation
+based design. The design of Integrated Circuit (IC)
+is thru aggregation: composing smaller components into larger ones.
+Join support this kind of design in software. Two basic methods
+of aggregation are "aliasing" and "adapting". This logged_buffer sample
+demonstrates how to extend the "buffer" sample thru aggregation:<br>
+<ul>
+ <li>composing: logged_buffer maintains a inner actor: buffer<br>
+ </li>
+ <li>aliasing: the interface of inner actor buffer (put(), get()) is
+exposed <span style="font-weight: bold;">directly</span> at
+logged_buffer by C++ references to these methods of
+inner buffer.<br>
+ </li>
+ <li>adapting: a new async&lt;&gt; method logged_put() is defined by
+invoking inner buffer's put() with the addition of logging.</li>
+</ul>
+<span style="font-weight: bold;"></span>First we define a simple thread
+safe buffer class as presented in the first tutorial.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class buffer: public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(V)&gt; put;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;V()&gt; get;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; buffer() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(put, get,
+&amp;buffer::chord_body);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+chord_body(async_o&lt;void(V)&gt; put, synch_o&lt;V()&gt;
+get) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; get.reply(put.arg1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"><br>
+</span></div>
+Next we define a logged_buffer class which is implemented thru
+aggregating and extending the original buffer class.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class logged_buffer: public
+actor {<br>
+</span></div>
+Here logged_buffer instantiate an instance of the original buffer class
+and manage its life time.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+buffer&lt;V&gt; buf_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><span
+ style="font-weight: bold;"><br>
+</span></div>
+And define two C++ references to export the interface of internal
+buffer object (its put and get method).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(V)&gt; &amp;put;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;V()&gt; &amp;get;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span></div>
+And define a new async method <span style="font-weight: bold;">logged_put
+</span>which extends the original buffer's put method with logging
+capability.<span style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(V)&gt; logged_put;<br>
+</span></div>
+In constructor, we initialize the parent actor class and inner
+buffer object.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+logged_buffer(executor *e) : actor(e), buf_(),
+<br>
+</span></div>
+And "aliasing"&nbsp; the inner buffer object's put and get method, so
+they are exposed at logged_buffer without any overhead.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; put(buf_.put), get(buf_.get) {<br>
+</span></div>
+And define a chord for the new async logged_put method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(logged_put, &amp;logged_buffer::chord_body);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the chord body for the new async logged_put method; basically
+we print out the arguments and forward it to the inner buffer's put
+method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void chord_body(async_o&lt;void(V)&gt; put) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "logged_put: " &lt;&lt;
+put.arg1 &lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; buf_.put(put.arg1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+<br>
+Class Demo is a multithreaded test driver similar to the class Demo in
+tutorial 1. The only difference is that the producer will send even
+numbers to logger_buffer's put method which is an alias of inner
+buffer's put method and send odd numbers to logged_buffer's logged_put
+method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Demo : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+logged_buffer&lt;std::string&gt; buf_;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; producer;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; consumer;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Demo(executor *e) :
+actor(e), buf_(e) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(producer,
+&amp;Demo::producer_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(consumer,
+&amp;Demo::consumer_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+producer_cb(async_o&lt;void()&gt; p) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; std::ostringstream
+ostr;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostr
+&lt;&lt; i;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i%2
+== 0)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+buf_.put(ostr.str());</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+buf_.logged_put(ostr.str());</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "producer sends
+[" &lt;&lt; i &lt;&lt; "]" &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ostr.str("");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+consumer_cb(async_o&lt;void()&gt; c) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "consumer recvs
+[" &lt;&lt; buf_.get() &lt;&lt; "]" &lt;&lt;
+logger::endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(2);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">int main(int argc, char **argv) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; executor exec(3);&nbsp; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Demo demo(&amp;exec.execute);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; demo.producer();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; demo.consumer();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; exec.shutdown();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+</div>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/async_call_ret_tutorial.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/async_call_ret_tutorial.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,172 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Asynchronous Call and Return Tutorial</title>
+</head>
+<body>
+<h2>Join Asynchronous Call and Return Tutorial</h2>
+<h4 style="font-weight: normal;" class="dtH4">This tutorial shows a
+simple demonstration of how to return
+values from
+asynchronous calls. This sample also demonstrate how to define
+"interfaces" or "abstract classes" in Join. <br>
+</h4>
+Class IService declares a async method "Service" and defines NO chords
+for it. So in IService, "Service" method only has its header or
+signature defined, without a body, similar to the way we define a pure
+virtual method in abstract class. So class IService is an "abstract"
+"active" (actor based) class. Since abstract classes are not fully
+defined (having methods without body defined), we should NOT allow
+creating an instance of&nbsp; them and use it. In C++, compilers will
+help catch it. However Join is implemented as a library,
+compilers will not prevent instantiating them. We'll get runtime
+execptions when we try to use them. In IService, "Service" method
+allows clients to submit requests (strings) to servers and pack up a
+callback method with the request, so that servers can return the
+results with callback.<span style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+IService {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(string,
+async&lt;void(string)&gt;&amp;)&gt; Service;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+The following class MyService initializes the parent actor with
+the executor and "implements" the above "interface" class
+IService by creating a chord for "Service" method and bind it to its
+body method. Also because the chord has only one async method in
+header, its body will run in a thread from executor's thread pool. So
+this server
+handles requests concurrently (in thread pool) and asynchronously, just
+as many of today's network servers.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+MyService : public actor, public IService {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; int n;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; MyService(int m, executor *e) :
+actor(e), n(m) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(Service,
+&amp;MyService::service_fun);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the body method. <span style="font-weight: bold;">Req.arg1</span>
+contains the request string and <span style="font-weight: bold;">req.arg2</span>
+is the callback. In body, we do some work first and then invoke the
+callback to return result.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void service_fun(async_o&lt;void(string,
+async&lt;void(string)&gt;&amp;)&gt; req) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;n; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; req.arg1 &lt;&lt; " is " &lt;&lt; i &lt;&lt;
+logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep((n%2)?1:2);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; req.arg2(req.arg1+"
+is done");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+Class Join2 allows us wait on responses from two concurrent activities.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Join2 : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(string)&gt; first;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(string)&gt;
+second;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;void(string&amp;,
+string&amp;)&gt; Wait;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Join2() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(Wait, first,
+second, &amp;Join2::wait_body);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+wait_body(synch_o&lt;void(string&amp;,string&amp;)&gt; w, </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;async_o&lt;void(string)&gt; f, </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;async_o&lt;void(string)&gt; s) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; w.arg1 = f.arg1;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; w.arg2 = s.arg1;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+In main(), we set up the test scenario.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">int
+main(int argc, char **argv) {<br>
+</span></div>
+First we create an executor with two threads in pool.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+executor exec(2);<br>
+</span></div>
+Next we create two MyService servers and tell them use the above
+executor's thread pool to dispatch request processing work.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+MyService s1(5, &amp;exec.execute);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; MyService s2(10,
+&amp;exec.execute);<br>
+</span></div>
+Here we create a Join2 object to wait for the results (callbacks) from
+service requests to both servers<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+Join2 j;<br>
+</span></div>
+Next we make requests to both servers and pass in request strings and
+callbacks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+s1.Service("Service 1", j.first);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; s2.Service("Service 2",
+j.second);<br>
+</span></div>
+Then main thread does some of its own work.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+for(int i=0; i&lt;7; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "Main " &lt;&lt; i &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; thread_sleep(1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+string x,y;</span><br style="font-weight: bold;">
+</div>
+Next main thread waits/joins on the responses from both servers.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp; j.Wait(x,y);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; log1.stream() &lt;&lt; "first
+result = " &lt;&lt; x &lt;&lt; ", second result = " &lt;&lt; y &lt;&lt;
+logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; exec.shutdown();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br>
+</div>
+<br>
+<div style="font-weight: bold;">
+<span style="font-family: monospace;"></span>&nbsp;</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/async_msg_state_tutorial.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/async_msg_state_tutorial.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Using Asynchronous Messages for State Tutorial</title>
+</head>
+<body>
+<h2>Join Using Asynchronous Messages For State Tutorial</h2>
+<h4 style="font-weight: normal;" class="dtH4">This tutorial shows how
+to use asynchronous message calls to carry state across method calls in
+Join.</h4>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+counter: public actor {<br>
+</span></div>
+We define an async method to represent the state of counter object:
+what value it contains.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(long)&gt; mystate;</span><br>
+<span style="font-weight: bold;">public:<br>
+</span></div>
+The public API of this class are two synch methods: <span
+ style="font-weight: bold;">inc() </span>will increase the counter
+value by 1 and <span style="font-weight: bold;">value()</span> will
+return the value of counter.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;void()&gt; inc;</span><br>
+<span style="font-weight: bold;">&nbsp; synch&lt;long()&gt; value;</span><br>
+</div>
+In contructor, we define two chords: one for <span
+ style="font-weight: bold;">inc() &amp; mystate()</span> and one for <span
+ style="font-weight: bold;">value() &amp; mystate()</span>. Then we
+initialize the counter state to 0.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+counter() : actor() {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(inc, mystate,
+&amp;counter::inc_bdy);</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(value,
+mystate, &amp;counter::val_bdy);</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; mystate(0);</span><br>
+<span style="font-weight: bold;">&nbsp; }</span><br>
+</div>
+Here is the chord body for <span style="font-weight: bold;">inc()
+&amp; mystate()</span>, meaning that calling inc() will increase the
+counter's value by 1. The current counter value is normally retrieved
+by <span style="font-weight: bold;">mi.arg1</span>. However since
+mystate() only carries a single argument, the method object <span
+ style="font-weight: bold;">mi </span>can be used directly
+as (converted to) the argument it contains.<span
+ style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void inc_bdy(synch_o&lt;void()&gt; inc, async_o&lt;void(long)&gt; mi) {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; mystate(mi+1);</span><br>
+<span style="font-weight: bold;">&nbsp; }</span><br>
+</div>
+The chord body of <span style="font-weight: bold;">value() &amp;
+mystate() </span>defines that the counter's value will be returned to
+caller of <span style="font-weight: bold;">value()</span>.<span
+ style="font-weight: bold;"> </span>And to allow more retrieval of
+counter value,<span style="font-weight: bold;"> mystate() </span>is
+called again with the same value.<span style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void val_bdy(synch_o&lt;long()&gt; val, async_o&lt;void(long)&gt; mi) {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; mystate(mi);</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; val.reply(mi);</span><br>
+<span style="font-weight: bold;">&nbsp; }</span><br>
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">};</span><span
+ style="font-weight: bold;"></span><br>
+</div>
+Class Demo is a multithreaded test driver which sets up two concurrent
+tasks: writer and reader. Writer keeps increasing the value of counter
+and Reader retrieving the counter.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Demo : public actor {</span><br>
+<span style="font-weight: bold;">public:</span><br>
+<span style="font-weight: bold;">&nbsp; counter c_;&nbsp; </span><br>
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; writer;</span><br>
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; reader;</span><br>
+<span style="font-weight: bold;">&nbsp; Demo(executor *e) :
+actor(e), c_() {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(writer,
+&amp;Demo::writer_bdy);</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(reader,
+&amp;Demo::reader_bdy);</span><br>
+<span style="font-weight: bold;">&nbsp; }</span><br>
+<span style="font-weight: bold;">&nbsp; void
+writer_bdy(async_o&lt;void()&gt; w) {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.msg("writer inc");</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+c_.inc();</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(1);</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br>
+<span style="font-weight: bold;">&nbsp; }</span><br>
+<span style="font-weight: bold;">&nbsp; void
+reader_bdy(async_o&lt;void()&gt; r) {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "reader reads [" &lt;&lt; c_.value() &lt;&lt;
+"]" &lt;&lt; logger::endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(2);</span><br>
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br>
+<span style="font-weight: bold;">&nbsp; } </span><br>
+<span style="font-weight: bold;">}; </span><br>
+<span style="font-weight: bold;"></span><br>
+<span style="font-weight: bold;">int main(int argc, char **argv) {</span><br>
+<span style="font-weight: bold;">&nbsp; executor exec(2);&nbsp; //spawn
+2 threads for executor thread pool</span><br>
+<span style="font-weight: bold;">&nbsp; Demo demo(&amp;exec.execute);</span><br>
+<span style="font-weight: bold;">&nbsp; demo.reader();</span><br>
+<span style="font-weight: bold;">&nbsp; demo.writer();</span><br>
+<span style="font-weight: bold;">&nbsp; exec.shutdown(); </span><br>
+<span style="font-weight: bold;">&nbsp; return 0;</span><br>
+<span style="font-weight: bold;">}</span><br>
+<span style="font-weight: bold;"></span></div>
+<br>
+<div style="font-weight: bold;"><span style="font-family: monospace;"></span><br>
+<span style="font-family: monospace;"></span>&nbsp;</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/buffer_tutorial.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/buffer_tutorial.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,294 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Buffer Tutorial</title>
+</head>
+<body>
+<h2>Join Buffer Tutorial</h2>
+This tutorial shows how to create and use a thread safe buffer in
+Join. Please refer to <a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_buffer.htm">the
+C&#969; buffer tutorial</a> for comparison.<br>
+<br>
+First we include Join's header file and open namespace.<br>
+<div style="margin-left: 40px; font-weight: bold;">#include
+&lt;boost/join/join.hpp&gt;<br>
+using namespace boost::join;<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Then
+a logger object is created to output log messages. In Windows/VC++
+environment, plain iostream objects are not thread friendly. The output
+messages from concurrent threads are garbled and mixed. Class logger
+provides a simple thread friendly logging tool for outputing messages
+from multiple threads in both Windows and Linux.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">logger log1("log");<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+comes the topic of this tutorial, defining a thread safe buffer in
+Join.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">template
+&lt;typename V&gt;<br>
+class buffer: public actor {<br>
+public:<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">First
+we declare
+a asynchronous method to allow putting messages into buffer and
+returning immediately.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+async&lt;void(V)&gt; put;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">and
+declare
+a sychronous method to allow waiting for message and getting it.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+synch&lt;V(void)&gt; get;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">The
+following chord() call and chord_body method define a chord with "put"
+and "get" methods and the chord will fire when both "put" and "get" are
+called. Inside chord body, the argument of "put" is returned to&nbsp;
+"get".</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; buffer() {<br>
+&nbsp;&nbsp;&nbsp; chord(get, put, &amp;buffer::chord_body);<br>
+&nbsp; }<br>
+&nbsp; V chord_body(synch_o&lt;V(void)&gt; get, async_o&lt;void(V)&gt;
+put) {<br>
+&nbsp;&nbsp;&nbsp; return put.arg1;<br>
+&nbsp; }<br>
+};<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Comparing
+with <a
+ href="http://research.microsoft.com/Comega/doc/comega_tutorial_buffer.htm">the
+buffer class in C&#969; tutorial</a>, the following differences are obvious:<br>
+</span>
+<ul>
+ <li><span style="font-weight: normal;">synchronous method -
+synch&lt;V(void)&gt;</span></li>
+</ul>
+<div style="margin-left: 40px;"><span style="font-weight: normal;">In
+C&#969;,
+there is no separate synch&lt;&gt; methods. When normal object methods
+are used in chords, they become synch&lt;&gt; methods. Since Join
+is implemented as a library instead of changing compiler, synch&lt;&gt;
+methods are presented as different from normal object methods. Objects'
+concurrent behaviour are solely defined by async&lt;&gt; /
+synch&lt;&gt; methods and chords.</span><br>
+<span style="font-weight: normal;"></span></div>
+<ul>
+ <li><span style="font-weight: normal;">chord definitions are
+different.</span></li>
+</ul>
+<ul>
+ <ul>
+ <li><span style="font-weight: normal;">In C</span><span
+ style="font-weight: normal;">&#969;, a chord definition such as "</span><span
+ style="font-weight: bold;">public string Get() &amp; Put(string s) {
+return s; }" </span><span style="font-weight: normal;">defines the
+following information in one piece:</span></li>
+ <ul>
+ <li><span style="font-weight: normal;">async&lt;&gt; /
+synch&lt;&gt; methods involved in this chord, joined by "&amp;"
+operator, such as "<span style="font-weight: bold;">Put</span>" and "<span
+ style="font-weight: bold;">Get</span>"<br>
+ </span></li>
+ <li><span style="font-weight: normal;">all arguments passed in
+thru involved async / synch methods, such as "</span><span
+ style="font-weight: bold;">string s". </span><span
+ style="font-weight: normal;">The names of arguments must be unique
+across the chord.</span></li>
+ <li><span style="font-weight: normal;">the body of code to be
+executed when all methods in header have been called</span></li>
+ </ul>
+ <li>
+ <p><span style="font-weight: normal;">In Join, a chord is
+defined as 2 separate pieces:</span></p>
+ </li>
+ <ul>
+ <li><span style="font-weight: normal;">chord() method call
+identifies all involved async&lt;&gt; / synch&lt;&gt; methods and
+associate them with a chord "body" method / function</span></li>
+ <li><span style="font-weight: normal;">The chord "body" method /
+function:<br>
+ </span></li>
+ <ul>
+ <li><span style="font-weight: normal;">The arguments of this
+"body" method are objects (async_o&lt;&gt; / synch_o&lt;&gt;)
+representing async / synch methods involved in this chord, each of
+which contains the arguments passed in thru corresponding async / synch
+method and which can be used to return result to synch method call. In
+class buffer, "put" method has only one argument, which can be accessed
+inside chord body by put.arg1. For methods with more than one
+arguments, their arguments can be accessed as async_o.arg1, </span><span
+ style="font-weight: normal;">async_o</span><span
+ style="font-weight: normal;">.arg2, </span><span
+ style="font-weight: normal;">async_o</span><span
+ style="font-weight: normal;">.arg3, etc.<br>
+ </span></li>
+ <li><span style="font-weight: normal;">The "body" method are
+code to be run when all methods in chord header are called.<br>
+ </span></li>
+ </ul>
+ </ul>
+ </ul>
+</ul>
+<ul>
+ <li><span style="font-weight: normal;">synchronous methods are
+handled differently</span></li>
+</ul>
+<div style="margin-left: 40px;">
+<ul>
+ <li><span style="font-weight: normal;">In C</span><span
+ style="font-weight: normal;"></span><span style="font-weight: normal;">&#969;,
+only the first method of chords (and at most one method) can be
+synchronous. So inside chord body, <span style="font-weight: bold;">return</span>
+statement returns the result to the caller of the synchronous method
+and release the blocked thread</span></li>
+ <li><span style="font-weight: normal;">In Join, there could be
+more than one synch methods in each chord. So in chord body, we have to
+use synch_o.reply(...) to return results to callers of synch methods
+and release their threads.</span></li>
+</ul>
+</div>
+<span style="font-weight: normal;">Next define a simple test function
+that puts simple strings into buffer and then get them from buffer and
+print out.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">void
+hello_world(buffer&lt;std::string&gt; &amp;b) {<br>
+&nbsp; b.put("hello");<br>
+&nbsp; b.put("world");<br>
+&nbsp; log1.msg(b.get()+" ");<br>
+&nbsp; log1.msg(b.get());<br>
+}<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">And
+define a convenience function to sleep calling thread for a few seconds.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">void
+thread_sleep(int sec) {<br>
+&nbsp;&nbsp;&nbsp; boost::xtime xt;<br>
+&nbsp;&nbsp;&nbsp; boost::xtime_get(&amp;xt, boost::TIME_UTC);<br>
+&nbsp;&nbsp;&nbsp; xt.sec += sec;<br>
+&nbsp;&nbsp;&nbsp; boost::thread::sleep(xt);<br>
+}<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Class
+Demo is a multithreaded test driver which use producer and consumer
+threads to test an instance of buffer. As further discussed in "</span><a
+ href="../concur_design.html">OO Concurrency Designs Based on
+Join</a>", <span style="font-weight: normal;">in Join
+based applications, there is no explicit thread creation and
+synchronization. Concurrent activities are spawned by chords with
+pure/only async&lt;&gt; methods whose chord body will be executed as a
+task in executor thread pool. Here we need 2 concurrent tasks: one for
+producing / putting messages into buffer and one for consuming /
+getting messages from buffer.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">class Demo : public
+actor {<br>
+public:<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">First
+declare an instance of buffer to be tested.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+buffer&lt;std::string&gt; &amp;buf_;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">declare
+async producer method to create the producer task</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+async&lt;void()&gt; producer;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">declare
+async consumer method to create the consumer task</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+async&lt;void()&gt; consumer;<br>
+&nbsp; Demo(buffer&lt;std::string&gt; &amp;b, executor *e) :
+actor(e), buf_(b) {<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">The
+following two chords have only async methods and so their chord body
+will be executed in different threads in executor's thread pool.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(producer, &amp;Demo::producer_cb);<br>
+&nbsp;&nbsp;&nbsp; chord(consumer, &amp;Demo::consumer_cb);<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">The
+body of chord with producer, putting message into buffer and then sleep
+1 second.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+producer_cb(async_o&lt;void()&gt; p) {<br>
+&nbsp;&nbsp;&nbsp; std::ostringstream ostr;<br>
+&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;5; i++) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostr &lt;&lt; i;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buf_.put(ostr.str());<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log1.stream() &lt;&lt; "producer sends
+[" &lt;&lt; i &lt;&lt; "]" &lt;&lt; logger::endl;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostr.str("");<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread_sleep(1);<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">The
+body of chord with consumer, get message from buffer, print it and
+sleep 2 seconds.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+consumer_cb(async_o&lt;void()&gt; c) {<br>
+&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;5; i++) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log1.stream() &lt;&lt; "consumer recvs
+[" &lt;&lt; buf_.get() &lt;&lt; "]" &lt;&lt;
+logger::endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thread_sleep(2);<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp; }<br>
+};<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Please
+notice that in above two "body" methods, their async methods pass in no
+arguments, so they are not used inside body, their existence only tell
+us that they have been called.<br>
+<br>
+In main(), we create an instance of buffer and invoke the simple test
+function (hello_world) to test buffer in main thread. Then an executor
+is created with 2 threads in pool. A demo object is created and
+associated with the executor, and its producer() and consumer() async
+methods are called, which will dispatch producing and consuming tasks
+into executor thread pool and test the buffer. Finally </span>exec.shutdown()<span
+ style="font-weight: normal;"> is called to wait for all threads of
+executor to exit.</span><br style="font-weight: normal;">
+</div>
+<div style="margin-left: 40px; font-weight: bold;">int main(int argc,
+char **argv) {<br>
+&nbsp; buffer&lt;std::string&gt; b;<br>
+&nbsp; hello_world(b);<br>
+<br>
+&nbsp; executor exec(2);&nbsp; //spawn 2 threads for executor thread
+pool<br>
+&nbsp; Demo demo(b, &amp;exec.execute);<br>
+&nbsp; demo.producer();<br>
+&nbsp; demo.consumer();<br>
+&nbsp; exec.shutdown();<br>
+&nbsp; return 0;<br>
+}<br>
+</div>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/dyn_chord_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/dyn_chord_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,208 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Dynamic Chord Tutorial</title>
+</head>
+<body>
+<h2>Array of Asynchronous Channel Tutorial</h2>
+This tutorial shows how to define an array of async channels (methods)
+and chords. The
+class join_many is a "merger" which merges the results from an array of
+input streams (async&lt;void(T)&gt;) and return as&nbsp; a whole.<br>
+<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename T, size_t N&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class join_many : public actor
+{</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+Here we declare an array of async&lt;&gt; methods, each of which takes
+an argument of type T as input.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+array&lt;async&lt;void(T)&gt;,
+N&gt; inputs;<br>
+</span></div>
+Next declare a synch&lt;&gt; method returning an array&lt;T&gt; which
+merges the arguments passed in thru all the above async&lt;&gt; methods.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;array&lt;T,N&gt;(void)&gt; output;<br>
+</span></div>
+In constructor, we initialize the parent class actor,
+and create a
+chord which binds "inputs" (the array of async methods) and "output"
+to the chord body method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+join_many(int n) :
+actor() {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(output,
+inputs, &amp;join_many::chord_body);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+In chord body method, we define what will be done when all the async
+methods of "inputs" and "output" have been called, which is simply that
+all arguments passed in thru async methods of "inputs" (in[i].arg1)
+will be packed into an array and returned to "output" as reault.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;</span><span
+ style="font-weight: bold;">array&lt;T,N&gt;</span><span
+ style="font-weight: bold;">
+chord_body(synch_o&lt;array&lt;T,N&gt;(void)&gt; out,
+array&lt;async_o&lt;void(T)&gt;, N&gt; in) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; array&lt;T,N&gt; vt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(size_t i=0;
+i&lt;N; i++)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+vt[i] = in[i].arg1;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return vt;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+<br>
+Class Demo is a multithreaded test driver to test join_many class. In
+the test, we have several concurrent "input" tasks periodically calling
+one of the async "inputs" of join_many, thus creating multiple input
+streams. The main thread will call the "output" synch method, waiting
+and retrieve the data merged from inputs.<br style="font-weight: bold;">
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Demo : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; enum {&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp; num_chan = 4,</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; num_test = 5</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; };</span><br>
+</div>
+First we define a instance of join_many class to be tested - merger.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp; join_many&lt;int, num_chan&gt;
+merger;<br>
+</span></div>
+Next define an async method whose only purpose is to spawn
+multiple concurrent input tasks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(int)&gt; inputer;<br>
+</span></div>
+The main thread will call the following wait() method, inside which the
+synch method "output" of merger is called, thus waiting and retrieving
+the result merged from all inputs.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void wait(void) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; array&lt;int,
+num_chan&gt;
+results;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;num_test; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; results
+= merger.output();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "output" &lt;&lt; i &lt;&lt; " = " &lt;&lt;
+logger::end;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+for(size_t j=0;j&lt;results.size();j++) </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+log1.stream()
+&lt;&lt; results[j] &lt;&lt; " " &lt;&lt; logger::end;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+In constructor, we create a chord for async
+inputer and bind it to its chord body method. Since the chord has
+only a async method, calling it will spawn a task in executor thread
+pool. Also we tell the parent actor class which executor to use
+to spawn new tasks. At end of constructor, we call async "inputer"
+method several times (thus spawning several concurrent tasks) passing
+in a integer telling its position in the list of input
+streams.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+Demo(executor *e, int n) :
+actor(e) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(inputer, &amp;Demo::chord_body);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;n; i++)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+inputer(i);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the body of async inputer. First we calculate the range of
+numbers this input task/stream will generate based on its position in
+the list of streams. Then the task will run a loop: calling the async
+"input" method of merger based on its position and pass in numbers,
+then sleeping for a while.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void
+chord_body(async_o&lt;void(int)&gt; p) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; int start =
+p.arg1*num_test;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; int end =
+start+num_test;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=start;
+i&lt;end; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "inputer[" &lt;&lt; p.arg1 &lt;&lt; "] sends ["
+&lt;&lt; i &lt;&lt; "] and wait..." &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+merger.inputs[p.arg1](i);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep((p.arg1+1)%3);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+<br>
+In main(), we set up the test.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">int
+main(int argc, char **argv) {<br>
+</span></div>
+We plan to run the test with 4 concurrent inputting tasks. So create an
+executor with 4 threads.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+executor exec(4);&nbsp; //spawn 4 threads for executor thread
+pool<br>
+</span></div>
+We construct a Demo instance and tell it to use the executor just
+created and run 4 concurrent input tasks. From here, 4 concurrent tasks
+will be spawned into executor and start pumping data into the merger
+object.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+Demo demo(&amp;exec.execute,4);</span><br>
+<span style="font-weight: bold;">&nbsp; log1.msg("main thread starts
+waiting...");<br>
+</span></div>
+Then calling demo.wait() to retrieve the data merged from 4 concurrent
+input streams and print them out.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+demo.wait();</span><br>
+<span style="font-weight: bold;">&nbsp; log1.msg("main thread finish
+waiting...");<br>
+</span></div>
+Finally waiting for all threads of executor thread pool to exit and
+test shut down.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+exec.shutdown();</span><br>
+<span style="font-weight: bold;">&nbsp; return 0;</span><br>
+<span style="font-weight: bold;">}</span><br>
+<span style="font-weight: bold;"></span></div>
+<span style="font-weight: bold;">
+<br style="font-weight: bold;">
+</span><br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/events_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/events_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,451 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Thread Safe Events Tutorial</title>
+</head>
+<body>
+<h2>Join Thread Safe Events Tutorial</h2>
+Event dispatching is a common design in today's interactive
+applications. Although it is based on the "Observer" design pattern, it
+has been called with different names, such as signals/slots,
+subject/observers or distributors. The common use scenario is that we
+use events to represent "interesting" system changes and application
+code can subscribe to events by registering callback functions /
+methods,
+which will be invoked when events happen. <br>
+<p>The design and implementation of event dispatching or Observer is
+more challenging and involving than how it first looks, just as Andrei
+Alexandrescu has discussed in his two articles
+[http://www.erdani.org/publications/cuj-2005-04.pdf]
+[http://www.erdani.org/publications/cuj-2005-06.pdf]. Most event
+dispatching is single-threaded and callbacks are executed
+by
+the event distributing thread. Multithreaded event dispatching involves
+the following design
+dimensions:</p>
+<ul>
+ <li>Allow subscribing / unsubscribing events concurrently from
+different threads; Events data structures must be thread safe.</li>
+ <li>During the loop of dispatching an event to the list of registered
+callbacks functions / methods, callback code could invoke the event
+interface again, change / delete event subscription or post a new
+event. This is difficult to handle with the "synchronous" semantics of
+normal method calls. It could lead to dead-lock (we need recursive
+mutex for event data structures). The event dispatching loop could be
+corrupted if some subscriptions are deleted during some callbacks,
+since the loop iterators may become
+invalid.
+Join's async methods provide an alternative to solve these issues.<br>
+ </li>
+ <li>When applications run on multi-core machines, we may want the
+callbacks to execute concurrently for better performance.</li>
+</ul>
+Join allow us to experiment with some interesting thread safe
+events designs. In the following we explain three thread safe events
+design with different focus.<br>
+<p><a href="../../examples/func_api/thread_safe_events/event1.cpp">The
+first event design</a> targets thread safety and allows callback
+functions to invoke any events API methods including adding / deleting
+subscriptions and posting new events. We achieve this by exporting all
+of events API as async methods.</p>
+The event class is templated by the type of event<span
+ style="font-weight: bold;"></span> data.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class event: public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+Here we define the callback function / method type.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+typedef boost::function&lt;void(V)&gt; subscriber;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; struct subscription_data {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; subscriber
+callback_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+subscription_data(subscriber cb) : callback_(cb) {}</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; };<br>
+</span></div>
+Here we define subscriptions which is returned when user code subscribe
+to a event by registering a callback. Subscription objects can be used
+to unsubscribe to events.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+typedef boost::shared_ptr&lt;subscription_data&gt; subscription;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">private:<br>
+</span></div>
+Here we define events' internal state: the list of subscriptions /
+callbacks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+std::vector&lt;subscription&gt; subs_;<br>
+</span></div>
+The thread safety and data integrity is maintained by async method
+"ready()" which is acting as lock.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; ready; <br>
+</span></div>
+Event subscriptions are submited thru the following async method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(subscription)&gt; subscribe_priv;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+Events are posted / submited thru async method "post()".<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(V)&gt; post;<br>
+</span></div>
+Application code will call subscribe() to attach a callback to event.
+Internally a subscription is created, submited to async method
+"subscribe_priv()" and returned to caller for later un-subscription.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+subscription subscribe(subscriber cb) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; subscription
+sub(new subscription_data(cb));</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; subscribe_priv(sub);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return sub;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Async method "unsubscribe()" is called to detach a subscription /&nbsp;
+callback from event.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(subscription)&gt; unsubscribe;<br>
+</span></div>
+operator() is define to allow posting event in similar way as function
+call: event_obj(data).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void operator()(V v) { post(v); }<br>
+</span></div>
+In constructor, we tell actor which executor to run the
+following three async chords bodies. The first chord is for posting and
+dispatching events; the second chord is for attaching callbacks to
+events and the third chord is for detaching callbacks. Please note that
+the third "unsubscribe" chord is defined with a lower priority so that
+all pending subscribing messages will always be processed before any
+pending un-subscribing messages. All three chords consist of pure async
+methods, so their chord bodies will be executed asynchronously as a
+task in executor's thread pool.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+event(executor *e) : actor(e) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(post, ready,
+&amp;event::post_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(subscribe_priv, ready, &amp;event::sub_cb);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; //set unsubscribe
+to lower priority so subscribe call will be processed first</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(unsubscribe,
+ready, &amp;event::unsub_cb,1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">private:<br>
+</span></div>
+In "posting" chord body, we broadcast the event to all callbacks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void post_cb(async_o&lt;void(V)&gt; post, async_o&lt;void()&gt; r) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(size_t i=0;
+i&lt;subs_.size(); i++)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+subs_[i]-&gt;callback_(post.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+In "subscribing" chord body, we add the new subscriber to event's list
+of subscribers.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void sub_cb(async_o&lt;void(subscription)&gt; sub,
+async_o&lt;void()&gt; r) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+subs_.push_back(sub.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+In "un-subscribing" chord body, we delete the subscription from list.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void unsub_cb(async_o&lt;void(subscription)&gt; unsub,
+async_o&lt;void()&gt; r) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; typename
+std::vector&lt;subscription&gt;::iterator iter;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; if((iter =
+std::find(subs_.begin(), subs_.end(), unsub.arg1)) != subs_.end()) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+subs_.erase(iter);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+<p><a href="../../examples/func_api/thread_safe_events/event2.cpp">The
+second event design</a> modifies the first design by letting all
+attached callbacks run concurrently as different tasks in executor's
+thread pool. The only changes are related to the API to post an event.
+We start these callback tasks as a chain: the first callback task is
+started by calling async method "post_priv(event_data,
+callback_task_index)" with the index = 0; the first callback task will
+call "post_priv()" with index=1 to spawn the second callback task and
+then run the first callback function; the second callback task will
+spawn the third callback task and then run its callback function, and
+so on.<br>
+</p>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class event: public actor {<br>
+&nbsp;&nbsp;&nbsp; ......<br style="font-weight: bold;">
+</span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">private:<br>
+&nbsp;&nbsp;&nbsp; ......<br>
+</span></div>
+Here is the async method to spawn task to run the callback function
+indexed by the <span style="font-weight: bold;">int </span>argument.<span
+ style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp; async&lt;void(V,int)&gt; post_priv;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+&nbsp;&nbsp;&nbsp; ......<br>
+</span></div>
+Here are the API to post an event, internally we call async method
+"post_priv()" to spawn the first callback task.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp; void operator()(V v) { post(v); }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void post(V v) { post_priv(v,
+0); }</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; event(executor *e) :
+actor(e) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(post_priv,
+ready, &amp;event::post_cb);<br>
+&nbsp;&nbsp;&nbsp; ......<br style="font-weight: bold;">
+</span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">private:<br>
+</span></div>
+Here is the "posting" chord body. <br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void post_cb(async_o&lt;void(V,int)&gt; post, async_o&lt;void()&gt; r) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; subscriber cb;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; bool callit = false;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+if((size_t)post.arg2 &lt; subs_.size()) {<br>
+</span></div>
+First we save the callback to be run in this task.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+callit = true;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cb =
+subs_[post.arg2]-&gt;callback_;<br>
+</span></div>
+Then we call async method "post_priv()" to spawn task to run the next
+callback.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+//start next callback in another task</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if(((size_t)post.arg2+1) &lt; subs_.size())</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+post_priv(post.arg1, (post.arg2+1));</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }<br>
+</span></div>
+Calling "ready()" allow other chords to run.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+ready();<br>
+</span></div>
+Finally invoke the callback of this task.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+if(callit)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+cb(post.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; ......<br style="font-weight: bold;">
+</span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">};</span><br>
+</div>
+<p><a href="../../examples/func_api/thread_safe_events/event3.cpp">The
+third event design</a> is different from the above two event designs.
+In some applications, we want all callbacks execute in the event
+dispatching thread (maybe the callbacks use some thread local data
+which is specified in the event dispatching thread); so event posting
+API must be synchronous. Also we may want a thread safe event design
+which doesn't involve asynchronous tasks (or executors) so we cannot
+use chords with pure async methods. However we still want the API for
+subscribing and unsubscribing to be asynchronous so that inside
+callbacks functions we can call them to change subscriptions. The third
+event design satisfy these requirements.<br>
+</p>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class event: public actor {<br>
+......<br style="font-weight: bold;">
+</span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">private:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; std::vector&lt;subscription&gt;
+subs_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; ready; <br>
+</span></div>
+Here we define a async method to mark the state that no more
+subscribing / un-subscribing messages are pending to be processed.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; subscription_empty; <br>
+</span></div>
+Here is a synch method which calls itself recursively to process all
+pending subscribing / un-subscribing messages.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;void()&gt; process_subscription;<br>
+</span></div>
+Here we define async method to process "subscribing" message.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(subscription)&gt; subscribe_priv;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+Here is the synch method to dispatch events and invoke all callbacks in
+the caller thread.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;void(V)&gt; post;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; subscription
+subscribe(subscriber cb) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; subscription
+sub(new subscription_data(cb));</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; subscribe_priv(sub);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return sub;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the async method to process "unsubscribing" message.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(subscription)&gt; unsubscribe;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void operator()(V v) { post(v);
+}<br>
+</span></div>
+In constructor, we create four chords to define event's concurrent
+behaviour.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+event() {<br>
+</span></div>
+The first chord is for posting a event synchronously (in caller's
+thread).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(post, ready, &amp;event::post_cb);<br>
+</span></div>
+The second chord is for processing "subscribing" messages.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(subscribe_priv, process_subscription, &amp;event::sub_cb);<br>
+</span></div>
+The third chord is for processing "unsubscribing" messages and it is
+specified with a lower priority so that all pending "subscribing"
+messages will be processed before any "unsubscribing" messages.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+//set unsubscribe to lower priority so subscribe call will be processed
+first</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(unsubscribe,
+process_subscription, &amp;event::unsub_cb,1);<br>
+</span></div>
+The fourth chord is for stopping processing when no more subscription
+messages pending and it is assigned the lowest priority so that it will
+run when no more subscription / un-subscription messages pending.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+//create a lowest priority chord for stopping process_subscription
+recursion when all subs are processed</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(subscription_empty, process_subscription,
+&amp;event::sub_empty_cb,2);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+subscription_empty();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">private:<br>
+</span></div>
+In "posting" chord, we first call synch method "process_subscription()"
+which will call itself recursively and process all pending subscribing
+/ unsubscribing messages. Then we dispatch the event to all attached
+callbacks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void post_cb(synch_o&lt;void(V)&gt; post, async_o&lt;void()&gt; r) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+process_subscription();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(size_t i=0;
+i&lt;subs_.size(); i++)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+subs_[i]-&gt;callback_(post.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+In "subscribing" chord, we first attach the pending subscriber and then
+call "process_subscription()" recursively.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void sub_cb(async_o&lt;void(subscription)&gt; sub,
+synch_o&lt;void()&gt; proc) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+subs_.push_back(sub.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+process_subscription();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+In "unsubscribing" chord, we first detach the subscriber and then call
+"process_subscription()" recursively.<br>
+<span style="font-weight: bold;"></span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void unsub_cb(async_o&lt;void(subscription)&gt; unsub,
+synch_o&lt;void()&gt; proc) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; typename
+std::vector&lt;subscription&gt;::iterator iter;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; if((iter =
+std::find(subs_.begin(), subs_.end(), unsub.arg1)) != subs_.end()) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+subs_.erase(iter);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+process_subscription();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Finally the simple "stopping" chord to stop the recursive call of
+"process_subscription()".<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void sub_empty_cb(async_o&lt;void()&gt; empty, synch_o&lt;void()&gt;
+proc) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+subscription_empty();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br>
+</div>
+<p><br>
+</p>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/exe_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/exe_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,266 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Executor Tutorial</title>
+</head>
+<body>
+<h2>Join Executor And Dynamic Chord Tutorial</h2>
+<div style="font-weight: bold;">
+<div style="font-weight: normal;">Executors are the "engine" of
+Join based applications - the body of all chords with only / pure
+async methods will run in the thread pool of executor. As the first
+application of Join, totally defined with async /
+synch methods and chords, class executor is also a good sample of using
+dynamically created chords.<br>
+<br>
+</div>
+<span style="font-weight: normal;">The general design of Executor is a
+pool of worker threads which serve / process "tasks" submited by
+clients thru one or many task queues.<br>
+</span>
+<div style="margin-left: 40px;">template &lt;size_t sz=32&gt;<br>
+</div>
+<div style="margin-left: 40px;">class Executor : public actor&lt;sz&gt;
+{<br>
+public:<br>
+&nbsp; typedef actor&lt;sz&gt; actor_type;<br>
+</div>
+<span style="font-weight: normal;">Here we define the type of tasks
+which can run in executor's thread pool. Its full type is <span
+ style="font-weight: bold;">boost::function&lt;void()&gt;</span>.</span><br>
+<div style="margin-left: 40px;">&nbsp; typedef actor_type::callable
+task;<br>
+</div>
+<span style="font-weight: normal;">Next we define a data structure to
+save the dynamically created task queues.</span><br>
+<div style="margin-left: 40px;">&nbsp; typedef std::map&lt;size_t,
+boost::shared_ptr&lt;async&lt;void(task)&gt; &gt; &gt;&nbsp;
+que_map_type;<br>
+<br>
+</div>
+<span style="font-weight: normal;">All task queues are implemented as
+async methods which takes task as argument, so clients can submit tasks
+by calling these async methods. Each executor has a default task queue
+- <span style="font-weight: bold;">execute() </span>which is a
+statically defined async method.</span><br>
+<div style="margin-left: 40px;">&nbsp; async&lt;void(task)&gt; execute;<br>
+</div>
+<span style="font-weight: normal;">Next we define a synch method </span>shutdown()
+<span style="font-weight: normal;">which main thread can call to notify
+and wait for all the threads in thread pool to exit.</span><br>
+<div style="margin-left: 40px;">&nbsp; synch&lt;void(void)&gt; shutdown;<br>
+<br>
+</div>
+<span style="font-weight: normal;">As described in </span><a
+ style="font-weight: normal;" href="prime_sieve_tut.html">Multi Task
+Queue and Round
+Robin Scheduling Tutorial</a><span style="font-weight: normal;">,
+executors support queue fairness by providing multiple dyanmically
+created task queues. All task queues are indexed by integers.</span><br>
+<div style="margin-left: 40px;">&nbsp; async&lt;void(task)&gt;
+*task_queue(size_t i=0) {<br>
+</div>
+<span style="font-weight: normal;">Since the executor is configured
+with size "sz", it means executor can only support up to "sz" async and
+synch methods. For internal implementation, Executor uses four async /
+synch methods, so it can provide at most (sz-5) dynamic task queues.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; if (i&gt;(sz-5)) i =
+i%(sz-5); <br>
+</div>
+<span style="font-weight: normal;">For index 0, we return the default
+task queue.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; if(i==0) return
+&amp;execute;<br>
+</div>
+<span style="font-weight: normal;">If clients try to retrieve task
+queues other than default, we'll have multiple task queues, so first
+make sure that the executor's actor is using scheduling policy : </span>fire_by_round_robin.
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp;
+if(this-&gt;dispatcher_ != actor_type::fire_by_round_robin) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;log.msg(" throw
+executor_missing_rr_exception ......");<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw executor_missing_rr_exception();<br>
+&nbsp;&nbsp;&nbsp; }<br>
+</div>
+<span style="font-weight: normal;">Then we search thru the map of
+existing queues. If the required one exist, simply return it.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; typename
+que_map_type::iterator iter;<br>
+&nbsp;&nbsp;&nbsp; if ((iter=que_map_.find(i)) != que_map_.end())<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return iter-&gt;second.get();<br>
+&nbsp;&nbsp;&nbsp; else {<br>
+</div>
+<span style="font-weight: normal;">Otherwise, we create a new task
+queue (async method) and create a chord to dispatch tasks submited thru
+it.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+this-&gt;log.msg(" creating task_queue ......");<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+boost::shared_ptr&lt;async&lt;void(task)&gt; &gt; nq(new
+async&lt;void(task)&gt;());<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chord(*nq, run, &amp;Executor::exec_cb);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; que_map_[i] = nq;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return nq.get();&nbsp;&nbsp;&nbsp;
+&nbsp; <br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp; }<br>
+</div>
+<span style="font-weight: normal;">In constructor, we define the number
+of threads to spawn in pool and the scheduling policy (for executor
+with multiple task queues we need use </span>fire_by_round_robin<span
+ style="font-weight: normal;">). We first initialize the parent actor
+class with the defined scheduling policy and then define four chords
+for executor's concurrent behaviour. At end of constructor, we
+transition executor to "started" state.</span><br>
+<div style="margin-left: 40px;">&nbsp; Executor(int num, const char
+*name = NULL, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; typename actor_type::dispatch_policy
+disp = actor_type::fire_as_soon_as_possible) : <br>
+&nbsp;&nbsp;&nbsp; actor_type(NULL, name, disp) {<br>
+</div>
+<span style="font-weight: normal;">Here is the chord defining the
+executor's behaviour when&nbsp; some of its threads are ready to run
+(sync method </span>run() <span style="font-weight: normal;">called
+by some threads) and clients submit tasks (async method </span>execute()
+<span style="font-weight: normal;">called) - ie. the submitted task
+will be executed in ready threads.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; chord(execute, run,
+&amp;Executor::exec_cb);<br>
+</div>
+<span style="font-weight: normal;">Here is the chord defining the
+executor's behaviour when</span> <span style="font-weight: normal;">
+some of its threads are ready to run (sync method </span>run() <span
+ style="font-weight: normal;">called by some threads) and there is
+request to stop the executor (async method <span
+ style="font-weight: bold;">stopped()</span> called). Please note that
+to make sure the executor to finish all tasks submitted, we set all the
+following chords related to "shutdown / stop" to a lower priority 1
+(default priority 0 is highest, the bigger the number, the lower the
+priority). Low priority chords will fire only after all higher priority
+chords have fired,<br>
+</span>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; chord(stopped, run,
+&amp;Executor::stop_cb, 1);<br>
+</div>
+<span style="font-weight: normal;">Here is the chord for shutting down
+executor; sync method <span style="font-weight: bold;">shutdown()</span>
+is called when executor is in "started" state (async method <span
+ style="font-weight: bold;">started()</span> called).</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; chord(shutdown,
+started, &amp;Executor::shutdown_cb,
+1);<br>
+</div>
+<span style="font-weight: normal;">Here is the chord for the case when <span
+ style="font-weight: bold;">shutdown()</span> is called again while
+executor already shut down.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; chord(shutdown,
+stopped, &amp;Executor::stopped_cb,
+1);<br>
+</div>
+<span style="font-weight: normal;">Next we spawn all the threads in
+executor's thread pool. All the threads main function is <span
+ style="font-weight: bold;">main_loop()</span> defined next,</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;num; i++)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+threads_.create_thread(boost::bind(&amp;Executor::main_loop, this));<br>
+</div>
+<span style="font-weight: normal;">At end of constructor, we transition
+executor to "started" state.</span><br>
+<div style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; started(); //init
+state<br>
+&nbsp; }<br>
+&nbsp; ~Executor() {<br>
+&nbsp;&nbsp;&nbsp; shutdown();<br>
+&nbsp; }<br>
+<br>
+private:<br>
+</div>
+<span style="font-weight: normal;">Threads in pool will use synch
+method <span style="font-weight: bold;">run()</span> to retrieve and
+execute tasks submited by clients.</span><br>
+<div style="margin-left: 40px;">&nbsp; synch&lt;bool(void)&gt; run;<br>
+</div>
+<span style="font-weight: normal;">Next we declare two async methods to
+represent executor's state: </span>started()<span
+ style="font-weight: normal;"> and </span>stopped().<br>
+<div style="margin-left: 40px;">&nbsp; async&lt;void(void)&gt; started;<br>
+&nbsp; async&lt;void(void)&gt; stopped;<br>
+</div>
+<span style="font-weight: normal;">Next are executor's private state:
+the thread group containing all worker threads in pool and a queueu map
+to maintain all active task queues.</span><br>
+<div style="margin-left: 40px;">&nbsp; boost::thread_group threads_;<br>
+&nbsp; que_map_type que_map_;<br>
+</div>
+<span style="font-weight: normal;">main_loop is the main function of
+all threads containing a loop calling<span style="font-weight: bold;">
+run()</span>.</span><br>
+<div style="margin-left: 40px;">&nbsp; void main_loop(void) {<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("a thread starts...");<br>
+&nbsp;&nbsp;&nbsp; while(run()) ;<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("a thread exits...");<br>
+&nbsp; }<br>
+</div>
+<span style="font-weight: normal;">Here is the chord body for executing
+tasks (when some threads are ready and called <span
+ style="font-weight: bold;">run()</span>). We execute the submitted
+task, catch exception and return true to <span
+ style="font-weight: bold;">run()</span> so that calling worker thread
+will continue working by calling <span style="font-weight: bold;">run()</span>
+again.</span><br>
+<div style="margin-left: 40px;">&nbsp; void
+exec_cb(async_o&lt;void(task)&gt; exec,
+synch_o&lt;bool(void)&gt; run) {<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("start one task...");<br>
+&nbsp;&nbsp;&nbsp; try {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (exec.arg1)();<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; catch (join_exception &amp;je) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;log.msg(je.what());<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; catch (...) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;log.msg("UNKNOWN exceptions
+happen inside a executor thread, ignore.");<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("finish one task...");<br>
+&nbsp;&nbsp;&nbsp; run.reply(true); //worker thread continue<br>
+&nbsp; }<br>
+</div>
+<span style="font-weight: normal;">Here is the chord body for stopping
+executor's threads when <span style="font-weight: bold;">shutdown()</span>
+is called. By returning false to <span style="font-weight: bold;">run()</span>
+we are telling the thread to exit.</span><br>
+<div style="margin-left: 40px;">&nbsp; void
+stop_cb(async_o&lt;void(void)&gt; stopd,
+synch_o&lt;bool(void)&gt; run) {<br>
+&nbsp;&nbsp;&nbsp; stopped(); <br>
+&nbsp;&nbsp;&nbsp; run.reply(false); //worker thread exit<br>
+&nbsp; }<br>
+</div>
+<span style="font-weight: normal;">Here is the chord body for shutting
+down. We first call <span style="font-weight: bold;">stopped()</span>
+to tell worker threads to exit and then waiting for them to exit bu
+join_all().</span><br>
+<div style="margin-left: 40px;">&nbsp; void
+shutdown_cb(synch_o&lt;void(void)&gt; shdn,
+async_o&lt;void(void)&gt; started) {<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("shutdown...");<br>
+&nbsp;&nbsp;&nbsp; stopped();<br>
+&nbsp;&nbsp;&nbsp; //waiting for the threads to exit<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("wait...");<br>
+&nbsp;&nbsp;&nbsp; threads_.join_all();&nbsp;&nbsp;&nbsp; <br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("all threads exit, done...");<br>
+&nbsp; }<br>
+&nbsp; void stopped_cb(synch_o&lt;void(void)&gt; shdn,
+async_o&lt;void(void)&gt; stopd) {<br>
+&nbsp;&nbsp;&nbsp; this-&gt;log.msg("stopped...");<br>
+&nbsp;&nbsp;&nbsp; stopped();<br>
+&nbsp; }<br>
+};<br>
+</div>
+<br>
+<br>
+</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/future_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/future_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,248 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Futures Tutorial</title>
+</head>
+<body>
+<h2>Join Futures Tutorial</h2>
+Future is a abstraction
+representing the value of a concurrent computation. Creating a future
+initiates a concurrent computation in another thread (in the executor
+thread pool) and then initiating thread is
+free to perform other tasks. When initiator needs the value of
+computation, it can call the future's get() method to synchronize with
+the computing thread and wait until/unless the computation is done.
+This sample shows a simple implementation of future using Join;
+adapted from sample in [3]. <br>
+<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename T&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class future : public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+First we define the type&nbsp; of computation to be carried out
+concurrently, a callable object (functions, methods, etc) taking no
+argument and returning value of type T.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+typedef boost::function&lt;T()&gt; Computation;<br>
+</span></div>
+And a synchronous "get" method which the initiating thread will call to
+wait and retrieve the result of concurrent computation.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;T()&gt; get;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">private:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Computation comp;<br>
+</span></div>
+We use two asynchronous methods to represent the state of concurrent
+computation: <span style="font-weight: bold;">compute</span> -
+computation is going on; <span style="font-weight: bold;">done</span>
+- computation is finished and result is ready to retrieve.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; compute;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; done;<br>
+</span></div>
+Next we define two member variables to save the result of concurrent
+computation: either the successfully computed result (value_) or an
+exception thrown during the computation (except_).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+std::auto_ptr&lt;T&gt; value_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+std::auto_ptr&lt;std::runtime_error&gt; except_;</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+In constructor, we tell the parent actor class which executor
+to dispatch tasks and create two chords.
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+future(Computation c, executor *e) : actor(e), comp(c) {<br>
+</span></div>
+The first chord (compute chord) is for async method <span
+ style="font-weight: bold;">compute</span>, which is<span
+ style="font-weight: bold;"> </span>for spawning a concurrent task in
+executor to do the real computation.
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(compute, &amp;future::compute_body);<br>
+</span></div>
+The second chord (get chord) is for the "joining" of async method <span
+ style="font-weight: bold;">done</span> and synch method <span
+ style="font-weight: bold;">get</span>; for the case when the
+computation is done, allowing initiator to retrieve the result.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(get, done, &amp;future::get_body);<br>
+</span></div>
+At end of constructor, we call async method <span
+ style="font-weight: bold;">compute()</span> to start the concurrent
+computation.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+compute();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the definition of compute chord body which will run in a thread
+from executor thread pool.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void compute_body(async_o&lt;void()&gt; c) {<br>
+</span></div>
+First we do the required computation, save the result in <span
+ style="font-weight: bold;">value_</span> or if exception is thrown,
+save exception in <span style="font-weight: bold;">except_</span>.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+try {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+value_.reset(new T(comp()));</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; catch (...) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //need
+more delicate way to catch
+application specific exceptions</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //such
+as Peter Dimov N2179 proposal</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //here
+for demo, simply change all
+exceptions to runtime_error</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+except_.reset(new
+std::runtime_error("exceptions happens inside future computation"));</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }<br>
+</span></div>
+And call async method <span style="font-weight: bold;">done() </span>to
+transition the state of this future object to "ready to be retrieved".<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+done();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the definition of get chord body, will run in the thread which
+calls the synch get method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void get_body(synch_o&lt;T()&gt; g, async_o&lt;void()&gt; d) {<br>
+</span></div>
+First we send another done() message so that other threads can also
+call get() to retrieve the result of computation.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+done(); //reissue done to allow multiple gets<br>
+</span></div>
+Next based on if the computation is done successfully or not, returning
+the result value to caller of <span style="font-weight: bold;">get() </span>or
+rethrow exception caught during computation in the thread calling<span
+ style="font-weight: bold;"> get().</span><br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+if(except_.get())</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw
+*except_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; g.reply(*value_);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+</div>
+Next we define two simple "computations" to be carried out
+concurrently, each will take some time and return a string result.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">std::string
+task1() {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; for(int i=0; i&lt;8; i++) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "task1 is running " &lt;&lt;
+i &lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; thread_sleep(1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return std::string("task1 is
+done");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">std::string task2() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; for(int i=0; i&lt;8; i++) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "task2 is running " &lt;&lt;
+i &lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; thread_sleep(1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; if(i==4) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw
+std::runtime_error("future
+exception test");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return std::string("task2 is
+done");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+</div>
+<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">int
+main(int argc, char **argv) {<br>
+</span></div>
+In main(), we first create an executor with two threads.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+executor exec(2);&nbsp; //add 2 threads in executor thread pool<br>
+</span></div>
+Then we create two future objects and pass in the computation to be
+done and which executor to use to spawn concurrent tasks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+future&lt;std::string&gt; fu1(task1, &amp;exec.execute);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; future&lt;std::string&gt;
+fu2(task2, &amp;exec.execute);<br>
+</span></div>
+First we let main thread wait and sleep for a while.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+for(int i=0; i&lt;4; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "Main " &lt;&lt; i &lt;&lt;
+logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; thread_sleep(1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; log1.msg("Main starts waiting
+on future");<br>
+</span></div>
+Here, the main thread is waiting to retrieve the result of concurrent
+computation. The first future object will return the result and the
+second future object will thrown an exception.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+try {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "future1 returns : " &lt;&lt;
+fu1.get() &lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; catch (...) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.msg("future1
+got exception");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; try {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "future2 returns : " &lt;&lt;
+fu2.get() &lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; catch (...) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.msg("future2
+got exception");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Finally waiting for executor threads to exit and test shutdown.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+exec.shutdown();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br>
+</div>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/guard_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/guard_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Guard Tutorial</title>
+</head>
+<body>
+<h2>Join Guard Tutorial</h2>
+In its basic form, chords will fire as
+long as there are messages available at involved
+async / synch methods. Chord or synchronization is not concerned with
+the messages' content or how many messages are available. Passing in
+guard functors to chord() give us extra control over the enabling of
+chords based on the message content. The guard function is passed the
+messages / arguments of all the involved async / synch methods; what
+guard function returns (true or false) will further decide if the chord
+will
+fire or not. <br>
+In this simple sample (guard.cpp), request messages contain two parts:
+a integer sequence number and a string body. There are two chords to
+process requests, distinguished by their guards: one is to process
+even-numbered messages and the other is to process odd-numbers messages.<br>
+<br>
+Here we are defining a multithreaded (thread pool based) server which
+serves requests consisting of a sequence number (int) and
+content(string). Normal chord() method will check against overlap of
+the set of async / synch methods with the sets of existing chords and
+throw hidden_chord_exception when overlap is found. When guard functors
+are used, such checking is disabled.<br>
+<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+server: public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+First we declare the async method to allow clients to submit requests
+(containing a sequence number and string content).<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(int, string)&gt; request; <br>
+</span></div>
+In constructor, we initialize the parent actor with the
+executor<span style="font-weight: bold;">.
+</span>And create two chords: one for processing even numbered requests
+and one for processing odd numbered requests.<span
+ style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+server(executor *e) : actor(e) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(request,
+&amp;server::req_proc_odd, 0,
+&amp;server::is_odd);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(request,
+&amp;server::req_proc_even, 0,
+&amp;server::is_even);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here are two chord body methods.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void req_proc_odd(async_o&lt;void(int, string)&gt; req) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "process a odd request:
+seq#[" &lt;&lt; req.arg1 </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp; &lt;&lt; "], req ["
+&lt;&lt; req.arg2 &lt;&lt; "]" &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+req_proc_even(async_o&lt;void(int, string)&gt; req) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "------------- process a even
+request: seq#[" &lt;&lt; req.arg1 </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp; &lt;&lt; "], req ["
+&lt;&lt; req.arg2 &lt;&lt; "]" &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here are two guard methods used in chord definitions.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+bool is_odd(async_o&lt;void(int, string)&gt; req) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return req.arg1 % 2
+!= 0;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; bool
+is_even(async_o&lt;void(int, string)&gt; req) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; return (req.arg1 %
+2) == 0;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br>
+</div>
+In main(), we create an executor with two threads in pool and
+instantiate a server object with the executor. Then we run a loop and
+submit one hundred requests with both even and odd sequence numbers.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">int
+main(int argc, char **argv) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; executor exec(2);&nbsp; //spawn
+2 threads for executor thread
+pool</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; server srv(&amp;exec.execute);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; for(int i=0; i&lt;100; i++) </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; srv.request(i,
+(i%2)?"odd request":"even request");</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; exec.shutdown();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+</div>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/one_place_buffer_tutorial.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/one_place_buffer_tutorial.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,175 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join One Place Buffer Tutorial</title>
+</head>
+<body>
+<h2>Join One Place Buffer Tutorial</h2>
+<h4 style="font-weight: normal;" class="dtH4">The previous tutorial
+showed how to define a buffer of unbounded size: any number of calls to
+<code class="ce">put()</code> could be queued up before matching a <code
+ class="ce">get()</code>.&nbsp;
+This tutorial defines a variant in which only a single data value may
+held in the buffer at any one time.</h4>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class one_place_buffer: public
+actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">private: </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span></div>
+First, we use two private asynchronous methods to represent the states
+of buffer: empty and contains exactly one item.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; empty;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(V)&gt; contains;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+The public API of this class are two synchronous methods; so <span
+ style="font-weight: bold;">put() </span>will block when buffer
+already contains one item and <span style="font-weight: bold;">get()</span>
+will block when buffer is empty.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+synch&lt;void(V)&gt; put;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;V()&gt; get;</span><br
+ style="font-weight: bold;">
+</div>
+In contructor, we define two chords and call <span
+ style="font-weight: bold;">empty()</span> async method to "transition"
+buffer into empty state.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp; one_place_buffer() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(put, empty,
+&amp;one_place_buffer::put_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(get,
+contains, &amp;one_place_buffer::get_cb);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; empty();&nbsp;
+//init state</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the chord body for <span style="font-weight: bold;">put()</span>
+and <span style="font-weight: bold;">empty()</span>. It means that
+when the buffer is empty (<span style="font-weight: bold;">empty()</span>
+async method called), calling <span style="font-weight: bold;">put()</span>
+will store the argument of <span style="font-weight: bold;">put()</span>
+inside buffer by calling <span style="font-weight: bold;">contains()</span>
+async method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void put_cb(synch_o&lt;void(V)&gt; put, async_o&lt;void()&gt; empty) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; contains(put.arg1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+</div>
+The chord body of <span style="font-weight: bold;">get()</span> and <span
+ style="font-weight: bold;">contains()</span> says that when the buffer
+is not empty (<span style="font-weight: bold;">contains()</span> async
+method called), calling <span style="font-weight: bold;">get()</span>
+will return the value contained in buffer and transition buffer to
+empty state.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void get_cb(synch_o&lt;V()&gt; get, async_o&lt;void(V)&gt; contains) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; empty();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+get.reply(contains.arg1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">};</span><br
+ style="font-weight: bold;">
+</div>
+Similar to the previous buffer tutorial, class Demo is a multithreaded
+test driver. It sets up two concurrent tasks : producer and consumer
+which communicate thru an instnace of one_place_buffer. The main()
+function creates a executor and run the test. Please note that the log
+printouts from this test are in order because the one_place_buffer will
+hold faster producer so that slower consumer task can catch up.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Demo : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+one_place_buffer&lt;std::string&gt; &amp;buf_;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; producer;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; consumer;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+Demo(one_place_buffer&lt;std::string&gt; &amp;b, executor *e) :
+actor(e), buf_(b) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(producer,
+&amp;Demo::producer_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(consumer,
+&amp;Demo::consumer_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+producer_cb(async_o&lt;void()&gt; p) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; std::ostringstream
+ostr;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostr
+&lt;&lt; i;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+buf_.put(ostr.str());</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "producer sends [" &lt;&lt; i &lt;&lt; "]"
+&lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ostr.str("");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+consumer_cb(async_o&lt;void()&gt; c) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "consumer recvs [" &lt;&lt; buf_.get() &lt;&lt;
+"]" &lt;&lt; logger::endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(2);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">int main(int argc, char **argv) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+one_place_buffer&lt;std::string&gt; b;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; executor exec(2);&nbsp; //spawn
+2 threads for executor thread pool</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Demo demo(b, &amp;exec.execute);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; demo.producer();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; demo.consumer();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;</span><br>
+</div>
+<br>
+<div style="font-weight: bold;"><span style="font-family: monospace;"></span><br>
+<span style="font-family: monospace;"></span>&nbsp;</div>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/override_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/override_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,260 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Chord Override Tutorial</title>
+</head>
+<body>
+<h2>Join Chord Override Tutorial</h2>
+In Join, the chords defined can be overriden
+with new bodies either thru "virtual" chord body methods or by calling
+chord_override(). Join supports two kinds of overriding:<br>
+<ul>
+ <li>static overriding</li>
+</ul>
+<div style="margin-left: 40px;">When we define async/synch methods and
+their chords, the chord "body" method can be defined as C++ virtual
+method. Then
+in child classes, this chord body can be overriden just as any other
+virtual methods. When an instance of this child class is used anywhere
+thru pointers or references to parent class (by calling its async/synch
+methods), the proper child class chord body method definition will be
+invoked.<br>
+</div>
+<ul>
+ <li>dynamic overriding</li>
+</ul>
+<div style="margin-left: 40px;">This refers to the capability that
+chord definitions can be changed by overriding or replacing chord body
+methods during runtime when code runs. For this purpose,
+chord_override() is called with the set of async / synch methods (same
+as the chord to be overriden) and the new chord body method. The
+identified chord will replace its chord body with the new method.<br>
+</div>
+<br>
+The following is an example demontrating both kinds of overriding.<br>
+<br>
+For demonstrating "static overriding", we use the thread-safe buffer
+class of the first tutorial. The only change here is to define the
+chord body method as "virtual"<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class buffer: public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(V)&gt; put;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; synch&lt;V()&gt; get;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; buffer() {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(put, get,
+&amp;buffer::chord_body);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; //to be overriden, the chord
+body method has to be "virtual"</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; virtual void
+chord_body(async_o&lt;void(V)&gt; put, synch_o&lt;V()&gt; get) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; get.reply(put.arg1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br style="font-weight: bold;">
+</div>
+To extend the original buffer's capability with "logging", we define a
+child class of class buffer and override the chord body method. With
+the chord body overriden, all its method headers (<span
+ style="font-weight: bold;">put()</span> and <span
+ style="font-weight: bold;">get()</span>) are "overriden" in the sense
+of that calling <span style="font-weight: bold;">put()</span> and <span
+ style="font-weight: bold;">get()</span> will exhibit the new behaviour.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">template
+&lt;typename V&gt;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">class logged_buffer: public
+buffer&lt;V&gt; {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; //override chord body method</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+chord_body(async_o&lt;void(V)&gt; put, synch_o&lt;V()&gt; get) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "logged_buffer transfer: " &lt;&lt; put.arg1 &lt;&lt;
+logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; get.reply(put.arg1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br>
+</div>
+For demonstrating dynamic overriding, we define the following
+transformer class which will transform the passed in strings by
+prefixing some simple text and forward the transformed strings to a
+buffer. At the end of each call to transform(), chord_override() is
+called to replace the chord with a new body. So consecutive calls to
+transform() will prefix different text to the incoming strings.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">class transformer : public actor {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; buffer&lt;std::string&gt;
+&amp;buf_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void(std::string)&gt;
+transform;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; ready;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;
+transformer(buffer&lt;std::string&gt; &amp;b, executor *e) :
+actor(e), buf_(b) {</span><br style="font-weight: bold;">
+</div>
+First we create the chord with a default chord body method.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(transform, ready, &amp;transformer::do_1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+do_1(async_o&lt;void(std::string)&gt; arg, async_o&lt;void()&gt; r) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; buf_.put("do_1: " +
+arg.arg1);<br>
+</span></div>
+Here we replace the chord with a new body by calling chord_override().<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord_override(transform, ready, &amp;transformer::do_2);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+do_2(async_o&lt;void(std::string)&gt; arg, async_o&lt;void()&gt; r) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; buf_.put("do_2: " +
+arg.arg1);</span><br style="font-weight: bold;">
+</div>
+Here we replace the chord with a new body by calling chord_override().<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord_override(transform, ready, &amp;transformer::do_1);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br>
+</div>
+Class Demo sets up a test scenario for testing the above defined
+transformer class and logged_buffer class. An instance of transformer
+will be created and hooked to a instance of logged_buffer. Two
+concurrent tasks will be spawned. A producer task will continuously
+sending strings to the instance of transformer; the instance of
+transformer will transform the strings and forward them to the instance
+of logged_buffer. A consumer task will keep waiting and receiving from
+the logged_buffer.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+Demo : public actor {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+First we define the instances to classes to be tested.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+logged_buffer&lt;std::string&gt; buf_;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; transformer trans_;<br>
+</span></div>
+Second we define two async methods which will spawn "producer" and
+"consumer" concurrent tasks.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; producer;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; consumer;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Demo(executor *e) :
+actor(e), trans_(buf_, e) {<br>
+</span></div>
+Since the following two chords contain only async methods, their bodies
+will execute in thread-pool concurrently.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(producer, &amp;Demo::producer_cb);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; chord(consumer,
+&amp;Demo::consumer_cb);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+producer_cb(async_o&lt;void()&gt; p) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; std::ostringstream
+ostr;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ostr
+&lt;&lt; i;<br>
+</span></div>
+Here we input strings to transform.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+trans_.transform(ostr.str());</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "producer sends [" &lt;&lt; i &lt;&lt; "]"
+&lt;&lt; logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ostr.str("");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(1);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; void
+consumer_cb(async_o&lt;void()&gt; c) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; for(int i=0;
+i&lt;5; i++) {<br>
+</span></div>
+Here we retrieve strings from logged_buffer.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "consumer recvs [" &lt;&lt; buf_.get() &lt;&lt;
+"]" &lt;&lt; logger::endl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(2);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">int main(int argc, char **argv) {</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; executor exec(3);&nbsp; </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; Demo demo(&amp;exec.execute);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; demo.producer();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; demo.consumer();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; exec.shutdown();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}<br>
+</span></div>
+<p>The log messages will show the following facts:</p>
+<ul>
+ <li>the overriding definition of chord body in class logged_buffer is
+invoked, althoug in class transformer, <span style="font-weight: bold;">put()
+ </span>is called thru reference to class buffer.</li>
+ <li>different text are prefixed to strings during consecutive calls
+to transformer.<span style="font-weight: bold;">transform()</span>.</li>
+</ul>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/parallel_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/parallel_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,506 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Data Parallel Programming Tutorial</title>
+</head>
+<body>
+<h2>Join Data Parallel Programming Tutorial</h2>
+Computers are having more and more cores (CPUs). How to harness these
+great computing power and make applications scalable for more CPUs is a
+challenging task. Many vendors are providing libraries to support
+multi-core
+programming, such as Intel's Threading Building Block. Data Parallel
+paradigm is particularly suitable for parallelizing computationally
+intensive work, allowing multiple tasks concurrently working on
+different parts of data. Data parallel programming scales well to
+larger number of processors by dividing the data collection into
+smaller pieces. Program performance increases as you add more
+processors.<br>
+<br>
+Join's toolset (async / synch methods and chords) provides a good
+foundation for data parallel programming. In this tutoral we discuss
+how to implement parallel loops and parallel map-reduce algorithm in
+Join. Here is <a href="../../examples/func_api/parallel.cpp">the
+tutorial's full source code</a>.<br>
+<br>
+Since the basic model is to initiate multiple tasks working
+concurrently on different parts of data set, we define the following
+interface for the main (initiating) task to wait for and synchronize
+with worker tasks.<br>
+<div style="margin-left: 40px; font-weight: bold;">template
+&lt;typename V&gt;<br>
+class future: public actor {<br>
+public:<br>
+</div>
+<div style="font-weight: bold; text-align: left;"><span
+ style="font-weight: normal;">Here we define synchronous methods (<span
+ style="font-weight: bold;">get()</span>, <span
+ style="font-weight: bold;">wait()</span>) to allow initiating task to
+wait for parallel worker tasks to finish; and return the final result
+if available. Please note that the synch method <span
+ style="font-weight: bold;">get()</span> has not been defined with any
+chord; it has no body defined and is a "pure virtual" method. So <span
+ style="font-weight: bold;">future</span> is an "abstract" concurrent
+class defining the interface to wait for concurrent computations.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+synch&lt;V()&gt; get;<br>
+&nbsp; V wait() { return get(); }<br>
+&nbsp; future(executor *e) : actor(e) {}<br>
+};<br>
+</div>
+<div style="font-weight: bold;">
+<p><span style="font-weight: normal;">The simplest form of parallelism
+is a loop of iterations that can each run simultaneously without
+interfering with each other. The interface will follow STL's <span
+ style="font-weight: bold;">for_each</span> algorithm, defining a
+sequence of data items and a unary function to be applied (as loop
+body) to each of data items. Since the unary function will run
+concurrently in different tasks, the class async_loop will inherit
+class future for user code to wait for all concurrent computations to
+finish. Also because no final result is returned, we use
+future&lt;void&gt; here. To return result from parallel computations,
+please use the next parallel map_reduce algorithm.<br>
+</span></p>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">template
+&lt;typename InputIterator, typename UnaryFunction&gt;<br>
+class async_loop: public future&lt;void&gt; {<br>
+</div>
+<div style="text-align: left;">Here we save the data defining the
+parallel loop: the start and end of sequence (first_, last_) and the
+unary function to be applied to each of sequence.<br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; InputIterator
+first_;<br>
+&nbsp; InputIterator last_;<br>
+&nbsp; UnaryFunction f_;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Next
+we use a few async methods to define the "states" of async loop. <span
+ style="font-weight: bold;">done() </span>- all concurrent
+computations have finished. <span style="font-weight: bold;">total()</span>
+and <span style="font-weight: bold;">one_finish()</span> are used to
+record how many concurrent computation are still unfinished.<span
+ style="font-weight: bold;"> run_priv()</span> is an async method which
+forks off all concurrent computations.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+async&lt;void()&gt; done;<br>
+&nbsp; async&lt;void(int)&gt; total; <br>
+&nbsp; async&lt;void()&gt; one_finish;<br>
+&nbsp; async&lt;void(InputIterator, int)&gt; run_priv;<br>
+public:<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Users
+of async_loop will call run() to start parallel loop. If the
+data sequence is empty, no work is needed and <span
+ style="font-weight: bold;">done() </span>is called directly.
+Otherwise the first computation task is spawned.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void run() {<br>
+&nbsp;&nbsp;&nbsp; if (first_ == last_)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done();<br>
+&nbsp;&nbsp;&nbsp; else<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; run_priv(first_, 0);<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">In
+constructor, we define three chords for forking concurrent
+computations, waiting for all computations tasks to finish. Please note
+that all these chords have only async methods. Their chord bodies will
+run asynchronously as concurrent tasks in executor's thread pool.</span><br>
+<br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+async_loop(executor *e, InputIterator first, InputIterator last,
+UnaryFunction f) : <br>
+&nbsp;&nbsp;&nbsp; future&lt;void&gt;(e), first_(first), last_(last),
+f_(f) {<br>
+&nbsp;&nbsp;&nbsp; chord(run_priv, &amp;async_loop::run_cb);<br>
+&nbsp;&nbsp;&nbsp; chord(get, done, &amp;async_loop::get_cb);<br>
+&nbsp;&nbsp;&nbsp; chord(one_finish, total, &amp;async_loop::finish_cb);<br>
+&nbsp; }<br>
+private:<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+is the chord body for forking concurrent computations. The passed-in
+argument will contain the data item (in sequence) to be worked on and
+the position in the chain of concurrent tasks.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+run_cb(async_o&lt;void(InputIterator, int)&gt; r) {<br>
+&nbsp;&nbsp;&nbsp; InputIterator next = r.arg1;<br>
+&nbsp;&nbsp;&nbsp; next++;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">If
+this is the last data item in sequence, set the total number of
+concurrent computations and start the process of counting how many
+computations have finished.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;
+if (next == last_) {//all loop bodies started<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; total(r.arg2+1);<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; else {<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Otherwise
+start the next concurrent loop-body.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+run_priv(next, r.arg2+1); //fire the
+next iteration<br>
+&nbsp;&nbsp;&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Then
+we do the concurrent computation: calling the unary function with data
+item. And finally <span style="font-weight: bold;">one_finished()</span>
+is called to notify one concurrent computation is done.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;
+f_(*r.arg1);<br>
+&nbsp;&nbsp;&nbsp; one_finish();<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+is the chord body to count how many concurrent computations are still
+left to finish and when all of them is done, </span>done()<span
+ style="font-weight: normal;"> is called.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+finish_cb(async_o&lt;void()&gt; one,
+async_o&lt;void(int)&gt; tot) {<br>
+&nbsp;&nbsp;&nbsp; if (tot.arg1 &gt; 1)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tot(tot.arg1-1);<br>
+&nbsp;&nbsp;&nbsp; else<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done();<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+is a simple chord to unblock the calling thread of </span>get()<span
+ style="font-weight: normal;"> when all concurrent computations are
+finished.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+get_cb(synch_o&lt;void()&gt; get, async_o&lt;void()&gt;
+done) {}<br>
+};<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Class
+<span style="font-weight: bold;">map_reduce_async</span> catch the
+common idiom of forking multiple concurrent computations and then
+collecting and merging the results from all of them. It follows the
+functional programming style of map/reduce. The basic model of parallel
+map_reduce is to apply a function (map function) concurrently to a
+sequence of data items marked by the start/end iterators, and then
+collect and merge the results by applying the reduce function to
+results from map tasks. Since we need to return a result to initiator,
+class map_reduce_async inherit future&lt;ResultType&gt;.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">template
+&lt;typename InputIterator, <br>
+&nbsp;&nbsp;&nbsp; &nbsp; typename ResultType, <br>
+&nbsp;&nbsp;&nbsp; &nbsp; typename MapFunction, <br>
+&nbsp;&nbsp;&nbsp; &nbsp; typename ReduceFunction&gt;<br>
+class map_reduce_async: public future&lt;ResultType&gt; {<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we save the data defining the concurrent computations.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; InputIterator
+first_;<br>
+&nbsp; InputIterator last_;<br>
+&nbsp; ResultType result_;<br>
+&nbsp; MapFunction map_fun_;<br>
+&nbsp; ReduceFunction reduce_fun_;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">We
+use the following async methods to define the "states" of concurrent
+map_reduce. <span style="font-weight: bold;">done()</span> - all the
+map and reduce tasks have finished and the result is ready to retrieve.
+<span style="font-weight: bold;">total()</span> - how many map tasks
+are not finished yet. <span style="font-weight: bold;">map_m()</span>
+- async method to fork all map tasks. <span style="font-weight: bold;">reduce_m()</span>
+- async method to reduce / merge the result from one completed map task.<br>
+</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+async&lt;void()&gt; done;<br>
+&nbsp; async&lt;void(int)&gt; total; <br>
+&nbsp; async&lt;void(InputIterator, int)&gt; map_m;<br>
+&nbsp; async&lt;void(ResultType)&gt; reduce_m;<br>
+<br>
+public:<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">In
+constructor, we save the data defining the parallel map_reduce
+computation: the sequence of data items (first, last), the init-value
+of result to be merged, map function and reduce function. And create
+three chords for forking concurrent map tasks and reducing / merging
+results from them. Please note all chords have only async methods and
+their chord bodies will run asynchronously and concurrently as tasks in
+executor's thread pool.</span> </div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+map_reduce_async(typename future&lt;ResultType&gt;::executor *e,
+<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; InputIterator first, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; InputIterator last, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ResultType init_val,
+<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; MapFunction mf, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ReduceFunction rf) : <br>
+&nbsp;&nbsp;&nbsp; future&lt;ResultType&gt;(e), first_(first),
+last_(last), result_(init_val),<br>
+&nbsp;&nbsp;&nbsp; map_fun_(mf), reduce_fun_(rf) {<br>
+&nbsp;&nbsp;&nbsp; chord(map_m, &amp;map_reduce_async::map_cb);<br>
+&nbsp;&nbsp;&nbsp; chord(reduce_m, total,
+&amp;map_reduce_async::reduce_cb);<br>
+&nbsp;&nbsp;&nbsp; chord(future&lt;ResultType&gt;::get, done,
+&amp;map_reduce_async::get_cb);<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;">
+<div style="font-weight: bold;"><span style="font-weight: normal;">Users
+of map_reduce_async will call run() to start concurrent computations.
+If the
+data sequence is empty, no work is needed and <span
+ style="font-weight: bold;">done() </span>is called directly.
+So the init-value will be returned when get()/wait() is called.
+Otherwise the first map task is spawned.</span></div>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">
+&nbsp; void run() {<br>
+&nbsp;&nbsp;&nbsp; if (first_ == last_)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done();<br>
+&nbsp;&nbsp;&nbsp; else<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; map_m(first_, 0);<br>
+&nbsp; }<br>
+private:<br style="font-weight: normal;">
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we define the chord body to fork map tasks. Map tasks are spawned as a
+chain. </span><span style="font-weight: normal;">The passed-in
+argument will contain the data item (in sequence) to be worked on and
+the position in the chain of concurrent tasks.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+map_cb(async_o&lt;void(InputIterator, int)&gt; r) {<br>
+&nbsp;&nbsp;&nbsp; InputIterator next = r.arg1;<br>
+&nbsp;&nbsp;&nbsp; next++;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">If
+this is the last data item in sequence, </span><span
+ style="font-weight: normal;">set the total number of
+concurrent computations and start the reducing process to merge the
+results from all map tasks.<br>
+</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;
+if (next == last_) {//all loop bodies started<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; total(r.arg2+1);<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; else {<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Otherwise
+the next map task in chain is spawned.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+map_m(next, r.arg2+1); //fire the next
+iteration<br>
+&nbsp;&nbsp;&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we do the real job by calling map function with the current data item
+in sequence and pass the result to the async</span> reduce_m().<br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;&nbsp;&nbsp;
+reduce_m(map_fun_(*r.arg1));<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we define the chord body for reducing / merging the results from all
+map tasks. First we call the reduce function to merge the resutlt from
+one map task to result. Then we check if any map tasks are still
+pending, otherwise we are finished and <span style="font-weight: bold;">done()</span>
+is called.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+reduce_cb(async_o&lt;void(ResultType)&gt; reduce,
+async_o&lt;void(int)&gt; tot) {<br>
+&nbsp;&nbsp;&nbsp; result_ = reduce_fun_(result_, reduce.arg1);<br>
+&nbsp;&nbsp;&nbsp; if (tot.arg1 &gt; 1)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tot(tot.arg1-1);<br>
+&nbsp;&nbsp;&nbsp; else<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; done();<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we define the chord body for returning the result to caller of</span>
+get() / wait() <span style="font-weight: normal;">when all map /
+reduce tasks are finished.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; void
+get_cb(synch_o&lt;ResultType()&gt; get,
+async_o&lt;void()&gt; done) {<br>
+&nbsp;&nbsp;&nbsp; get.reply(result_);<br>
+&nbsp; }<br>
+};<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Class
+parallel is a wrapper of the above parallel loop and map_reduce
+algorithms to provide a simple STL style functional interface to invoke
+these algorithms. Also class parallel specifies which executor's thread
+pool to run all the async tasks spawned from algorithms.</span> </div>
+<div style="margin-left: 40px; font-weight: bold;">class parallel {<br>
+&nbsp; actor::executor *exec_;<br>
+public:<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">In
+constructor, we pass in and save the executor.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+parallel(actor::executor *e) : exec_(e) {}<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+is the method to invoke the parallel loop algorithm, following STL's <span
+ style="font-weight: bold;">for_each</span> algorithm. An async_loop
+object is created with the arguments passed in and is returned as a
+future&lt;void&gt; to caller. Caller can synchronize and wait for all
+parallel loop bodies using this future object.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; template
+&lt;typename InputIterator, typename UnaryFunction&gt;<br>
+&nbsp; future&lt;void&gt; *for_each(InputIterator first, InputIterator
+last, UnaryFunction f) {<br>
+&nbsp;&nbsp;&nbsp; async_loop&lt;InputIterator, UnaryFunction&gt;
+*aloop = <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new async_loop&lt;InputIterator,
+UnaryFunction&gt;(exec_, first, last, f);<br>
+&nbsp;&nbsp;&nbsp; aloop-&gt;run();<br>
+&nbsp;&nbsp;&nbsp; return aloop;<br>
+&nbsp; }<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+is the method to invoke parallel map_reduce algorithm. A
+map_reduce_async object is created with the arguments passed in and
+returned to caller as a future&lt;ResultType&gt; to caller. </span><span
+ style="font-weight: normal;">Caller can wait for all parallel map /
+reduce tasks and retrieve the final result using this future object.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; template
+&lt;typename InputIterator, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; typename ResultType, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; typename MapFunction, <br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; typename ReduceFunction&gt;<br>
+&nbsp; future&lt;ResultType&gt; *map_reduce(InputIterator first,
+InputIterator last, ResultType init, MapFunction mf, ReduceFunction rf)
+{<br>
+&nbsp;&nbsp;&nbsp;
+map_reduce_async&lt;InputIterator,ResultType,MapFunction,ReduceFunction&gt;
+*mapred = <br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new
+map_reduce_async&lt;InputIterator,ResultType,MapFunction,ReduceFunction&gt;(exec_,
+first, last, init, mf, rf);<br>
+&nbsp;&nbsp;&nbsp; mapred-&gt;run();<br>
+&nbsp;&nbsp;&nbsp; return mapred;<br>
+&nbsp; }<br>
+};<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">In
+the following, we define a simple data seqeunce of integers to
+demonstrate parallel algorithms.<br>
+</span></div>
+<div style="margin-left: 40px; font-weight: bold;">int data[] = {1, 2,
+3, 4, 5, 6, 7, 8, 9, 10};<br>
+int size = sizeof(data) / sizeof(int);<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we define a "square" function to be used as either the loop body of
+parallel loop or map function of parallel map / reduce.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">int sqr(int val) {<br>
+&nbsp; //do some work<br>
+&nbsp; for(int i=0; i&lt;3; i++) {<br>
+&nbsp;&nbsp;&nbsp; log1.stream() &lt;&lt; "one map task calculating: "
+&lt;&lt; val &lt;&lt; " * " &lt;&lt; val &lt;&lt; " ...[" &lt;&lt; i
+&lt;&lt; "]" &lt;&lt; logger::endl;<br>
+&nbsp;&nbsp;&nbsp; thread_sleep(2);<br>
+&nbsp; }<br>
+&nbsp; return val * val;<br>
+}<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+is a "plus" function we'll use as the reduce / merge function.</span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">int plus(int total,
+int one_more) {<br>
+&nbsp; log1.stream() &lt;&lt; "reduce task accumulates: " &lt;&lt;
+one_more &lt;&lt; logger::endl;<br>
+&nbsp; return total + one_more;<br>
+}<br>
+<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">In
+main() function, we set up a test of the above parallel algorithms. </span><br>
+</div>
+<div style="margin-left: 40px; font-weight: bold;">int main(int argc,
+char **argv) {<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">First
+we creates a thread pool with six threads to run the async tasks
+spawned from the parallel algorithms.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; executor
+exec(6);&nbsp; <br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Then
+we create a parallel object with the thread pool.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; parallel
+para(&amp;exec.execute);<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Next
+we invoke the parallel loop algorithm and asking function sqr() to be
+applied concurrently to each item of the data sequence.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+future&lt;void&gt; *f1 = para.for_each(data, data+size, sqr);<br>
+&nbsp; log1.msg("main thread waiting for parallel.for_each() ...");<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we wait for all tasks of parallel loop to finish.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; f1-&gt;wait();<br>
+&nbsp; log1.msg("parallel.for_each() is done, start
+parallel.map_reduce() ...");<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we invoke the parallel map_reduce algorithm on the data sequence using </span>sqr()<span
+ style="font-weight: normal;"> as map function and </span>plus()<span
+ style="font-weight: normal;"> as reduce function.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+future&lt;int&gt; *f2 = para.map_reduce(data, data+size, 0, sqr,
+plus);<br>
+&nbsp; log1.msg("main thread waiting for parallel.map_reduce() ...");<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Here
+we wait for all tasks of parallel map_reduce to finish and retrieve the
+final result.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp; log1.stream()
+&lt;&lt; "parallel.map_reduce() returns: "
+&lt;&lt; f2-&gt;get() &lt;&lt; logger::endl;<br>
+</div>
+<div style="font-weight: bold;"><span style="font-weight: normal;">Finally
+we clean up by shutting down executor (wait for all its threads to
+exit) and delete two future objects.</span></div>
+<div style="margin-left: 40px; font-weight: bold;">&nbsp;
+exec.shutdown();<br>
+&nbsp; delete f1;<br>
+&nbsp; delete f2;<br>
+&nbsp; return 0;<br>
+}<br>
+</div>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/prime_sieve_tut.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/prime_sieve_tut.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,202 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Multi Task Queues and Round Robin Scheduling
+Tutorial</title>
+</head>
+<body>
+<h2>Join Multi Task Queues and Round Robin Scheduling Tutorial</h2>
+In concurrent applications, there are
+many event/message producers and consumers. Some producers produce much
+more events/messages than others and much faster. If the handling of
+all events/messages are dispatched to the same task queue, the fast
+producer will flood the task queue while the events/messages from slow
+producer wont get a fair chance to be processed. The executor of
+Join solve this problem with multiple task queues and round-robin
+scheduling which are implemented using dynamic ports and chords. <br>
+Prime_sieve.cpp is a simple application for finding prime numbers using
+a
+chain of concurrent tasks (prime_task). <a
+ href="http://swtch.com/%7Ersc/thread/">The
+original design</a> is based on CSP style channels. In this sample,
+each of tasks is assigned a separate task_queue and
+executor's thread pool
+round-robin through all task queues so that all tasks get a fair chance
+to run.<br>
+<br>
+Each prime_task will take a stream of integers as input and the first
+integer will be a prime. The prime_task will save the prime and filter
+all the remaining incoming integers: if the integer is multiples of the
+task's prime, the integer will be dropped; otherwise it will be
+forwarded to the next prime_task in chain.<br>
+The prime_task's body runs asynchronously in the executor's thread pool
+and multiple prime_tasks can be active simultaneously.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">class
+prime_task : public actor {<br>
+</span></div>
+The task's private state includes its prime number, its position in
+chain, the pointer to the next task and the executor to dispatch the
+task.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+int my_prime_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; int my_no_;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; prime_task * next_;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; boost::join::executor *e_;</span><br
+ style="font-weight: bold;">
+</div>
+Next declare two asynchronous methods to describe the state of
+prime_task: <span style="font-weight: bold;">"init</span>" - the
+prime_task hasn't received its first integer (the prime number) yet; <span
+ style="font-weight: bold;">"ready"</span> - the first number (prime)
+has been received and saved and task is ready to "sieve" incoming
+numbers based on its prime.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void()&gt; init;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; async&lt;void()&gt; ready;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">public:<br>
+</span></div>
+"<span style="font-weight: bold;">sieve</span>" is the asynchronous
+method to input the stream of integers.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+async&lt;void(int)&gt; sieve;<br>
+</span></div>
+In constructor, we initialize the parent actor class with a
+dynamic task queue selected by its position in the chain, thus the
+bodies of this prime_task will be dispatched into its queue and queue
+fairness can be achieved.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+prime_task(boost::join::executor *e, int no) : </span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">
+&nbsp;&nbsp;&nbsp; actor(e-&gt;task_queue(no)), my_prime_(-1),
+my_no_(no), next_(NULL), e_(e) {<br>
+</span></div>
+Two chords are created for task's behaviour in its two states: "init"
+and "ready". Because these two chords contain only async methods in
+their headers, their bodies will run asynchronously in executor's
+thread pool.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">
+&nbsp;&nbsp;&nbsp; chord(sieve, init, &amp;prime_task::sieve_init_body);</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">
+&nbsp;&nbsp;&nbsp; chord(sieve, ready,
+&amp;prime_task::sieve_ready_body);<br>
+</span></div>
+At end of constructor, call async method <span
+ style="font-weight: bold;">init()</span> to initialize prime_task's
+state.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">
+&nbsp;&nbsp;&nbsp; init(); </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">
+&nbsp; }<br>
+</span></div>
+Here is the chord body of "init" chord (when prime_task is in init
+state). We save the first incoming integer to my_prime_ and spawn the
+next prime_task in chain. Then calling <span style="font-weight: bold;">ready()</span>
+transition the prime_task to "ready" state.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">
+&nbsp; void sieve_init_body(async_o&lt;void(int)&gt; value,
+async_o&lt;void()&gt; init) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; my_prime_ = value;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; log1.stream()
+&lt;&lt; "------ prime_task ["
+&lt;&lt; my_no_ &lt;&lt; "] found prime = " &lt;&lt; my_prime_ &lt;&lt;
+logger::endl;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; next_ = new
+prime_task(e_, my_no_+1); //create the
+next task</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready();</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }<br>
+</span></div>
+Here is the chord body of "ready" chord (when prime_task is in "ready"
+state). The task will "sieve" incoming integers: dropping integers
+which are multiples of its prime number and forwarding the others to
+the next prime_task in chain.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+void sieve_ready_body(async_o&lt;void(int)&gt; value,
+async_o&lt;void()&gt; ready) {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; int val = value;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; ready(); //allow
+processing the next incoming number
+as soon as possible</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; if (val %
+my_prime_) { //not my multiples</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+next_-&gt;sieve(val);</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; } else { //my
+multiples</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.stream() &lt;&lt; "prime_task ["
+&lt;&lt; my_no_ &lt;&lt; "] drop " &lt;&lt; val &lt;&lt; logger::endl;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;"></span><span style="font-weight: bold;">&nbsp;
+~prime_task() {</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; if (next_ != NULL)
+delete next_;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; }</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">};</span><br style="font-weight: bold;">
+<br>
+</div>
+In main(), we set up the chain of prime_tasks and feed the stream of
+integers to it.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">int
+main(int argc, char **argv) {<br>
+</span></div>
+First we create an executor with some threads in pool. Note: since we
+are going to use multiple task queues of executor to dispatch jobs for
+queue fairness, we should use <span style="font-weight: bold;">fire_by_round_robin
+scheduling policy </span>to construct the executor.<span
+ style="font-weight: bold;"><br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+executor exec(4,NULL,executor::actor_type::fire_by_round_robin);<br>
+</span></div>
+Next decide the range of integers to be sieved : 2 - max_num.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+int max_num;</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; if (argc &gt; 1)</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; max_num =
+atoi(argv[1]); </span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; else</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; max_num = 1000;<br>
+<br style="font-weight: bold;">
+</span></div>
+Then create the first task in chain (position = 0) which will create
+its next task and the other tasks in chain as "sieving" goes on.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+prime_task first_task(&amp;exec,0);</span><br style="font-weight: bold;">
+</div>
+We run a simple loop to feed the stream of integers into the head of
+task chain.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+for(int i=2; i&lt;=max_num; i++)</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp;&nbsp;&nbsp; first_task.sieve(i);</span><br
+ style="font-weight: bold;">
+</div>
+The main thread will wait here till all integers sieved and executor's
+threads exit.<br>
+<div style="margin-left: 40px;"><span style="font-weight: bold;">&nbsp;
+exec.shutdown();</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; log1.msg("main thread
+shutdown...");</span><br style="font-weight: bold;">
+<span style="font-weight: bold;">&nbsp; return 0;</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">}</span><br style="font-weight: bold;">
+</div>
+<br>
+</body>
+</html>

Added: sandbox/join/libs/join/doc/tutorials/spawn_tutorial.html
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/doc/tutorials/spawn_tutorial.html 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Join Spawning Thread Tutorial</title>
+</head>
+<body>
+<h2>Join Spawning Thread Tutorial</h2>
+<h4 style="font-weight: normal;" class="dtH4">This tutorial shows how
+to spawn threads by simply calling an Join asynchronous method. <br>
+</h4>
+In Join,<span style="font-weight: normal;">
+there is no explicit thread creation and synchronization or even no
+explicit
+task creation and dispatching to executor thread pool. </span>Chords
+with only
+async&lt;&gt;
+methods will implicitly (automatically) create a task for its body and
+dispatch it to the thread pool of the executor
+associated with the actor. <span style="font-weight: normal;">All
+concurrency and
+asynchroncy are defined and created by async&lt;&gt; methods and chords.<br>
+<br>
+</span>
+<div style="margin-left: 40px;"><span style="font-weight: normal;"><span
+ style="font-weight: bold;">class spawner : public actor {</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">public:<br>
+</span></span></div>
+First we define an async method for spawning tasks in executor. And
+define a chord body method which will run when the async method is
+called.<br>
+<div style="margin-left: 40px;"><span style="font-weight: normal;"><span
+ style="font-weight: bold;">&nbsp; async&lt;void(std::string)&gt; spawn;</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+void run(async_o&lt;void(std::string)&gt; str) {</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+for(int i=0; i&lt;6; i++) {</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+log1.msg(str.arg1);</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+thread_sleep(1);</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+}</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+}<br>
+</span></span></div>
+In contructor, we initialize the parent actor with the
+executor. The asynchronous chord bodies of this actor will be
+dispatched to the thread pool of this executor to run. And we create a
+chord for the above async method and bind it to its chord body. Since
+this chord has only async methods, its body will run in a thread from
+executor's thread pool.<br>
+<div style="margin-left: 40px;"><span style="font-weight: normal;"><span
+ style="font-weight: bold;">&nbsp; spawner(executor *e) :
+actor(e) {</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;&nbsp;&nbsp;
+chord(spawn, &amp;spawner::run);</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+}</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">};</span></span><br
+ style="font-weight: bold;">
+</div>
+In main(), we create the executor with two threads in pool and create
+an instance of spawner class. Then we spawn two tasks into pool.<br>
+<div style="margin-left: 40px;"><span style="font-weight: normal;"><span
+ style="font-weight: bold;">int main(int argc, char **argv) {</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+executor exec(2);</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+spawner sched(&amp;exec.execute);</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+sched.spawn("thread 1");</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+sched.spawn("thread 2");</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+thread_sleep(5);</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+exec.shutdown();</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+log1.msg("...main thread exits...");</span></span><br
+ style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">&nbsp;
+return 0;</span></span><br style="font-weight: bold;">
+<span style="font-weight: normal;"><span style="font-weight: bold;">}</span></span><br>
+<span style="font-weight: normal;"></span></div>
+<span style="font-weight: normal;"><br>
+</span><br>
+<div style="font-weight: bold;">
+<span style="font-family: monospace;"></span>&nbsp;</div>
+</body>
+</html>

Added: sandbox/join/libs/join/examples/func_api/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,56 @@
+
+project
+ : requirements
+ <library>/boost/thread//boost_thread
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ ;
+
+obj buffer.obj : buffer.cpp ;
+exe buffer : buffer.obj ;
+obj spawner1.obj : spawner1.cpp ;
+exe spawner1 : spawner1.obj ;
+obj one_place_buffer.obj : one_place_buffer.cpp ;
+exe one_place_buffer : one_place_buffer.obj ;
+obj counter.obj : counter.cpp ;
+exe counter : counter.obj ;
+obj rwlock.obj : rwlock.cpp ;
+exe rwlock : rwlock.obj ;
+obj bounded_buffer.obj : bounded_buffer.cpp ;
+exe bounded_buffer : bounded_buffer.obj ;
+obj semaphore.obj : semaphore.cpp ;
+exe semaphore : semaphore.obj ;
+obj active_object.obj : active_object.cpp ;
+exe active_object : active_object.obj ;
+obj async_call_ret.obj : async_call_ret.cpp ;
+exe async_call_ret : async_call_ret.obj ;
+obj future.obj : future.cpp ;
+exe future : future.obj ;
+obj join_many.obj : join_many.cpp ;
+exe join_many : join_many.obj ;
+obj spawner2.obj : spawner2.cpp ;
+exe spawner2 : spawner2.obj ;
+obj prime_sieve.obj : prime_sieve.cpp ;
+exe prime_sieve : prime_sieve.obj ;
+obj logged_buffer.obj : logged_buffer.cpp ;
+exe logged_buffer : logged_buffer.obj ;
+obj chord_override.obj : chord_override.cpp ;
+exe chord_override : chord_override.obj ;
+obj buffer_func_pointer.obj : buffer_func_pointer.cpp ;
+exe buffer_func_pointer : buffer_func_pointer.obj ;
+obj event1.obj : thread_safe_events/event1.cpp ;
+exe event1 : event1.obj ;
+obj event2.obj : thread_safe_events/event2.cpp ;
+exe event2 : event2.obj ;
+obj event3.obj : thread_safe_events/event3.cpp ;
+exe event3 : event3.obj ;
+obj parallel.obj : parallel.cpp ;
+exe parallel : parallel.obj ;
+obj with_stl.obj : with_stl.cpp ;
+exe with_stl : with_stl.obj ;
+obj jocaml1.obj : jocaml1.cpp ;
+exe jocaml1 : jocaml1.obj ;
+obj ccr1.obj : ccr1.cpp ;
+exe ccr1 : ccr1.obj ;
+obj ccr2.obj : ccr2.cpp ;
+exe ccr2 : ccr2.obj ;

Added: sandbox/join/libs/join/examples/func_api/active_object.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/active_object.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,94 @@
+//
+// active_object.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+#include <vector>
+#include <string>
+
+using namespace boost::join;
+
+logger log1("log");
+
+class ActiveObject : public actor {
+protected:
+ bool done;
+ synch<void()> ProcessMessage;
+ async<void()> Start;
+public:
+ ActiveObject(executor *e) : actor(e), done(false) {
+ chord(Start, &ActiveObject::main_loop);
+ Start();
+ }
+ void main_loop(async_o<void()> s) {
+ log1.msg("Active object thread starts");
+ while(!done) ProcessMessage();
+ }
+};
+
+class EventSink {
+public:
+ async<void(std::string)> Post;
+};
+
+class Distributor : public ActiveObject, public EventSink {
+ std::vector<EventSink*> subscribers;
+ std::string name;
+public:
+ async<void(EventSink*)> Subscribe;
+ async<void()> Close;
+
+ Distributor(std::string n, executor *e) : ActiveObject(e), name(n) {
+ chord(ProcessMessage, Subscribe, &Distributor::sub_cb);
+ chord(ProcessMessage, Post, &Distributor::post_cb);
+ chord(ProcessMessage, Close, &Distributor::close_cb);
+ }
+
+ void sub_cb(synch_o<void()> P, async_o<void(EventSink*)> S) {
+ subscribers.push_back(S.arg1);
+ }
+ void post_cb(synch_o<void()> P, async_o<void(std::string)> M) {
+ for(size_t i=0; i<subscribers.size(); i++)
+ subscribers[i]->Post(name+" : "+M.arg1);
+ }
+ void close_cb(synch_o<void()> P, async_o<void()> C) {
+ done = true;
+ }
+
+};
+
+class Subscriber : public EventSink, public actor {
+ std::string name;
+public:
+ Subscriber(std::string n, executor *e) : actor(e), name(n) {
+ chord(Post, &Subscriber::post_cb);
+ }
+ void post_cb(async_o<void(std::string)> M) {
+ log1.stream() << name << " got message " << M.arg1 << logger::endl;
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(2);
+ Distributor d("D", &exec.execute);
+ Subscriber a("a", &exec.execute);
+ d.Subscribe(&a);
+ d.Post("First message");
+ Subscriber b("b", &exec.execute);
+ d.Subscribe(&b);
+ d.Post("Second message");
+ Subscriber c("c", &exec.execute);
+ d.Subscribe(&c);
+ d.Post("Third message");
+ d.Close();
+ log1.msg("Main thread waits for exit...");
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/async_call_ret.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/async_call_ret.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,77 @@
+//
+// async_call_ret.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <boost/join/join.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace boost::join;
+
+logger log1("log");
+
+class IService {
+public:
+ async<void(string, async<void(string)>&)> Service;
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class MyService : public actor, public IService {
+ int n;
+public:
+ MyService(int m, executor *e) : actor(e), n(m) {
+ chord(Service, &MyService::service_fun);
+ }
+ void service_fun(async_o<void(string, async<void(string)>&)> req) {
+ for(int i=0; i<n; i++) {
+ log1.stream() << req.arg1 << " is " << i << logger::endl;
+ thread_sleep((n%2)?1:2);
+ }
+ req.arg2(req.arg1+" is done");
+ }
+};
+
+class Join2 : public actor {
+public:
+ async<void(string)> first;
+ async<void(string)> second;
+ synch<void(string&, string&)> Wait;
+ Join2() {
+ chord(Wait, first, second, &Join2::wait_body);
+ }
+ void wait_body(synch_o<void(string&,string&)> w,
+ async_o<void(string)> f,
+ async_o<void(string)> s) {
+ w.arg1 = f.arg1;
+ w.arg2 = s.arg1;
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(2);
+ MyService s1(5, &exec.execute);
+ MyService s2(10, &exec.execute);
+ Join2 j;
+ s1.Service("Service 1", j.first);
+ s2.Service("Service 2", j.second);
+ for(int i=0; i<7; i++) {
+ log1.stream() << "Main " << i << logger::endl;
+ thread_sleep(1);
+ }
+ string x,y;
+ j.Wait(x,y);
+ log1.stream() << "first result = " << x << ", second result = " << y << logger::endl;
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/bounded_buffer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/bounded_buffer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,90 @@
+//
+// bounded_buffer.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename T>
+class BufferN : public actor {
+private:
+ async<void()> token;
+ async<void(T)> value;
+
+public:
+ synch<void(T)> put;
+ synch<T()> get;
+
+ BufferN(int sz) {
+ chord(put, token, &BufferN::put_cb);
+ chord(get, value, &BufferN::get_cb);
+ for(int i=0; i<sz; i++)
+ token();
+ }
+ void put_cb(synch_o<void(T)> put, async_o<void()> tok) {
+ value(put.arg1);
+ }
+ T get_cb(synch_o<T()> get, async_o<void(T)> val) {
+ token();
+ return val.arg1;
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Test : public actor {
+public:
+ BufferN<int> buf_;
+ async<void()> producer;
+ async<void()> consumer1;
+ async<void()> consumer2;
+ Test(executor *e) : actor(e), buf_(5) {
+ chord(producer, &Test::producer_cb);
+ chord(consumer1, &Test::consumer1_cb);
+ chord(consumer2, &Test::consumer2_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ for(int i=0; i<2000000; i++) {
+ buf_.put(i);
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ //thread_sleep(2);
+ }
+ }
+ void consumer1_cb(async_o<void()> c) {
+ for(int i=0; i<1000000; i++) {
+ log1.stream() << "consumer1 recvs [" << buf_.get() << "]" << logger::endl;
+ //thread_sleep(3);
+ }
+ }
+ void consumer2_cb(async_o<void()> c) {
+ for(int i=0; i<1000000; i++) {
+ log1.stream() << "consumer2 recvs [" << buf_.get() << "]" << logger::endl;
+ //thread_sleep(1);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(3);
+ Test test(&exec.execute);
+ test.producer();
+ test.consumer1();
+ test.consumer2();
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/buffer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/buffer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,97 @@
+//
+// buffer.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <boost/join/join.hpp>
+
+//using namespace boost;
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class buffer: public actor {
+public:
+ async<void(V)> put;
+ synch<V(void)> get;
+ buffer() {
+ chord(get, put, &buffer::chord_body);
+ log1.msg("buffer constructed");
+ }
+ V chord_body(synch_o<V(void)> get, async_o<void(V)> put) {
+ return put.arg1;
+ }
+};
+
+void hello_world(buffer<std::string> &b) {
+ b.put("hello");
+ b.put("world");
+ log1.msg(b.get()+" ");
+ log1.msg(b.get());
+}
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ buffer<std::string> &buf_;
+ async<void()> producer;
+ async<void()> consumer;
+ Demo(buffer<std::string> &b, executor *e) : actor(e), buf_(b) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<5; i++) {
+ thread_sleep(i+1);
+ ostr << i;
+ buf_.put(ostr.str());
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ ostr.str("");
+ }
+ }
+ void consumer_cb(async_o<void()> c) {
+ int i=0;
+ while(i<5) {
+ try {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += 1; //receiver timeout in 1 sec
+ log1.stream() << "consumer recvs [" << buf_.get(xt) << "]" << logger::endl;
+ i++;
+ }
+ catch (synch_time_out_exception) {
+ log1.msg("consumer timeout (1 sec)");
+ }
+ catch (...) {
+ log1.msg("consumer unknown exception");
+ }
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ buffer<std::string> b;
+ hello_world(b);
+
+ executor exec(2); //spawn 2 threads for executor thread pool
+ Demo demo(b, &exec.execute);
+ demo.producer();
+ demo.consumer();
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/buffer_func_pointer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/buffer_func_pointer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,84 @@
+//
+// buffer.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+//using namespace boost;
+using namespace boost::join;
+
+logger log1("log");
+
+std::string chord_body(synch_o<std::string(void)> get, async_o<void(std::string)> put) {
+ return put.arg1;
+}
+
+class buffer: public actor {
+public:
+ async<void(std::string)> put;
+ synch<std::string(void)> get;
+ buffer() {
+ chord(get, put, chord_body);
+ }
+};
+
+void hello_world(buffer &b) {
+ b.put("hello");
+ b.put("world");
+ log1.msg(b.get()+" ");
+ log1.msg(b.get());
+}
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ buffer &buf_;
+ async<void()> producer;
+ async<void()> consumer;
+ Demo(buffer &b, executor *e) : actor(e), buf_(b) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<5; i++) {
+ ostr << i;
+ buf_.put(ostr.str());
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void()> c) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "consumer recvs [" << buf_.get() << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ buffer b;
+ hello_world(b);
+
+ executor exec(2); //spawn 2 threads for executor thread pool
+ Demo demo(b, &exec.execute);
+ demo.producer();
+ demo.consumer();
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/ccr1.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/ccr1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,107 @@
+//
+// ccr1.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/bind.hpp>
+#include <string>
+
+using namespace boost::join;
+using namespace boost;
+using namespace std;
+
+logger log1("log");
+
+
+class ServiceResponse {
+public:
+ async<void(string)> result;
+ async<void(std::exception*)> failure;
+};
+
+class Stop {
+public:
+ ServiceResponse *response;
+ Stop(ServiceResponse *r) : response(r) {}
+};
+
+class UpdateState {
+public:
+ ServiceResponse *response;
+ string state;
+ UpdateState() {}
+ UpdateState(string st, ServiceResponse *r) : response(r), state(st) {}
+};
+
+class GetState {
+public:
+ ServiceResponse *response;
+ GetState() {}
+ GetState(ServiceResponse *r) : response(r) {}
+};
+
+class SimpleService {
+ joint joins;
+ string state_;
+public:
+ async<void(Stop)> stop;
+ async<void(UpdateState)> update;
+ async<void(GetState)> get;
+
+ SimpleService(joint::executor *e) : joins(e), state_("") {
+ joins.chord(update, bind(&SimpleService::UpdateHandler, this, _1))
+ .chord(get, bind(&SimpleService::GetStateHandler, this, _1));
+ }
+ void GetStateHandler(async_o<void(GetState)> get) {
+ if (state_.length() == 0)
+ get.arg1.response->failure(new std::exception());
+ else
+ get.arg1.response->result("from get: "+state_);
+ }
+ void UpdateHandler(async_o<void(UpdateState)> update) {
+ state_ = update.arg1.state;
+ update.arg1.response->result("from update: "+state_);
+ }
+};
+
+void print_result(async_o<void(string)> a) {
+ log1.stream() << "result : " << a.arg1 << logger::endl;
+}
+
+
+void print_failure(async_o<void(std::exception *)> e) {
+ delete e.arg1;
+ log1.stream() << "got std::exception" << logger::endl;
+}
+
+
+int main(int argc, char **argv) {
+
+ //create an executor with 2 threads in pool
+ executor exec(2);
+
+ SimpleService ssrv(&exec.execute);
+
+ ServiceResponse resp;
+
+ joint joins(&exec.execute);
+ joins.chord(resp.result, print_result)
+ .chord(resp.failure, print_failure);
+
+ //send some requests
+ GetState g(&resp);
+ ssrv.get(g); //should get std::exception here
+ UpdateState up(string("state1"), &resp);
+ ssrv.update(up);
+ ssrv.get(g);
+
+ exec.shutdown();
+
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/ccr2.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/ccr2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,160 @@
+//
+// ccr2.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+using namespace boost::join;
+using namespace boost;
+using namespace std;
+
+logger log1("log");
+
+//base interface for all service messages. define <result, failure> channels
+class ServiceResponse {
+public:
+ async<void(string)> result;
+ async<void(std::exception*)> failure;
+};
+
+class Stop : public ServiceResponse {};
+
+class UpdateState : public ServiceResponse {
+public:
+ string state;
+ UpdateState(string s): state(s) {}
+ void set(string st) { state = st; }
+};
+
+class GetState : public ServiceResponse {};
+
+//base interface of all services, defining what messages a service can serve
+class Service {
+public:
+ async<void(Stop&)> stop;
+ async<void(UpdateState&)> update;
+ async<void(GetState&)> get;
+};
+
+//a simple service implemnt the above service base interface
+//following the same pattern as CCR, using a static method to
+//create the server obj and return the msg based interface
+class SimpleService : public Service, public actor {
+public:
+ static shared_ptr<Service> Create(joint::executor *e) {
+ shared_ptr<Service> srv(new SimpleService(e));
+ return srv;
+ }
+
+private:
+ string state_;
+
+ SimpleService(joint::executor *e) : actor(e), state_("") {
+ chord(update, &SimpleService::UpdateHandler);
+ chord(get, &SimpleService::GetStateHandler);
+ chord(stop, &SimpleService::StopHandler);
+ }
+ void GetStateHandler(async_o<void(GetState&)> get) {
+ if (state_.length() == 0)
+ get.arg1.failure(new std::exception());
+ else
+ get.arg1.result("from get: "+state_);
+ }
+ void UpdateHandler(async_o<void(UpdateState&)> update) {
+ state_ = update.arg1.state;
+ update.arg1.result("from update: "+state_);
+ }
+ void StopHandler(async_o<void(Stop&)> stop) {
+ log1.stream() << "clients ask for stop" << logger::endl;
+ stop.arg1.result("i am going to stop...");
+ }
+};
+
+void async_print_result(async_o<void(string)> a) {
+ log1.stream() << "async result : " << a.arg1 << logger::endl;
+}
+
+
+void async_print_failure(async_o<void(std::exception *)> e) {
+ delete e.arg1;
+ log1.stream() << "async got std::exception" << logger::endl;
+}
+
+void synch_print_result(synch_o<void()> r, async_o<void(string)> a) {
+ log1.stream() << "synch recv result : " << a.arg1 << logger::endl;
+}
+
+
+void synch_print_failure(synch_o<void()> r, async_o<void(std::exception *)> e) {
+ delete e.arg1;
+ log1.stream() << "synch got std::exception" << logger::endl;
+}
+
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+int main(int argc, char **argv) {
+
+ //create an executor with 2 threads in pool
+ executor exec(2);
+
+ shared_ptr<Service> ssrv(SimpleService::Create(&exec.execute));
+
+ GetState g;
+ UpdateState u("state1");
+
+ //asynchronous recv and processing responses from server
+ joint joins(&exec.execute);
+ joins.chord(g.result, async_print_result)
+ .chord(g.failure, async_print_failure)
+ .chord(u.result, async_print_result)
+ .chord(u.failure, async_print_failure);
+
+ //send some requests
+ ssrv->get(g); //should get std::exception here
+ ssrv->update(u);
+ ssrv->get(g);
+
+ //wait for async processing responses
+ log1.stream() << "wait 1 secs for async responses processing ..." << logger::endl;
+ thread_sleep(1);
+
+ //reset joins
+ joins.reset();
+
+ //create synchronous recv channel
+ synch<void()> recv;
+
+ //and steup new chords with synchronous "recv"
+ joins.chord(recv, g.result, synch_print_result)
+ .chord(recv, g.failure, synch_print_failure)
+ .chord(recv, u.result, synch_print_result)
+ .chord(recv, u.failure, synch_print_failure);
+
+ //send a few req
+ int runs=5;
+ for(int i=0; i<runs; i++)
+ ssrv->update(u);
+
+ //recv & process the responses. Note: recv() will block wait
+ for(int i=0; i<runs; i++)
+ recv();
+
+ exec.shutdown();
+
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/ccr_service.cs
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/ccr_service.cs 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,99 @@
+/// Copyright Microsoft
+///
+/// Copied from Microsoft MSDN CCR User Guide
+///
+/// <summary>
+/// Base type for all service messages. Defines a response PortSet used
+/// by all message types.
+/// </summary>
+public class ServiceOperation
+{
+ public PortSet<string, Exception> ResponsePort = new PortSet<string, Exception>();
+}
+
+public class Stop : ServiceOperation
+{
+}
+
+public class UpdateState : ServiceOperation
+{
+ public string State;
+}
+
+public class GetState : ServiceOperation
+{
+}
+
+/// <summary>
+/// PortSet that defines which messages the services listens to
+/// </summary>
+public class ServicePort : PortSet<Stop, UpdateState, GetState>
+{
+}
+/// <summary>
+/// Simple example of a CCR component that uses a PortSet to abstract
+/// its API for message passing
+/// </summary>
+public class SimpleService
+{
+ ServicePort _mainPort;
+ DispatcherQueue _taskQueue;
+ string _state;
+
+ public static ServicePort Create(DispatcherQueue taskQueue)
+ {
+ SimpleService service = new SimpleService(taskQueue);
+ service.Initialize();
+ return service._mainPort;
+ }
+
+ private void Initialize()
+ {
+ // using the supplied taskQueue for scheduling, activate three
+ // persisted receivers, that will run concurrently to each other,
+ // one for each item type
+ Arbiter.Activate(_taskQueue,
+ Arbiter.Receive<UpdateState>(true, _mainPort, UpdateHandler),
+ Arbiter.Receive<GetState>(true, _mainPort, GetStateHandler)
+ );
+ }
+
+ private SimpleService(DispatcherQueue taskQueue)
+ {
+ // create PortSet instance used by external callers to post items
+ _mainPort = new ServicePort();
+
+ // cache dispatcher queue used to schedule tasks
+ _taskQueue = taskQueue;
+ }
+ void GetStateHandler(GetState get)
+ {
+ if (_state == null)
+ {
+ // To demonstrate a failure response,
+ // when state is null will post an exception
+ get.ResponsePort.Post(new InvalidOperationException());
+ return;
+ }
+
+ // return the state as a message on the response port
+ get.ResponsePort.Post(_state);
+ }
+ void UpdateHandler(UpdateState update)
+ {
+ // update state from field in the message
+ _state = update.State;
+
+ // as success result, post the state itself
+ update.ResponsePort.Post(_state);
+ }
+}
+
+In the example above we show a class implementing the common CCR pattern for a software component:
+
+ * Definitions of message types used to interact with the component
+ * Definition of a PortSet derived class that accepts the message types defined. Its not necessary to derive from PortSet, but its a convenient way to reuse a PortSet with a particular number of types.
+ * A static Create method that initializes an instance of the component and returns a PortSet instance used to communicate with the component instance
+ * A private Initialize method that attaches some Arbiters on the public PortSet external code will use to talk to the service
+
+If no concurrency constraints exist between the different handlers, simple, persisted single item receivers can be used.

Added: sandbox/join/libs/join/examples/func_api/chord_override.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/chord_override.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,113 @@
+//
+// chord_override.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+//---- demo of "static" overriding by virtual chord body ----
+
+//original buffer definitio
+template <typename V>
+class buffer: public actor {
+public:
+ async<void(V)> put;
+ synch<V()> get;
+ buffer() {
+ chord(get, put, &buffer::chord_body);
+ }
+ //to be overriden, the chord body method has to be "virtual"
+ virtual V chord_body(synch_o<V()> get, async_o<void(V)> put) {
+ return put.arg1;
+ }
+};
+
+//logged_buffer changes buffer's behaviour by overriding chord method
+template <typename V>
+class logged_buffer: public buffer<V> {
+public:
+ //override chord body method
+ V chord_body(synch_o<V()> get, async_o<void(V)> put) {
+ log1.stream() << "logged_buffer transfer: " << put.arg1 << logger::endl;
+ return put.arg1;
+ }
+};
+
+//---- demo of "dynamic" overiding by chord_override method ----
+
+class transformer : public actor {
+ buffer<std::string> &buf_;
+public:
+ async<void(std::string)> transform;
+ async<void()> ready;
+ transformer(buffer<std::string> &b, executor *e) : actor(e), buf_(b) {
+ chord(transform, ready, &transformer::do_1);
+ ready();
+ }
+ void do_1(async_o<void(std::string)> arg, async_o<void()> r) {
+ buf_.put("do_1: " + arg.arg1);
+ chord_override(transform, ready, &transformer::do_2);
+ ready();
+ }
+ void do_2(async_o<void(std::string)> arg, async_o<void()> r) {
+ buf_.put("do_2: " + arg.arg1);
+ chord_override(transform, ready, &transformer::do_1);
+ ready();
+ }
+};
+
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ logged_buffer<std::string> buf_;
+ transformer trans_;
+ async<void()> producer;
+ async<void()> consumer;
+ Demo(executor *e) : actor(e), trans_(buf_, e) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<5; i++) {
+ ostr << i;
+ trans_.transform(ostr.str());
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void()> c) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "consumer recvs [" << buf_.get() << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(3);
+ Demo demo(&exec.execute);
+ demo.producer();
+ demo.consumer();
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/counter.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/counter.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,79 @@
+//
+// counter.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+class counter: public actor {
+ async<void(long)> mystate;
+public:
+ async<void()> inc;
+ synch<long()> value;
+
+ void inc_bdy(async_o<void()> inc, async_o<void(long)> mi) {
+ mystate(mi+1);
+ }
+
+ long val_bdy(synch_o<long()> val, async_o<void(long)> mi) {
+ mystate(mi);
+ return mi;
+ }
+
+ counter(executor *e) : actor(e) {
+ chord(inc, mystate, &counter::inc_bdy);
+ chord(value, mystate, &counter::val_bdy);
+ mystate(0);
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ counter c_;
+ async<void()> writer;
+ async<void()> reader;
+ Demo(executor *e) : actor(e), c_(e) {
+ chord(writer, &Demo::writer_bdy);
+ chord(reader, &Demo::reader_bdy);
+ }
+ void writer_bdy(async_o<void()> w) {
+ for(int i=0; i<5; i++) {
+ log1.msg("writer inc");
+ c_.inc();
+ thread_sleep(1);
+ }
+ }
+ void reader_bdy(async_o<void()> r) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "reader reads [" << c_.value() << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(3); //spawn 2 threads for executor thread pool
+ Demo demo(&exec.execute);
+ demo.reader();
+ demo.writer();
+ thread_sleep(8);
+ log1.msg("---- executor exit ----");
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/future.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/future.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,106 @@
+//
+// future.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+#include <string>
+#include <stdexcept>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename T>
+class future : public actor {
+public:
+ typedef boost::function<T()> Computation;
+ synch<T()> get;
+private:
+ Computation comp;
+ async<void()> compute;
+ async<void()> done;
+ std::auto_ptr<T> value_;
+ std::auto_ptr<std::runtime_error> except_;
+
+public:
+ future(Computation c, executor *e) : actor(e), comp(c) {
+ chord(compute, &future::compute_body);
+ chord(get, done, &future::get_body);
+ compute();
+ }
+ void compute_body(async_o<void()> c) {
+ try {
+ value_.reset(new T(comp()));
+ }
+ catch (...) {
+ //need more delicate way to catch application specific exceptions
+ //such as Peter Dimov N2179 proposal
+ //here for demo, simply change all exceptions to runtime_error
+ except_.reset(new std::runtime_error("exceptions happens inside future computation"));
+ }
+ done();
+ }
+ T get_body(synch_o<T()> g, async_o<void()> d) {
+ done(); //reissue done to allow multiple gets
+ if(except_.get())
+ throw *except_;
+ return *value_;
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+std::string task1() {
+ for(int i=0; i<8; i++) {
+ log1.stream() << "task1 is running " << i << logger::endl;
+ thread_sleep(1);
+ }
+ return std::string("task1 is done");
+}
+
+std::string task2() {
+ for(int i=0; i<8; i++) {
+ log1.stream() << "task2 is running " << i << logger::endl;
+ thread_sleep(1);
+ if(i==4) {
+ throw std::runtime_error("future exception test");
+ }
+ }
+ return std::string("task2 is done");
+}
+
+int main(int argc, char **argv) {
+ executor exec(2); //add 2 threads in executor thread pool
+ future<std::string> fu1(task1, &exec.execute);
+ future<std::string> fu2(task2, &exec.execute);
+ for(int i=0; i<4; i++) {
+ log1.stream() << "Main " << i << logger::endl;
+ thread_sleep(1);
+ }
+ log1.msg("Main starts waiting on future");
+ try {
+ log1.stream() << "future1 returns : " << fu1.get() << logger::endl;
+ }
+ catch (...) {
+ log1.msg("future1 got exception");
+ }
+ try {
+ log1.stream() << "future2 returns : " << fu2.get() << logger::endl;
+ }
+ catch (...) {
+ log1.msg("future2 got exception");
+ }
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/jocaml1.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/jocaml1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,154 @@
+//
+// jocaml1.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/bind.hpp>
+//#include <iostream>
+
+using namespace boost::join;
+using namespace boost;
+using namespace std;
+
+logger log1("log");
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+//define 2 plain functions as chord-body or message handlers
+void apple_pie(async_o<void(string)> a, async_o<void()> p) {
+ log1.stream() << a.arg1 << " apple pie" << logger::endl;
+}
+
+void raspberry_pie(async_o<void(string)> r, async_o<void()> p) {
+ log1.stream() << r.arg1 << " raspberry pie" << logger::endl;
+}
+
+//define a class using its object's methods as chord-body or message handlers
+class fruit_pie {
+ int count;
+public:
+ fruit_pie(int c) : count(c) {}
+ void apple(async_o<void(string)> a, async_o<void()> p) {
+ log1.stream() << a.arg1 << " apple pie " << count << logger::endl;
+ }
+ void raspberry(async_o<void(string)> r, async_o<void()> p) {
+ log1.stream() << r.arg1 << " raspberry pie " << count << logger::endl;
+ }
+ void blueberry(async_o<void(string)> r, async_o<void()> p) {
+ log1.stream() << r.arg1 << " blueberry pie " << count << logger::endl;
+ }
+ void strange(async_o<void(string)> a, async_o<void()> p) {
+ log1.stream() << "STRANGE " << a.arg1 << " apple pie " << count << logger::endl;
+ }
+};
+
+
+int main(int argc, char **argv) {
+ //define a few asynchronous message channels
+ async<void(string)> apple;
+ async<void(string)> raspberry;
+ async<void(string)> blueberry;
+ async<void()> pie;
+
+ //create an executor with 2 threads in pool
+ executor exec(2);
+
+ //test1: a new joins obj is created, used, reused and destroyed at end of scope
+ try
+ {
+ //define an actor/joint object with a few chords/join-patterns to specify
+ //what to do with messages at channels : apple(), raspberry() and pie()
+ actor joins(&exec.execute);
+ joins.chord(apple, pie, apple_pie)
+ .chord(raspberry, pie, raspberry_pie);
+
+ //send a few messages to test
+ pie(); pie();
+ raspberry("green");
+ apple("red");
+
+ //clear all chords (join patterns or coordination definitions) in "joins" to reuse it
+ joins.reset();
+
+ //redefine 2 chords with different processing code
+ fruit_pie fp1(1);
+ joins.chord(apple, pie, bind(&fruit_pie::apple, fp1, _1, _2))
+ .chord(raspberry, pie, bind(&fruit_pie::raspberry, fp1, _1, _2));
+
+ //send more test messages
+ pie(); pie();
+ raspberry("purple");
+ apple("yellow");
+
+ //override chord <apple,pie> to print diff msg
+ joins.chord_override(apple, pie, bind(&fruit_pie::strange, fp1, _1, _2));
+ apple("white"); pie();
+
+ //add a new chord into existing chords
+ joins.chord(blueberry, pie, bind(&fruit_pie::blueberry, fp1, _1, _2));
+ blueberry("dark"); pie();
+
+ //here when going out of scope, "joins" is destroyed with its coordination/join patterns
+ //for channels pie()/apple()/raspberry(); while the channels are left unattached.
+ }
+ catch (join_exception &e) {
+ log1.stream() << "Caught exception: " << e.what() << logger::endl;
+ }
+
+ //test2: another joins object is used
+ try
+ {
+ //define an actor/joint object with a few chords
+ fruit_pie fp2(2);
+ actor joins(&exec.execute);
+ joins.chord(apple, pie, bind(&fruit_pie::apple, fp2, _1, _2))
+ .chord(raspberry, pie, bind(&fruit_pie::raspberry, fp2, _1, _2))
+ .chord(blueberry, pie, bind(&fruit_pie::blueberry, fp2, _1, _2));
+
+ //send some test messages
+ pie(); pie();
+ raspberry("sour");
+ apple("dull");
+ blueberry("sweet"); pie();
+
+ //test delete a chord
+ joins.chord_remove(raspberry, pie);
+ //since channel raspberry is not associated with joins/actor anymore,
+ //calling it will throw exception
+ raspberry("bitter");
+ }
+ catch (join_exception &e) {
+ log1.stream() << "Caught bitter-raspberry exception: " << e.what() << logger::endl;
+ }
+
+ try {
+ //test unbound async methods/channels
+ //an exception should be thrown here since
+ //all joiners/actors are gone and async channel "pie"
+ //is not associated with any actor
+ pie();
+ }
+ catch (join_exception &e) {
+ log1.stream() << "Caught unbound-pie exception: " << e.what() << logger::endl;
+ }
+
+ try {
+ exec.shutdown();
+ }
+ catch(join_exception &e) {
+ log1.stream() << "Caught exception: " << e.what() << logger::endl;
+ }
+
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/join_many.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/join_many.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,86 @@
+//
+// join_many.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+#include <vector>
+
+using namespace boost;
+using namespace boost::join;
+
+logger log1("log");
+
+// join multiple input streams into one output stream
+template <typename T, size_t N>
+class join_many : public actor {
+public:
+ array<async<void(T)>,N> inputs;
+ synch<array<T,N>()> output;
+ join_many() {
+ chord(output, inputs, &join_many::chord_body);
+ }
+ array<T,N> chord_body(synch_o<array<T,N>()> out, array<async_o<void(T)>,N> in) {
+ array<T,N> vt;
+ for(size_t i=0; i<N; i++)
+ vt[i] = in[i].arg1;
+ return vt;
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ enum {
+ num_chan = 4,
+ num_test = 5
+ };
+ join_many<int,num_chan> merger;
+ async<void(int)> inputer;
+ void wait(void) {
+ array<int,num_chan> results;
+ for(int i=0; i<num_test; i++) {
+ results = merger.output();
+ log1.stream() << "output" << i << " = " << logger::end;
+ for(size_t j=0;j<num_chan;j++)
+ log1.stream() << results[j] << " " << logger::end;
+ log1.stream() << logger::endl;
+ }
+ }
+ Demo(executor *e) : actor(e) {
+ chord(inputer, &Demo::chord_body);
+ //spawn multiple concurrent test streams
+ for(int i=0; i<num_chan; i++)
+ inputer(i);
+ }
+ void chord_body(async_o<void(int)> p) {
+ int start = p.arg1*num_test;
+ int end = start+num_test;
+ for(int i=start; i<end; i++) {
+ log1.stream() << "inputer[" << p.arg1 << "] sends [" << i << "] and wait..." << logger::endl;
+ merger.inputs[p.arg1](i);
+ thread_sleep((p.arg1+1)%3);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(4); //spawn 4 threads for executor thread pool
+ Demo demo(&exec.execute);
+ log1.msg("main thread starts waiting...");
+ demo.wait();
+ log1.msg("main thread finish waiting...");
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/lambda1.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/lambda1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,16 @@
+#include <boost/lambda/lambda.hpp>
+#include <algorithm>
+#include <iostream>
+using namespace std;
+using namespace boost::lambda;
+
+int a[] = {1,2,3,4};
+void d(int a) {
+ cout << a << endl;
+}
+
+int main(int argc, char **argv) {
+ for_each(a, a+4, (_1, cout << _1 << '\n'));
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/logged_buffer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/logged_buffer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,96 @@
+//
+// logged_buffer.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+//original buffer definition
+template <typename V>
+class buffer: public actor {
+public:
+ async<void(V)> put;
+ synch<V()> get;
+ buffer() {
+ chord(get, put, &buffer::chord_body);
+ }
+ V chord_body(synch_o<V()> get, async_o<void(V)> put) {
+ return put.arg1;
+ }
+};
+
+//logged_buffer aggregates the original buffer and extends it with new functionality
+template <typename V>
+class logged_buffer: public actor {
+ buffer<V> buf_;
+public:
+ //export inner actor's interface
+ async<void(V)> &put;
+ synch<V()> &get;
+ //add new interface
+ async<void(V)> logged_put;
+ logged_buffer(executor *e) : actor(e), buf_(), put(buf_.put), get(buf_.get) {
+ chord(logged_put, &logged_buffer::chord_body);
+ }
+ void chord_body(async_o<void(V)> put) {
+ log1.stream() << "logged_put: " << put.arg1 << logger::endl;
+ buf_.put(put.arg1);
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ logged_buffer<std::string> buf_;
+ async<void()> producer;
+ async<void()> consumer;
+ Demo(executor *e) : actor(e), buf_(e) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<5; i++) {
+ ostr << i;
+ if (i%2 == 0)
+ buf_.put(ostr.str());
+ else
+ buf_.logged_put(ostr.str());
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void()> c) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "consumer recvs [" << buf_.get() << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(3);
+ Demo demo(&exec.execute);
+ demo.producer();
+ demo.consumer();
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/one_place_buffer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/one_place_buffer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,87 @@
+//
+// one_place_buffer.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class one_place_buffer: public actor {
+private:
+ //private async methods/msgs to represent buffer states
+ async<void()> empty;
+ async<void(V)> contains;
+public:
+ synch<void(V)> put;
+ synch<V()> get;
+
+ void put_cb(synch_o<void(V)> put, async_o<void()> empty) {
+ contains(put.arg1);
+ }
+
+ V get_cb(synch_o<V()> get, async_o<void(V)> contains) {
+ empty();
+ return contains.arg1;
+ }
+
+ one_place_buffer() {
+ chord(put, empty, &one_place_buffer::put_cb);
+ chord(get, contains, &one_place_buffer::get_cb);
+ empty(); //init state
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ one_place_buffer<std::string> &buf_;
+ async<void()> producer;
+ async<void()> consumer;
+ Demo(one_place_buffer<std::string> &b, executor *e) : actor(e), buf_(b) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<5; i++) {
+ ostr << i;
+ buf_.put(ostr.str());
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void()> c) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "consumer recvs [" << buf_.get() << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ one_place_buffer<std::string> b;
+ executor exec(2); //spawn 2 threads for executor thread pool
+ Demo demo(b, &exec.execute);
+ demo.producer();
+ demo.consumer();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/parallel.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/parallel.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,188 @@
+//
+// parallel.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/shared_ptr.hpp>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class future: public actor {
+public:
+ synch<V()> get;
+ V wait() { return get(); }
+ future(executor *e) : actor(e) {}
+};
+
+template <typename InputIterator, typename UnaryFunction>
+class async_loop: public future<void> {
+ InputIterator first_;
+ InputIterator last_;
+ UnaryFunction f_;
+ async<void()> done;
+ async<void(int)> total; //total of bodies running
+ async<void()> one_finish;
+ async<void(InputIterator, int)> run_priv;
+public:
+ void run() {
+ if (first_ == last_)
+ done();
+ else
+ run_priv(first_, 0);
+ }
+ async_loop(executor *e, InputIterator first, InputIterator last, UnaryFunction f) :
+ future<void>(e), first_(first), last_(last), f_(f) {
+ chord(run_priv, &async_loop::run_cb);
+ chord(get, done, &async_loop::get_cb);
+ chord(one_finish, total, &async_loop::finish_cb);
+ }
+private:
+ void run_cb(async_o<void(InputIterator, int)> r) {
+ InputIterator next = r.arg1;
+ next++;
+ if (next == last_) {//all loop bodies started
+ total(r.arg2+1);
+ }
+ else {
+ run_priv(next, r.arg2+1); //fire the next iteration
+ }
+ f_(*r.arg1);
+ one_finish();
+ }
+ void finish_cb(async_o<void()> one, async_o<void(int)> tot) {
+ if (tot.arg1 > 1)
+ tot(tot.arg1-1);
+ else
+ done();
+ }
+ void get_cb(synch_o<void()> get, async_o<void()> done) {}
+};
+
+
+template <typename InputIterator,
+ typename ResultType,
+ typename MapFunction,
+ typename ReduceFunction>
+class map_reduce_async: public future<ResultType> {
+ InputIterator first_;
+ InputIterator last_;
+ ResultType result_;
+ MapFunction map_fun_;
+ ReduceFunction reduce_fun_;
+ async<void()> done;
+ async<void(int)> total; //total of bodies running
+ async<void(InputIterator, int)> map_m;
+ async<void(ResultType)> reduce_m;
+
+public:
+ map_reduce_async(typename future<ResultType>::executor *e, InputIterator first, InputIterator last,
+ ResultType init_val, MapFunction mf, ReduceFunction rf) :
+ future<ResultType>(e), first_(first), last_(last), result_(init_val),
+ map_fun_(mf), reduce_fun_(rf) {
+ chord(map_m, &map_reduce_async::map_cb);
+ chord(reduce_m, total, &map_reduce_async::reduce_cb);
+ chord(future<ResultType>::get, done, &map_reduce_async::get_cb);
+ }
+ void run() {
+ if (first_ == last_)
+ done();
+ else
+ map_m(first_, 0);
+ }
+private:
+ void map_cb(async_o<void(InputIterator, int)> r) {
+ InputIterator next = r.arg1;
+ next++;
+ if (next == last_) {//all loop bodies started
+ total(r.arg2+1);
+ }
+ else {
+ map_m(next, r.arg2+1); //fire the next iteration
+ }
+ reduce_m(map_fun_(*r.arg1));
+ }
+ void reduce_cb(async_o<void(ResultType)> reduce, async_o<void(int)> tot) {
+ result_ = reduce_fun_(result_, reduce.arg1);
+ if (tot.arg1 > 1)
+ tot(tot.arg1-1);
+ else
+ done();
+ }
+ ResultType get_cb(synch_o<ResultType()> get, async_o<void()> done) {
+ return result_;
+ }
+};
+
+
+class parallel {
+ actor::executor *exec_;
+public:
+ parallel(actor::executor *e) : exec_(e) {}
+
+ template <typename InputIterator, typename UnaryFunction>
+ future<void> *for_each(InputIterator first, InputIterator last, UnaryFunction f) {
+ async_loop<InputIterator, UnaryFunction> *aloop =
+ new async_loop<InputIterator, UnaryFunction>(exec_, first, last, f);
+ aloop->run();
+ return aloop;
+ }
+
+ template <typename InputIterator,
+ typename ResultType,
+ typename MapFunction,
+ typename ReduceFunction>
+ future<ResultType> *map_reduce(InputIterator first, InputIterator last, ResultType init, MapFunction mf, ReduceFunction rf) {
+ map_reduce_async<InputIterator,ResultType,MapFunction,ReduceFunction> *mapred =
+ new map_reduce_async<InputIterator,ResultType,MapFunction,ReduceFunction>(exec_, first, last, init, mf, rf);
+ mapred->run();
+ return mapred;
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+int size = sizeof(data) / sizeof(int);
+
+int sqr(int val) {
+ //do some work
+ for(int i=0; i<3; i++) {
+ log1.stream() << "one map task calculating: " << val << " * " << val << " ...[" << i << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ return val * val;
+}
+
+int plus(int total, int one_more) {
+ log1.stream() << "reduce task accumulates: " << one_more << logger::endl;
+ return total + one_more;
+}
+
+int main(int argc, char **argv) {
+ executor exec(6);
+ parallel para(&exec.execute);
+ future<void> *f1 = para.for_each(data, data+size, sqr);
+ log1.msg("main thread waiting for parallel.for_each() ...");
+ f1->wait();
+ log1.msg("parallel.for_each() is done, start parallel.map_reduce() ...");
+ future<int> *f2 = para.map_reduce(data, data+size, 0, sqr, plus);
+ log1.msg("main thread waiting for parallel.map_reduce() ...");
+ log1.stream() << "parallel.map_reduce() returns: " << f2->get() << logger::endl;
+ exec.shutdown();
+ delete f1;
+ delete f2;
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/prime_sieve.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/prime_sieve.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,81 @@
+//
+// prime_sieve.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <string>
+#include <iostream>
+
+using namespace std;
+using namespace boost::join;
+
+logger log1("log");
+
+typedef rr_executor exec_type;
+typedef actor_t<async<void(actor_base::callable)> > actor_type;
+
+class prime_task : public actor_type {
+ int my_prime_;
+ int my_no_;
+ prime_task * next_;
+ exec_type *e_;
+ //using async<> methods to represent states
+ async<void()> init;
+ async<void()> ready;
+public:
+ async<void(int)> sieve;
+ void sieve_init_body(async_o<void(int)> value, async_o<void()> init) {
+ my_prime_ = value;
+ log1.stream() << "------ prime_task [" << my_no_ << "] found prime = " << my_prime_ << logger::endl;
+ next_ = new prime_task(e_, my_no_+1); //create the next task
+ ready();
+ }
+ void sieve_ready_body(async_o<void(int)> value, async_o<void()> ready) {
+ int val = value;
+ ready(); //allow processing the next incoming number as soon as possible
+ if (val % my_prime_) { //not my multiples
+ next_->sieve(val);
+ } else { //my multiples
+ log1.stream() << "prime_task [" << my_no_ << "] drop " << val << logger::endl;
+ }
+ }
+ prime_task(exec_type *e, int no) :
+ actor_type(e->task_queue(no)), my_prime_(-1), my_no_(no), next_(0), e_(e) {
+ chord(sieve, init, &prime_task::sieve_init_body);
+ chord(sieve, ready, &prime_task::sieve_ready_body);
+ init(); //initialize actor's state
+ }
+ ~prime_task() {
+ if (next_ != 0) delete next_;
+ }
+};
+
+int main(int argc, char **argv) {
+ exec_type exec(4);
+
+ int max_num;
+ if (argc > 1)
+ max_num = atoi(argv[1]);
+ else
+ max_num = 1000;
+
+ log1.stream() << "find primes in range [2-" << max_num << "]" << logger::endl;
+
+ //create prime_task0
+ prime_task first_task(&exec,0);
+
+ //generate integer series to be sieved and feed them to the chain of tasks
+ for(int i=2; i<=max_num; i++)
+ first_task.sieve(i);
+
+ log1.msg("main thread shutdown...");
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/rwlock.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/rwlock.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,107 @@
+//
+// rwlock.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+class ReaderWriter : public actor {
+private:
+ //async msgs describe rwlock status
+ async<void()> idle;
+ async<void(int)> s;
+
+public:
+ synch<void()> ReleaseShared;
+ synch<void()> Shared;
+ synch<void()> Exclusive;
+
+ ReaderWriter() {
+ chord(ReleaseShared, s, &ReaderWriter::release_cb);
+ chord(Shared, idle, &ReaderWriter::shared_cb1);
+ chord(Shared, s, &ReaderWriter::shared_cb2);
+ chord(Exclusive, idle, &ReaderWriter::exclusive_cb);
+ idle(); //init state
+ }
+
+ void release_cb(synch_o<void()> ReleaseShared, async_o<void(int)> sn) {
+ if(sn == 1) idle();
+ else s(sn-1);
+ }
+ void shared_cb1(synch_o<void()> Shared, async_o<void()> idl) {
+ s(1);
+ }
+ void shared_cb2(synch_o<void()> Shared, async_o<void(int)> sn) {
+ s(sn+1);
+ }
+ void exclusive_cb(synch_o<void()> Exclusive, async_o<void()> idl) {
+ }
+ void ReleaseExclusive() {
+ idle();
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class client : public actor {
+ ReaderWriter &rwlock;
+ int id;
+ async<void()> run;
+public:
+ client(int i, ReaderWriter &rwl, executor *e) : actor(e), rwlock(rwl), id(i) {
+ chord(run, &client::run_cb);
+ run();
+ }
+ void run_cb(async_o<void()> r) {
+ log1.msg("one client starts running...");
+ while(true) {
+ read(); delay();
+ write(); delay();
+ }
+ }
+ void delay() {
+ thread_sleep(2);
+ }
+ void read() {
+ log1.stream() << id << " waiting to read" << logger::endl;
+ rwlock.Shared();
+ log1.stream() << id << " reading" << logger::endl;
+ delay();
+ rwlock.ReleaseShared();
+ log1.stream() << id << " finished reading" << logger::endl;
+ }
+ void write() {
+ log1.stream() << id << " waiting to write" << logger::endl;
+ rwlock.Exclusive();
+ log1.stream() << id << " writing" << logger::endl;
+ delay();
+ rwlock.ReleaseExclusive();
+ log1.stream() << id << " finished writing" << logger::endl;
+ }
+};
+
+int main(int argc, char **argv) {
+ ReaderWriter rwlock;
+ int num_thr = 5;
+ executor exec(num_thr);
+ std::vector<boost::shared_ptr<client> > cls;
+ for(int i=0; i<num_thr; i++)
+ cls.push_back(boost::shared_ptr<client>(new client(i, rwlock, &exec.execute)));
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/semaphore.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/semaphore.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,67 @@
+//
+// semaphore.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+class semaphore : public actor {
+public:
+ async<void(void)> signal;
+ synch<void(void)> wait;
+ semaphore() {
+ chord(wait, signal, &semaphore::wait_cb);
+ }
+ void wait_cb(synch_o<void(void)> wait, async_o<void(void)> signal) {
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ async<void(int,semaphore&)> task;
+ Demo(executor *e) : actor(e) {
+ chord(task, &Demo::task_cb);
+ }
+ void task_cb(async_o<void(int,semaphore&)> task) {
+ for(int i=0; i<10; i++) {
+ log1.stream() << "Task " << task.arg1 << logger::endl;
+ thread_sleep(task.arg1 * 1);
+ }
+ task.arg2.signal();
+ }
+};
+
+int main(int argc, char **argv) {
+ semaphore sema;
+ executor exec(2);
+ Demo demo(&exec.execute);
+ demo.task(1,sema);
+ demo.task(2,sema);
+ for(int i=0; i<10; i++) {
+ log1.stream() << "main..." << logger::endl;
+ thread_sleep(1);
+ }
+ log1.stream() << "wait for tasks to finish" << logger::endl;
+ sema.wait();
+ sema.wait();
+ log1.stream() << "both tasks finish" << logger::endl;
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/func_api/spawner1.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/spawner1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,50 @@
+//
+// spawner1.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <string>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class spawner : public actor {
+public:
+ async<void(std::string)> spawn;
+ void run(async_o<void(std::string)> str) {
+ for(int i=0; i<6; i++) {
+ log1.msg(str.arg1);
+ thread_sleep(1);
+ }
+ }
+ spawner(executor *e) : actor(e) {
+ chord(spawn, &spawner::run);
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(2);
+ spawner sched(&exec.execute);
+ sched.spawn("thread 1");
+ sched.spawn("thread 2");
+ thread_sleep(5);
+ exec.shutdown();
+ log1.msg("...main thread exits...");
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/spawner2.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/spawner2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,43 @@
+//
+// spawner2.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <string>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+void run(std::string str) {
+ for(int i=0; i<6; i++) {
+ log1.msg(str);
+ thread_sleep(1);
+ }
+}
+
+int main(int argc, char **argv) {
+ executor exec(2);
+ async_p<executor::task> &spawn(exec.execute);
+ spawn(boost::bind(run, "thread 1"));
+ spawn(boost::bind(run, "thread 2"));
+ thread_sleep(5);
+ exec.shutdown();
+ log1.msg("...main thread exits...");
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/thread_safe_events/event1.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/thread_safe_events/event1.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,147 @@
+//
+// event1.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class event: public actor {
+public:
+ typedef boost::function<void(V)> subscriber;
+ struct subscription_data {
+ subscriber callback_;
+ subscription_data(subscriber cb) : callback_(cb) {}
+ };
+ typedef boost::shared_ptr<subscription_data> subscription;
+private:
+ std::vector<subscription> subs_;
+ async<void()> ready;
+ async<void(subscription)> subscribe_priv;
+public:
+ async<void(V)> post;
+ subscription subscribe(subscriber cb) {
+ subscription sub(new subscription_data(cb));
+ subscribe_priv(sub);
+ return sub;
+ }
+ async<void(subscription)> unsubscribe;
+ void operator()(V v) { post(v); }
+ event(executor *e) : actor(e) {
+ //post chord has lowest priority so that sub/unsub messages will be processed first
+ chord(post, ready, &event::post_cb, 2);
+ chord(subscribe_priv, ready, &event::sub_cb);
+ //unsubscribe chord has lower priority so subscribe call will be processed first
+ chord(unsubscribe, ready, &event::unsub_cb,1);
+ ready();
+ }
+private:
+ void post_cb(async_o<void(V)> post, async_o<void()> r) {
+ for(size_t i=0; i<subs_.size(); i++)
+ subs_[i]->callback_(post.arg1);
+ ready();
+ }
+ void sub_cb(async_o<void(subscription)> sub, async_o<void()> r) {
+ subs_.push_back(sub.arg1);
+ ready();
+ }
+ void unsub_cb(async_o<void(subscription)> unsub, async_o<void()> r) {
+ typename std::vector<subscription>::iterator iter;
+ if((iter = std::find(subs_.begin(), subs_.end(), unsub.arg1)) != subs_.end()) {
+ subs_.erase(iter);
+ }
+ ready();
+ }
+};
+
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+void evt_consumer2(std::string evt_data) {
+ log1.stream() << "evt_consumer2 recv: " << evt_data << logger::endl;
+}
+
+class Demo : public actor {
+public:
+ event<std::string> evt;
+ async<void()> producer;
+ async<void(int)> consumer;
+ Demo(executor *e) : actor(e), evt(e) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<10; i++) {
+ ostr << i;
+ log1.stream() << "producer asynchronously sends evt [" << i << "]" << logger::endl;
+ evt(ostr.str());
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void(int)> c) {
+ event<std::string>::subscription sub;
+ int times = (c.arg1 == 1)?10:5;
+ for(int i=0; i<times; i++) {
+ if (c.arg1 == 1) {
+ if(i % 2 == 0) {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously subscribe to event " << logger::endl;
+ sub = evt.subscribe(boost::bind(&Demo::evt_consumer1, this, _1));
+ }
+ else {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously un-subscribe to event " << logger::endl;
+ evt.unsubscribe(sub);
+ }
+ thread_sleep(1);
+ } else {
+ if(i % 2 == 1) {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously subscribe to event " << logger::endl;
+ sub = evt.subscribe(&evt_consumer2);
+ }
+ else {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously un-subscribe to event " << logger::endl;
+ evt.unsubscribe(sub);
+ }
+ thread_sleep(2);
+ }
+ }
+ }
+
+ void evt_consumer1(std::string evt_data) {
+ log1.stream() << "evt_consumer1 recv: " << evt_data << logger::endl;
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(5); //3 threads for producer(1)/consumers(2) and 2 for other async tasks
+ Demo demo(&exec.execute);
+ demo.producer();
+ demo.consumer(1);
+ demo.consumer(2);
+ //main thread have to wait about 10 secs here, other executor's threads will exit
+ //and Demo will fail
+ thread_sleep(10);
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/thread_safe_events/event2.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/thread_safe_events/event2.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,155 @@
+//
+// event2.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class event: public actor {
+public:
+ typedef boost::function<void(V)> subscriber;
+ struct subscription_data {
+ subscriber callback_;
+ subscription_data(subscriber cb) : callback_(cb) {}
+ };
+ typedef boost::shared_ptr<subscription_data> subscription;
+private:
+ std::vector<subscription> subs_;
+ async<void()> ready;
+ async<void(subscription)> subscribe_priv;
+ async<void(V,int)> post_priv;
+public:
+ subscription subscribe(subscriber cb) {
+ subscription sub(new subscription_data(cb));
+ subscribe_priv(sub);
+ return sub;
+ }
+ async<void(subscription)> unsubscribe;
+ void operator()(V v) { post(v); }
+ void post(V v) { post_priv(v, 0); }
+ event(executor *e) : actor(e) {
+ //post chord has the lowest priority so that sub/unsub msgs will be processed first
+ chord(post_priv, ready, &event::post_cb);
+ chord(subscribe_priv, ready, &event::sub_cb);
+ //set unsubscribe to lower priority so subscribe call will be processed first
+ chord(unsubscribe, ready, &event::unsub_cb, 1);
+ ready();
+ }
+private:
+ void post_cb(async_o<void(V,int)> post, async_o<void()> r) {
+ subscriber cb;
+ if ((size_t)post.arg2 < subs_.size()) {
+ cb = subs_[post.arg2]->callback_;
+ if((size_t)(post.arg2+1) < subs_.size()) {
+ //start next callback in another task
+ post_priv(post.arg1, (post.arg2+1));
+ }
+ }
+ ready();
+ if(cb) cb(post.arg1);
+ }
+ void sub_cb(async_o<void(subscription)> sub, async_o<void()> r) {
+ subs_.push_back(sub.arg1);
+ ready();
+ }
+ void unsub_cb(async_o<void(subscription)> unsub, async_o<void()> r) {
+ typename std::vector<subscription>::iterator iter;
+ if((iter = std::find(subs_.begin(), subs_.end(), unsub.arg1)) != subs_.end()) {
+ subs_.erase(iter);
+ }
+ ready();
+ }
+};
+
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+void evt_consumer2(std::string evt_data) {
+ log1.stream() << "evt_consumer2 recv: " << evt_data << logger::endl;
+}
+
+class Demo : public actor {
+public:
+ event<std::string> evt;
+ async<void()> producer;
+ async<void(int)> consumer;
+ Demo(executor *e) : actor(e), evt(e) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<10; i++) {
+ ostr << i;
+ log1.stream() << "producer asynchronously sends evt [" << i << "]" << logger::endl;
+ evt(ostr.str());
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void(int)> c) {
+ event<std::string>::subscription sub;
+ int times = (c.arg1 == 1)?10:5;
+ for(int i=0; i<times; i++) {
+ if (c.arg1 == 1) {
+ if(i % 2 == 0) {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously subscribe to event " << logger::endl;
+ sub = evt.subscribe(boost::bind(&Demo::evt_consumer1, this, _1));
+ }
+ else {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously un-subscribe to event " << logger::endl;
+ evt.unsubscribe(sub);
+ }
+ thread_sleep(1);
+ } else {
+ if(i % 2 == 1) {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously subscribe to event " << logger::endl;
+ sub = evt.subscribe(&evt_consumer2);
+ }
+ else {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously un-subscribe to event " << logger::endl;
+ evt.unsubscribe(sub);
+ }
+ thread_sleep(2);
+ }
+ }
+ }
+
+ void evt_consumer1(std::string evt_data) {
+ log1.stream() << "evt_consumer1 recv: " << evt_data << logger::endl;
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(5); //3 threads for producer(1)/consumers(2) and 2 for other async tasks
+ Demo demo(&exec.execute);
+ demo.producer();
+ demo.consumer(1);
+ demo.consumer(2);
+ //main thread have to wait about 10 secs here, other executor's threads will exit
+ //and Demo will fail
+ thread_sleep(10);
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/thread_safe_events/event3.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/thread_safe_events/event3.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,155 @@
+//
+// event1.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class event: public actor {
+public:
+ typedef boost::function<void(V)> subscriber;
+ struct subscription_data {
+ subscriber callback_;
+ subscription_data(subscriber cb) : callback_(cb) {}
+ };
+ typedef boost::shared_ptr<subscription_data> subscription;
+private:
+ std::vector<subscription> subs_;
+ async<void()> ready;
+ async<void()> subscription_empty;
+ synch<void()> process_subscription;
+ async<void(subscription)> subscribe_priv;
+public:
+ synch<void(V)> post;
+ subscription subscribe(subscriber cb) {
+ subscription sub(new subscription_data(cb));
+ subscribe_priv(sub);
+ return sub;
+ }
+ async<void(subscription)> unsubscribe;
+ void operator()(V v) { post(v); }
+ event() {
+ chord(post, ready, &event::post_cb);
+ chord(process_subscription, subscribe_priv, &event::sub_cb);
+ //set unsubscribe to lower priority so subscribe call will be processed first
+ chord(process_subscription, unsubscribe, &event::unsub_cb,1);
+ //create a lowest priority chord for stopping process_subscription recursion when all subs are processed
+ chord(process_subscription, subscription_empty, &event::sub_empty_cb,2);
+ ready();
+ subscription_empty();
+ }
+private:
+ void post_cb(synch_o<void(V)> post, async_o<void()> r) {
+ process_subscription();
+ for(size_t i=0; i<subs_.size(); i++)
+ subs_[i]->callback_(post.arg1);
+ ready();
+ }
+ void sub_cb(synch_o<void()> proc, async_o<void(subscription)> sub) {
+ subs_.push_back(sub.arg1);
+ process_subscription();
+ }
+ void unsub_cb(synch_o<void()> proc, async_o<void(subscription)> unsub) {
+ typename std::vector<subscription>::iterator iter;
+ if((iter = std::find(subs_.begin(), subs_.end(), unsub.arg1)) != subs_.end()) {
+ subs_.erase(iter);
+ }
+ process_subscription();
+ }
+ void sub_empty_cb(synch_o<void()> proc, async_o<void()> empty) {
+ subscription_empty();
+ }
+};
+
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+void evt_consumer2(std::string evt_data) {
+ log1.stream() << "evt_consumer2 recv: " << evt_data << logger::endl;
+}
+
+class Demo : public actor {
+public:
+ event<std::string> evt;
+ async<void()> producer;
+ async<void(int)> consumer;
+ Demo(executor *e) : actor(e) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_o<void()> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<10; i++) {
+ ostr << i;
+ log1.stream() << "producer synchronously sends evt [" << i << "]" << logger::endl;
+ evt(ostr.str());
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_o<void(int)> c) {
+ event<std::string>::subscription sub;
+ int times = (c.arg1 == 1)?10:5;
+ for(int i=0; i<times; i++) {
+ if (c.arg1 == 1) {
+ if(i % 2 == 0) {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously subscribe to event " << logger::endl;
+ sub = evt.subscribe(boost::bind(&Demo::evt_consumer1, this, _1));
+ }
+ else {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously un-subscribe to event " << logger::endl;
+ evt.unsubscribe(sub);
+ }
+ thread_sleep(1);
+ } else {
+ if(i % 2 == 1) {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously subscribe to event " << logger::endl;
+ sub = evt.subscribe(&evt_consumer2);
+ }
+ else {
+ log1.stream() << "consumer[" << c.arg1 << "] asynchronously un-subscribe to event " << logger::endl;
+ evt.unsubscribe(sub);
+ }
+ thread_sleep(2);
+ }
+ }
+ }
+
+ void evt_consumer1(std::string evt_data) {
+ log1.stream() << "evt_consumer1 recv: " << evt_data << logger::endl;
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(5); //3 threads for producer(1)/consumers(2) and 2 for other async tasks
+ Demo demo(&exec.execute);
+ demo.producer();
+ demo.consumer(1);
+ demo.consumer(2);
+ //main thread have to wait about 10 secs here, other executor's threads will exit
+ //and Demo will fail
+ thread_sleep(10);
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/func_api/with_stl.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/func_api/with_stl.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,56 @@
+//
+// with_stl.cpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <vector>
+#include <algorithm>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <boost/utility.hpp>
+#include <boost/function.hpp>
+#include <boost/join/join.hpp>
+
+using namespace boost::join;
+
+logger log1("log");
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class workers : public actor {
+public:
+ async<void(int)> do_it;
+ workers(executor *e) : actor(e) {
+ chord(do_it, &workers::chord_body);
+ }
+private:
+ void chord_body(async_o<void(int)> do_it) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "do_it: " << do_it.arg1 << logger::endl;
+ thread_sleep(1);
+ }
+ }
+};
+
+int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+int size = sizeof(data) / sizeof(int);
+
+int main(int argc, char **argv) {
+ executor exec(5);
+ workers w(&exec.execute);
+ std::for_each(data, data+size, boost::bind(boost::ref(w.do_it), _1));
+ //or
+ //std::for_each(data, data+size, boost::function<void(int)>(boost::ref(w.do_it)));
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/port_api/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/port_api/Jamfile.v2 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,12 @@
+
+project
+ : requirements
+ <library>/boost/thread//boost_thread
+ <define>BOOST_ALL_NO_LIB=1
+ <threading>multi
+ ;
+
+obj buffer.obj : buffer.cpp ;
+exe buffer : buffer.obj ;
+obj bounded_buffer.obj : bounded_buffer.cpp ;
+exe bounded_buffer : bounded_buffer.obj ;

Added: sandbox/join/libs/join/examples/port_api/bounded_buffer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/port_api/bounded_buffer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,90 @@
+//
+// bounded_buffer.cpp
+//
+// Copyright (c) 2007 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/join/join.hpp>
+#include <iostream>
+
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename T>
+class BufferN : public actor {
+private:
+ async_p<void> token;
+ async_p<T> value;
+
+public:
+ synch_p<void,T> put;
+ synch_p<T,void> get;
+
+ BufferN(int sz) {
+ chord(put, token, &BufferN::put_cb);
+ chord(get, value, &BufferN::get_cb);
+ for(int i=0; i<sz; i++)
+ token();
+ }
+ void put_cb(synch_v<void,T> put, async_v<void> tok) {
+ value(put);
+ }
+ T get_cb(synch_v<T,void> get, async_v<T> val) {
+ token();
+ return val;
+ }
+};
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Test : public actor {
+public:
+ BufferN<int> buf_;
+ async_p<void> producer;
+ async_p<void> consumer1;
+ async_p<void> consumer2;
+ Test(executor *e) : actor(e), buf_(5) {
+ chord(producer, &Test::producer_cb);
+ chord(consumer1, &Test::consumer1_cb);
+ chord(consumer2, &Test::consumer2_cb);
+ }
+ void producer_cb(async_v<void> p) {
+ for(int i=0; i<2000000; i++) {
+ buf_.put(i);
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ //thread_sleep(2);
+ }
+ }
+ void consumer1_cb(async_v<void> c) {
+ for(int i=0; i<1000000; i++) {
+ log1.stream() << "consumer1 recvs [" << buf_.get() << "]" << logger::endl;
+ //thread_sleep(3);
+ }
+ }
+ void consumer2_cb(async_v<void> c) {
+ for(int i=0; i<1000000; i++) {
+ log1.stream() << "consumer2 recvs [" << buf_.get() << "]" << logger::endl;
+ //thread_sleep(1);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ executor exec(3);
+ Test test(&exec.execute);
+ test.producer();
+ test.consumer1();
+ test.consumer2();
+ exec.shutdown();
+ return 0;
+}
+

Added: sandbox/join/libs/join/examples/port_api/buffer.cpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/port_api/buffer.cpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,85 @@
+//
+// buffer.cpp
+//
+// Copyright (c) 2007 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <boost/join/join.hpp>
+
+//using namespace boost;
+using namespace boost::join;
+
+logger log1("log");
+
+template <typename V>
+class buffer: public actor {
+public:
+ async_p<V> put;
+ synch_p<V,void> get;
+ buffer() {
+ chord(get, put, &buffer::chord_body);
+ log1.msg("buffer constructed");
+ }
+ V chord_body(synch_v<V,void> get, async_v<V> put) {
+ return put.arg1;
+ }
+};
+
+void hello_world(buffer<std::string> &b) {
+ b.put("hello");
+ b.put("world");
+ log1.msg(b.get()+" ");
+ log1.msg(b.get());
+}
+
+void thread_sleep(int sec) {
+ boost::xtime xt;
+ boost::xtime_get(&xt, boost::TIME_UTC);
+ xt.sec += sec;
+ boost::thread::sleep(xt);
+}
+
+class Demo : public actor {
+public:
+ buffer<std::string> &buf_;
+ async_p<void> producer;
+ async_p<void> consumer;
+ Demo(buffer<std::string> &b, executor *e) : actor(e, 0, 0), buf_(b) {
+ chord(producer, &Demo::producer_cb);
+ chord(consumer, &Demo::consumer_cb);
+ }
+ void producer_cb(async_v<void> p) {
+ std::ostringstream ostr;
+ for(int i=0; i<5; i++) {
+ ostr << i;
+ buf_.put(ostr.str());
+ log1.stream() << "producer sends [" << i << "]" << logger::endl;
+ ostr.str("");
+ thread_sleep(1);
+ }
+ }
+ void consumer_cb(async_v<void> c) {
+ for(int i=0; i<5; i++) {
+ log1.stream() << "consumer recvs [" << buf_.get() << "]" << logger::endl;
+ thread_sleep(2);
+ }
+ }
+};
+
+int main(int argc, char **argv) {
+ buffer<std::string> b;
+ hello_world(b);
+
+ executor exec(2); //spawn 2 threads for executor thread pool
+ Demo demo(b, &exec.execute);
+ demo.producer();
+ demo.consumer();
+ exec.shutdown();
+ return 0;
+}

Added: sandbox/join/libs/join/examples/port_api/executor.hpp
==============================================================================
--- (empty file)
+++ sandbox/join/libs/join/examples/port_api/executor.hpp 2009-03-07 13:45:13 EST (Sat, 07 Mar 2009)
@@ -0,0 +1,104 @@
+//
+// boost/join/executor.hpp
+//
+// Copyright (c) 2007, 2008 Yigong Liu (yigongliu at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_JOIN_SIMPLE_EXECUTOR_HPP
+#define BOOST_JOIN_SIMPLE_EXECUTOR_HPP
+
+#include <iostream>
+#include <map>
+#include <boost/thread.hpp>
+#include <boost/join/join.hpp>
+
+namespace boost {
+ namespace join {
+
+ template <template <size_t> class scheduler=sched_first_match, size_t sz=32>
+ class executor_t : public actor_t<async_p<typename actor_base::callable>, scheduler, sz> {
+ public:
+ typedef scheduler<sz> sched_type;
+ typedef actor_t<async_p<typename actor_base::callable>, scheduler, sz> actor_type;
+ typedef typename actor_type::callable task;
+
+ //api: one default task queue
+ async_p<task> execute;
+ synch_p<void,void> shutdown;
+
+ executor_t(int num, const char *name = 0) :
+ actor_type(0, 0, name) {
+ chord(run, execute, &executor_t::exec_cb);
+ chord(run, stopped, &executor_t::stop_cb);
+ chord(shutdown, started, &executor_t::shutdown_cb);
+ chord(shutdown, stopped, &executor_t::stopped_cb);
+ for(int i=0; i<num; i++)
+ threads_.create_thread(boost::bind(&executor_t::main_loop, this));
+ started(); //init state
+ }
+ ~executor_t() {
+ shutdown();
+ }
+
+ private:
+ synch_p<bool,void> run;
+ //executor states
+ async_p<void> started;
+ async_p<void> stopped;
+ //thread pool
+ boost::thread_group threads_;
+
+ //entry func of each thread - a loop which exists when no tasks in execute queue and shutdown
+ void main_loop(void) {
+ this->log.msg("a thread starts...");
+ while(run()) {}
+ this->log.msg("a thread exits...");
+ }
+ bool exec_cb(synch_v<bool,void> run, async_v<task> exec) {
+ this->log.msg("start one task...");
+ try {
+ (exec.arg1)();
+ }
+ catch (join_exception &je) {
+ this->log.msg(je.what());
+ }
+ catch (...) {
+ this->log.msg("UNKNOWN exceptions happen inside a executor thread, ignore.");
+ }
+ this->log.msg("finish one task...");
+ return true; //worker thread continue
+ }
+ bool stop_cb(synch_v<bool,void> run, async_v<void> stopd) {
+ stopped();
+ return false; //worker thread exit
+ }
+ void shutdown_cb(synch_v<void,void> shdn, async_v<void> started) {
+ this->log.msg("shutdown...");
+ stopped();
+ //waiting for the threads to exit
+ this->log.msg("wait...");
+ threads_.join_all();
+ this->log.msg("all threads exit, done...");
+ }
+ void stopped_cb(synch_v<void,void> shdn, async_v<void> stopd) {
+ this->log.msg("stopped...");
+ stopped();
+ }
+ };
+
+ //define a default executor_t
+ class executor : public executor_t<> {
+ public:
+ executor(int num, const char *name = 0) :
+ executor_t<>(num, name)
+ {
+ }
+ };
+
+ }
+}
+
+#endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk