signal_wrapper_base.h

Go to the documentation of this file.
00001 #ifndef _SIGX_SIGNAL_BASE_HPP_
00002 #define _SIGX_SIGNAL_BASE_HPP_
00003 
00004 /*
00005  * Copyright 2006 Klaus Triendl
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Library General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Library General Public
00018  * License along with this library; if not, write to the Free 
00019  * Software Foundation, 51 Franklin Street, Fifth Floor, 
00020  * Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <tr1/memory>
00024 #include <utility> // std::pair
00025 #include <sigxconfig.h>
00026 #include <sigx/fwddecl.h>
00027 #include <sigx/static_assert.h>
00028 #include <sigx/nonheapallocatable.h>
00029 #include <sigx/shared_dispatchable.h>
00030 #include <sigx/connection_wrapper.h>
00031 #include <sigx/auto_tunneler.h>
00032 
00033 
00034 namespace sigx
00035 {
00036 
00043 class SIGX_API signal_wrapper_base: nonheapallocatable
00044 {
00045 
00046 protected:
00050     signal_wrapper_base();
00051     // non-virtual by design
00052     ~signal_wrapper_base() throw();
00053     signal_wrapper_base(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr<signal_source_base>& _A_sigsource) throw();
00054 
00055     // implicit copy ctor is fine
00056     // implicit assignment operator is fine
00057 
00058 
00059 
00064     std::pair<connection_wrapper, std::tr1::shared_ptr<sigc_connection_ptr> >
00065     prepare_connection(const tunnel_base& _A_tunnel) const;
00066 
00071     template<typename T_functor, typename T_functor_conn_handler>
00072     connection_wrapper connect(const T_functor& _A_func, const T_functor_conn_handler& _A_func_conn_handler) const;
00073 
00074 protected:
00077     shared_dispatchable m_disp;
00079     std::tr1::shared_ptr<signal_source_base> m_sigsource;
00080 };
00081 
00082 
00083 template<typename T_functor, typename T_functor_conn_handler>
00084 connection_wrapper signal_wrapper_base::connect(const T_functor& _A_func, const T_functor_conn_handler& _A_func_conn_handler) const
00085 {
00086     typedef internal::auto_tunneler<T_functor> auto_tunneler_t;
00087     
00088     // passed in functor must not be a slot or adapt a slot;
00089     // we have to apply this restriction because slots might have bound
00090     // trackables that can cause non-threadsafe access to the passed in slot
00091     // which will live in the context of the server thread
00092     SIGX_STATIC_ASSERT((sigx::internal::is_or_adapts_slot<T_functor>::value == false));
00093     
00094     // toplevel functor must be a tunnel functor
00095     SIGX_STATIC_ASSERT((sigc::is_base_and_derived<tunnel_base, typename auto_tunneler_t::functor_type>::value == true));
00096 
00097     typename auto_tunneler_t::functor_type functor2connect = 
00098         auto_tunneler_t::auto_open_tunnel(_A_func);
00099     // the validity of tunnel functors doesn't get tracked by the sigc++ default visit_each mechanism, 
00100     // we activate sigx' own validity tracking, which is threadsafe
00101     functor2connect.activate_validity_tracking();
00102 
00103     const std::pair<connection_wrapper, std::tr1::shared_ptr<sigc_connection_ptr> >& ret = 
00104         signal_wrapper_base::prepare_connection(functor2connect);
00105 
00106     try
00107     {
00108         // now send a message to the server thread (holding the signal the client thread wants 
00109         // to connect to);
00110         // the message gets handled by a special function handling the connection
00111         open_tunnel_with(
00112             _A_func_conn_handler, 
00113             m_disp
00114         )
00115         // transfer:
00116         // - the prepared connection pointer
00117         // - the signal source
00118         // - the functor to connect
00119         // 
00120         // The functor to connect is the tunnel functor wrapped in an exception catcher
00121         // that catches a bad_dispatcher error.
00122         // This is necessary because the dispatcher of the tunnel functor (that is 
00123         // probably the dispatcher running in the context of the calling thread)
00124         // could go out of scope (e.g. because the calling thread finishes), but 
00125         // the tunnel functor is still connected to the server thread's signal.
00126         // Before the server thread gets the disconnect message (which is 
00127         // triggered by the dispatcher or by trackable objects of the calling 
00128         // thread going out of scope) it might emit the signal 
00129         // on this tunnel functor and gets a bad_dispatcher error thrown.
00130         // Because the programmer can't really influence this situation, sigx
00131         // catches the exception.
00132         (   ret.second, m_sigsource, 
00133             sigc::exception_catch(functor2connect, 
00134                 // use a catcher here because the signal might get emitted 
00135                 // while the dispatcher the tunnel functor operates on dies
00136                 // before the tunnel functor is disconnected from that signal
00137                 // (btw: this is done internally by the validity trackable
00138                 bad_dispatcher_catcher<typename auto_tunneler_t::functor_type::result_type>()
00139             )
00140         );
00141     }
00142     catch (...)
00143     {
00144         // message dispatching failed at the call site;
00145         // reset pointer to the sigc connection to make the connection invalid
00146         *ret.second = 0;
00147         throw;
00148     }
00149 
00150     return ret.first;
00151 }
00152 
00153 
00154 } // namespace sigx
00155 
00156 
00157 #endif // end file guard

Generated on Sun May 17 15:47:34 2009 for sigx++ by  doxygen 1.5.9