sigx++  2.0.1
signal_wrapper_base.h
Go to the documentation of this file.
1 #ifndef _SIGX_SIGNAL_BASE_HPP_
2 #define _SIGX_SIGNAL_BASE_HPP_
3 
4 /*
5  * Copyright 2006 Klaus Triendl
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21 */
22 
23 #include <tr1/memory>
24 #include <utility> // std::pair
25 #include <sigxconfig.h>
26 #include <sigx/fwddecl.h>
27 #include <sigx/static_assert.h>
31 #include <sigx/auto_tunneler.h>
32 
33 
34 namespace sigx
35 {
36 
44 {
45 
46 protected:
51  // non-virtual by design
52  ~signal_wrapper_base() throw();
53  signal_wrapper_base(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr<signal_source_base>& _A_sigsource) throw();
54 
55  // implicit copy ctor is fine
56  // implicit assignment operator is fine
57 
58 
59 
64  std::pair<connection_wrapper, std::tr1::shared_ptr<sigc_connection_ptr> >
65  prepare_connection(const tunnel_base& _A_tunnel) const;
66 
71  template<typename T_functor, typename T_functor_conn_handler>
72  connection_wrapper connect(const T_functor& _A_func, const T_functor_conn_handler& _A_func_conn_handler) const;
73 
74 protected:
79  std::tr1::shared_ptr<signal_source_base> m_sigsource;
80 };
81 
82 
83 template<typename T_functor, typename T_functor_conn_handler>
84 connection_wrapper signal_wrapper_base::connect(const T_functor& _A_func, const T_functor_conn_handler& _A_func_conn_handler) const
85 {
86  typedef internal::auto_tunneler<T_functor> auto_tunneler_t;
87 
88  // passed in functor must not be a slot or adapt a slot;
89  // we have to apply this restriction because slots might have bound
90  // trackables that can cause non-threadsafe access to the passed in slot
91  // which will live in the context of the server thread
92  SIGX_STATIC_ASSERT((sigx::internal::is_or_adapts_slot<T_functor>::value == false));
93 
94  // toplevel functor must be a tunnel functor
95  SIGX_STATIC_ASSERT((sigc::is_base_and_derived<tunnel_base, typename auto_tunneler_t::functor_type>::value == true));
96 
97  typename auto_tunneler_t::functor_type functor2connect =
98  auto_tunneler_t::auto_open_tunnel(_A_func);
99  // the validity of tunnel functors doesn't get tracked by the sigc++ default visit_each mechanism,
100  // we activate sigx' own validity tracking, which is threadsafe
101  functor2connect.activate_validity_tracking();
102 
103  const std::pair<connection_wrapper, std::tr1::shared_ptr<sigc_connection_ptr> >& ret =
105 
106  try
107  {
108  // now send a message to the server thread (holding the signal the client thread wants
109  // to connect to);
110  // the message gets handled by a special function handling the connection
112  _A_func_conn_handler,
113  m_disp
114  )
115  // transfer:
116  // - the prepared connection pointer
117  // - the signal source
118  // - the functor to connect
119  //
120  // The functor to connect is the tunnel functor wrapped in an exception catcher
121  // that catches a bad_dispatcher error.
122  // This is necessary because the dispatcher of the tunnel functor (that is
123  // probably the dispatcher running in the context of the calling thread)
124  // could go out of scope (e.g. because the calling thread finishes), but
125  // the tunnel functor is still connected to the server thread's signal.
126  // Before the server thread gets the disconnect message (which is
127  // triggered by the dispatcher or by trackable objects of the calling
128  // thread going out of scope) it might emit the signal
129  // on this tunnel functor and gets a bad_dispatcher error thrown.
130  // Because the programmer can't really influence this situation, sigx
131  // catches the exception.
132  ( ret.second, m_sigsource,
133  sigc::exception_catch(functor2connect,
134  // use a catcher here because the signal might get emitted
135  // while the dispatcher the tunnel functor operates on dies
136  // before the tunnel functor is disconnected from that signal
137  // (btw: this is done internally by the validity trackable
139  )
140  );
141  }
142  catch (...)
143  {
144  // message dispatching failed at the call site;
145  // reset pointer to the sigc connection to make the connection invalid
146  *ret.second = 0;
147  throw;
148  }
149 
150  return ret.first;
151 }
152 
153 
154 } // namespace sigx
155 
156 
157 #endif // end file guard