Orocos Real-Time Toolkit  2.9.0
SignalBase.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Wed Jan 18 14:11:39 CET 2006 SignalBase.cxx
3 
4  SignalBase.cxx - description
5  -------------------
6  begin : Wed January 18 2006
7  copyright : (C) 2006 Peter Soetens
8  email : peter.soetens@mech.kuleuven.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #include "SignalBase.hpp"
40 #include <boost/bind.hpp>
41 
42 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
43 #else
44 #include "../os/MutexLock.hpp"
45 #endif
46 
47 namespace RTT {
48  namespace internal {
49 
50  // ConnectionBase
51 
54 
56  void ConnectionBase::deref() { if ( refcount.dec_and_test() ) delete this; }
57 
59  : mconnected(false), m_sig(sig)
60  , refcount(0)
61  {
62  }
63 
65  }
66 
68  if( !m_sig ) return false;
69  mconnected = true;
70  return true;
71  }
73  if (!m_sig) return false;
74  mconnected = false;
75  return true;
76  }
78  if( !m_sig ) return;
79  mconnected = false;
80  SignalBase* copy = m_sig;
81  m_sig = 0;
82  copy->conn_destroy(this);
83  // after this point this object may be destructed !
84  }
85 
86  // SignalBase
87 
89  // allocate empty slot in list.
90 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
91  mconnections.grow(1);
92 #else
93 #ifdef ORO_SIGNAL_USE_RT_LIST
94  mconnections.rt_grow(1);
95 #else
96  connection_t d(0);
97  mconnections.push_back( d );
98 #endif
99 #endif
100  this->conn_connect( conn );
101  }
102 
104  assert( conn.get() && "virtually impossible ! only connection base should call this function !" );
105 
106 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
107  mconnections.append( conn );
108 #else
109  // derived class must make sure that list contained enough list items !
110  //assert( itend != mconnections.end() );
111 
112  // connection (push_back) in emit() does not invalidate iterators, so this
113  // function is straightforwardly implemented.
114  os::MutexLock lock(m);
115 #ifdef ORO_SIGNAL_USE_RT_LIST
116  mconnections.push_back( conn );
117 #else
118  iterator tgt;
119  connection_t empty;
120  // find empty slot
121  if ( (tgt = std::find( mconnections.begin(),
122  mconnections.end(),
123  empty )) != mconnections.end() ) {
124  *tgt = conn;
125  }
126 #endif
127 #endif
128  }
129 
131  this->conn_disconnect(conn);
132  // increase number of connections destroyed.
133 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
134  // free memory
135  mconnections.shrink(1);
136 #else
137 #ifdef ORO_SIGNAL_USE_RT_LIST
138  // free memory
139  mconnections.rt_shrink(1);
140 #else
141  ++concount;
142 #endif
143 #endif
144  }
145 
147  assert( conn.get() && "virtually impossible ! only connection base should call this function !" );
148 
149 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
150  mconnections.erase( conn );
151 #else
152  iterator tgt;
153  // avoid invalidating iterator of emit() upon self or cross removal of conn.
154  os::MutexLock lock(m);
155  if ( (tgt = std::find( mconnections.begin(),
156  mconnections.end(),
157  conn)) != mconnections.end() ) {
158 #ifdef ORO_SIGNAL_USE_RT_LIST
159  if ( !emitting ) {
160  mconnections.erase( tgt ); // safe to remove we hold mutex + no self removal.
161  return;
162  }
163  // only done when in emit(). cleanup() is guaranteed to be called afterwards.
164  ++disconcount; // used in cleanup() to detect self-disconnections.
165 #endif
166  // cfr for loop in cleanup()
167  connection_t d(0);
168  *tgt = d; //clear out, no erase, keep all iterators valid !
169  }
170 #endif
171  }
172 
173 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
174  // NOP
175 #else
176  void SignalBase::cleanup() {
177  // this is called from within emit().
178  // mutex already locked !
179 #ifdef ORO_SIGNAL_USE_RT_LIST
180  // this construct allows self+cross removal (cfr conn_disconnect) in emit().
181  iterator it = mconnections.begin();
182  iterator newit(it);
183  const_iterator end = mconnections.end();
184  for (; newit != end && disconcount > 0 ; it=newit ) {
185  if (!*it) {
186  // it & newit become invalid after erase !
187  // do not change this construct unthoughtfully !
188  if ( it == mconnections.begin() ) {
189  mconnections.erase( it );
190  newit = mconnections.begin();
191  } else {
192  ++newit;
193  mconnections.erase( it );
194  }
195  --disconcount;
196  } else
197  ++newit;
198  }
199 #else
200  while ( concount > 0 ) {
201  mconnections.erase( --(mconnections.end()) );
202  --concount;
203  }
204 #endif
205  // remove zeros. too expensive ?
206  //itend = std::remove( mconnections.begin(), itend, 0);
207  }
208 #endif
209 
212  mconnections(4) // this is a 'sane' starting point, this number will be grown if required.
213 #else
214 #ifdef ORO_SIGNAL_USE_RT_LIST
215  disconcount(0)
216 #else
217  concount(0)
218 #endif
219 #endif
220  ,emitting(false)
221  {
222 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
223  // NOP
224 #else
225  itend = mconnections.end();
226 #endif
227  }
228 
230  // call destroy on all connections.
231  destroy();
232  }
233 
234 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
235  static void disconnectImpl( const ConnectionBase::shared_ptr& c ) {
236  c->disconnect();
237  }
238 #endif
239 
241 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
242  mconnections.apply( boost::bind(&disconnectImpl, _1 ) );
243 #else
244  // avoid invalidating iterator
245  os::MutexLock lock(m);
246  for( iterator tgt = mconnections.begin(); tgt != mconnections.end(); ++tgt)
247  (*tgt)->disconnect();
248 #endif
249  }
250 
252  while ( !mconnections.empty() ) {
253  if ( mconnections.front() )
254  mconnections.front()->destroy(); // this calls-back conn_disconnect.
255 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
256  // NOP
257 #else
258 #ifdef ORO_SIGNAL_USE_RT_LIST
259  // NOP
260 #else
261  mconnections.erase( mconnections.begin() );
262 #endif
263 #endif
264  }
265  }
266 
267  void SignalBase::reserve( size_t conns ) {
268 #ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
269  mconnections.reserve( conns );
270 #endif
271  }
272 
273  }
274 }
value_t front() const
Returns the first element of the list.
void ref()
Increase the reference count by one.
Definition: SignalBase.cpp:55
The base signal class which stores connection objects.
Definition: SignalBase.hpp:128
void reserve(size_t conns)
Reserves memory for a number of connections.
Definition: SignalBase.cpp:267
void conn_destroy(connection_t conn)
Definition: SignalBase.cpp:130
void reserve(size_t lsize)
Reserve a capacity for this list.
bool empty() const
Returns true if this list is empty.
void RTT_API intrusive_ptr_add_ref(RTT::internal::IntrusiveStorage *p)
virtual ~SignalBase()
Deletes this Signal and will destroy all connections and handles of this object.
Definition: SignalBase.cpp:229
void RTT_API intrusive_ptr_release(RTT::internal::IntrusiveStorage *p)
boost::intrusive_ptr< ConnectionBase > shared_ptr
Definition: SignalBase.hpp:108
bool dec_and_test()
Decrement and test if the result is zero.
Definition: Atomic.hpp:104
void apply(Function func)
Apply a function to the elements of the whole list.
#define ORO_SIGNAL_USE_LIST_LOCK_FREE
Definition: SignalBase.hpp:50
void disconnect()
Disconnects all connections.
Definition: SignalBase.cpp:240
void conn_disconnect(connection_t conn)
Definition: SignalBase.cpp:146
void conn_connect(connection_t conn)
Definition: SignalBase.cpp:103
void destroy()
Destroys all connections.
Definition: SignalBase.cpp:251
void conn_setup(connection_t conn)
Definition: SignalBase.cpp:88
A connection &#39;memorises&#39; the connection between an event and an event handler function.
Definition: SignalBase.hpp:80
os::AtomicInt refcount
We require an internal refcount to ease self-addition and removal of this connection.
Definition: SignalBase.hpp:92
void deref()
Decrease the reference count by one and delete this on zero.
Definition: SignalBase.cpp:56
connections_list mconnections
Definition: SignalBase.hpp:154
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
ConnectionBase::shared_ptr connection_t
Definition: SignalBase.hpp:131
bool erase(value_t item)
Erase a value from the list.
MutexLock is a scope based Monitor, protecting critical sections with a Mutex object through locking ...
Definition: MutexLock.hpp:51
ConnectionBase(SignalBase *sig)
Definition: SignalBase.cpp:58