sigx++ 2.0.1
|
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