OpenWalnut
1.4.0
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #include <iostream> 00026 #include <list> 00027 #include <string> 00028 #include <sstream> 00029 #include <set> 00030 00031 #include <boost/version.hpp> 00032 #if ( BOOST_VERSION >= 104200 ) // exception.hpp is deprecated in Boost 1.42 00033 #include <boost/exception/all.hpp> 00034 #else 00035 #include <boost/exception.hpp> 00036 #endif 00037 00038 #include <boost/signals2/signal.hpp> 00039 #include <boost/signals2/connection.hpp> 00040 00041 #include "../common/exceptions/WSignalSubscriptionFailed.h" 00042 #include "WModule.h" 00043 #include "WModuleConnectorSignals.h" 00044 #include "WModuleContainer.h" 00045 #include "WModuleInputConnector.h" 00046 #include "WModuleOutputConnector.h" 00047 #include "combiner/WDisconnectCombiner.h" 00048 #include "exceptions/WModuleConnectionFailed.h" 00049 #include "exceptions/WModuleConnectionInvalid.h" 00050 #include "exceptions/WModuleConnectorsIncompatible.h" 00051 #include "exceptions/WModuleDisconnectFailed.h" 00052 #include "exceptions/WModuleConnectorModuleLockFailed.h" 00053 00054 #include "WModuleConnector.h" 00055 00056 WModuleConnector::WModuleConnector( boost::shared_ptr< WModule > module, std::string name, std::string description ): 00057 boost::enable_shared_from_this<WModuleConnector>() 00058 { 00059 // initialize members 00060 m_module = module; 00061 m_moduleName = module->getName(); 00062 00063 m_name = name; 00064 m_description = description; 00065 00066 // connect standard signals 00067 // NOTE: these signals are NOT emitted by the connector this one is connected to, since a module can't send a "connection 00068 // closed" message if the connection is closed. 00069 subscribeSignal( CONNECTION_ESTABLISHED, boost::bind( &WModuleConnector::notifyConnectionEstablished, this, _1, _2 ) ); 00070 subscribeSignal( CONNECTION_CLOSED, boost::bind( &WModuleConnector::notifyConnectionClosed, this, _1, _2 ) ); 00071 00072 signal_ConnectionEstablished.connect( getSignalHandler( CONNECTION_ESTABLISHED ) ); 00073 signal_ConnectionClosed.connect( getSignalHandler( CONNECTION_CLOSED ) ); 00074 } 00075 00076 WModuleConnector::~WModuleConnector() 00077 { 00078 disconnectAll(); 00079 00080 // cleanup 00081 signal_ConnectionEstablished.disconnect_all_slots(); 00082 signal_ConnectionClosed.disconnect_all_slots(); 00083 } 00084 00085 bool WModuleConnector::isConnectedTo( boost::shared_ptr<WModuleConnector> con ) 00086 { 00087 boost::shared_lock<boost::shared_mutex> slock; 00088 slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock ); 00089 int c1 = m_connected.count( con ); 00090 slock.unlock(); 00091 00092 slock = boost::shared_lock<boost::shared_mutex>( con->m_connectionListLock ); 00093 int c2 = con->m_connected.count( shared_from_this() ); 00094 slock.unlock(); 00095 00096 // if the count is different the connection is invalid 00097 if( c1 != c2 ) 00098 { 00099 std::ostringstream s; 00100 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed."; 00101 throw WModuleConnectionInvalid( s.str() ); 00102 } 00103 00104 return ( c1 == 1 ); 00105 } 00106 00107 unsigned int WModuleConnector::isConnected() 00108 { 00109 boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock ); 00110 int count = m_connected.size(); 00111 slock.unlock(); 00112 return count; 00113 } 00114 00115 void WModuleConnector::connect( boost::shared_ptr<WModuleConnector> con ) 00116 { 00117 boost::shared_ptr< WModule > module = m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope 00118 std::string containerName = "Unknown"; 00119 if( module ) 00120 { 00121 boost::shared_ptr< WModuleContainer > container; 00122 container = module->getAssociatedContainer(); 00123 containerName = container.get() ? container->getName() : "Unknown"; 00124 } 00125 WLogger::getLogger()->addLogMessage( "Connecting " + con->getCanonicalName() + " with " + getCanonicalName(), 00126 "ModuleContainer (" + containerName + ")", LL_INFO ); 00127 00128 // are both partners compatible to each other? 00129 if( !( con->connectable( shared_from_this() ) && connectable( con ) ) ) 00130 { 00131 std::ostringstream s; 00132 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed."; 00133 throw WModuleConnectorsIncompatible( s.str() ); 00134 } 00135 00136 // check whether they are already connected 00137 if( isConnectedTo( con ) ) 00138 { 00139 WLogger::getLogger()->addLogMessage( con->getCanonicalName() + " and " + getCanonicalName() + " are already connected.", 00140 "ModuleContainer (" + containerName + ")", LL_INFO ); 00141 return; 00142 } 00143 00144 boost::unique_lock<boost::shared_mutex> lock; 00145 boost::unique_lock<boost::shared_mutex> lockRemote; 00146 try 00147 { 00148 // get locks 00149 lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock ); 00150 lockRemote = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock ); 00151 00152 // is the input connected already? 00153 if( ( isInputConnector() && m_connected.size() ) || ( con->isInputConnector() && con->m_connected.size() ) ) 00154 { 00155 throw WModuleConnectionFailed( std::string( "Input connector already connected. Disconnect it first." ) ); 00156 } 00157 00158 m_connected.insert( con ); 00159 con->m_connected.insert( shared_from_this() ); 00160 00161 lock.unlock(); 00162 lockRemote.unlock(); 00163 } 00164 catch( const WException& e ) 00165 { 00166 lock.unlock(); 00167 lockRemote.unlock(); 00168 00169 // undo changes 00170 m_connected.erase( con ); 00171 con->m_connected.erase( con ); 00172 00173 throw e; 00174 } 00175 catch( const std::exception& e ) 00176 { 00177 lock.unlock(); 00178 lockRemote.unlock(); 00179 00180 // undo changes 00181 m_connected.erase( con ); 00182 con->m_connected.erase( con ); 00183 00184 std::ostringstream s; 00185 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed."; 00186 throw WModuleConnectionFailed( s.str() ); 00187 } 00188 catch( const boost::exception& e ) 00189 { 00190 lock.unlock(); 00191 lockRemote.unlock(); 00192 00193 // undo changes 00194 m_connected.erase( con ); 00195 con->m_connected.erase( con ); 00196 00197 std::ostringstream s; 00198 s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed."; 00199 throw WModuleConnectionFailed( s.str() ); 00200 } 00201 00202 // let them connect their signals 00203 connectSignals( con ); 00204 con->connectSignals( shared_from_this() ); 00205 00206 // signal "connection established" 00207 signal_ConnectionEstablished( shared_from_this(), con ); 00208 // signal to my partner, of course with the parameters the other way round 00209 con->signal_ConnectionEstablished( con, shared_from_this() ); 00210 } 00211 00212 void WModuleConnector::connectSignals( boost::shared_ptr<WModuleConnector> /*con*/ ) 00213 { 00214 // Add extra signal- connections here that are COMMON to ALL connectors. 00215 // NOTE: connection established and connection closed are not signals to connect, since you can not send an connection closed 00216 // signal to somebody with whom you are not connected anymore ;-). 00217 } 00218 00219 void WModuleConnector::disconnectSignals( boost::shared_ptr<WModuleConnector> /*con*/ ) 00220 { 00221 // The base module does not subscribe to any signal -> no disconnection needed here 00222 } 00223 00224 boost::signals2::connection WModuleConnector::subscribeSignal( MODULE_CONNECTOR_SIGNAL signal, 00225 t_GenericSignalHandlerType notifier ) 00226 { 00227 switch( signal) 00228 { 00229 case CONNECTION_ESTABLISHED: 00230 return signal_ConnectionEstablished.connect( notifier ); 00231 case CONNECTION_CLOSED: 00232 return signal_ConnectionClosed.connect( notifier ); 00233 default: 00234 std::ostringstream s; 00235 s << "Could not subscribe to unknown signal. You need to implement this signal type explicitly."; 00236 throw WSignalSubscriptionFailed( s.str() ); 00237 break; 00238 } 00239 } 00240 00241 const t_GenericSignalHandlerType WModuleConnector::getSignalHandler( MODULE_CONNECTOR_SIGNAL signal ) 00242 { 00243 // the module instance knows that 00244 boost::shared_ptr< WModule > module = m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope 00245 if( !module ) 00246 { 00247 throw WModuleConnectorModuleLockFailed(); 00248 } 00249 return module->getSignalHandler( signal ); 00250 } 00251 00252 boost::shared_ptr< WModule > WModuleConnector::getModule() const 00253 { 00254 return m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope 00255 } 00256 00257 void WModuleConnector::disconnect( boost::shared_ptr<WModuleConnector> con, bool removeFromOwnList ) 00258 { 00259 boost::shared_ptr< WModule > module = m_module.lock(); // it is "unlocked" at the end of this function as "module" looses its scope 00260 std::string containerName = "Unknown"; 00261 if( module ) 00262 { 00263 boost::shared_ptr< WModuleContainer > container; 00264 container = module->getAssociatedContainer(); 00265 containerName = container.get() ? container->getName() : "Unknown"; 00266 } 00267 00268 if( !isConnectedTo( con ) ) 00269 { 00270 WLogger::getLogger()->addLogMessage( "Could not disconnect " + con->getCanonicalName() + " from " + getCanonicalName() + " as they are"+ 00271 " not connected.", "ModuleContainer (" + containerName + ")", LL_INFO ); 00272 return; 00273 } 00274 00275 WLogger::getLogger()->addLogMessage( "Disconnecting " + con->getCanonicalName() + " from " + getCanonicalName(), 00276 "ModuleContainer (" + containerName + ")", LL_INFO ); 00277 00278 // write lock 00279 boost::unique_lock<boost::shared_mutex> lock; 00280 try 00281 { 00282 // disconnect all signals 00283 con->disconnectSignals( shared_from_this() ); 00284 disconnectSignals( con ); 00285 00286 // remove from list 00287 if( removeFromOwnList ) 00288 { 00289 lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock ); 00290 // since we use shared pointers, erasing the item should be enough 00291 m_connected.erase( con ); 00292 lock.unlock(); 00293 } 00294 00295 // remove me from his list 00296 lock = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock ); 00297 con->m_connected.erase( shared_from_this() ); 00298 lock.unlock(); 00299 00300 // signal "closed connection" 00301 // NOTE: at this point, there might be an connected input connector even though we disconnected it. This is because of removeFromOwnList. 00302 // The input connectors handle this with an additional member variable denoting their disconnect state 00303 signal_ConnectionClosed( shared_from_this(), con ); 00304 con->signal_ConnectionClosed( shared_from_this(), con ); 00305 } 00306 catch( const std::exception& e ) 00307 { 00308 lock.unlock(); 00309 00310 std::ostringstream s; 00311 s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << "."; 00312 throw WModuleDisconnectFailed( s.str() ); 00313 } 00314 catch( const boost::exception& e ) 00315 { 00316 lock.unlock(); 00317 00318 std::ostringstream s; 00319 s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << "."; 00320 throw WModuleDisconnectFailed( s.str() ); 00321 } 00322 } 00323 00324 void WModuleConnector::disconnectAll() 00325 { 00326 // remove from list 00327 00328 // acquire read lock 00329 boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock ); 00330 00331 // each connector needs to be notified and disconnected properly 00332 for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end(); 00333 ++listIter ) 00334 { 00335 disconnect( *listIter, false ); 00336 } 00337 rlock.unlock(); 00338 00339 // lock it for writing 00340 boost::unique_lock<boost::shared_mutex> lock( m_connectionListLock ); 00341 m_connected.clear(); 00342 lock.unlock(); 00343 } 00344 00345 const std::string WModuleConnector::getDescription() const 00346 { 00347 return m_description; 00348 } 00349 00350 const std::string WModuleConnector::getName() const 00351 { 00352 return m_name; 00353 } 00354 00355 const std::string WModuleConnector::getCanonicalName() const 00356 { 00357 std::ostringstream s; 00358 s << m_moduleName << ":" << getName(); 00359 00360 return s.str(); 00361 } 00362 00363 void WModuleConnector::setDescription( std::string desc ) 00364 { 00365 m_description = desc; 00366 } 00367 00368 void WModuleConnector::setName( std::string name ) 00369 { 00370 m_name = name; 00371 } 00372 00373 WCombinerTypes::WOneToOneCombiners WModuleConnector::getPossibleDisconnections() 00374 { 00375 WCombinerTypes::WOneToOneCombiners l; 00376 00377 // acquire read lock 00378 boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock ); 00379 00380 // for each connector 00381 for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end(); ++listIter ) 00382 { 00383 // simply create the combiner 00384 l.push_back( boost::shared_ptr< WDisconnectCombiner >( new WDisconnectCombiner( shared_from_this(), ( *listIter ) ) ) ); 00385 } 00386 rlock.unlock(); 00387 00388 return l; 00389 } 00390 00391 void WModuleConnector::notifyConnectionEstablished( boost::shared_ptr<WModuleConnector> /*here*/, boost::shared_ptr<WModuleConnector> /*there*/ ) 00392 { 00393 // by default: do nothing. 00394 } 00395 00396 void WModuleConnector::notifyConnectionClosed( boost::shared_ptr<WModuleConnector> /*here*/, boost::shared_ptr<WModuleConnector> /*there*/ ) 00397 { 00398 // do nothing by default 00399 } 00400 00401 boost::shared_ptr< WModuleInputConnector > WModuleConnector::toInputConnector() 00402 { 00403 return boost::dynamic_pointer_cast< WModuleInputConnector >( shared_from_this() ); 00404 } 00405 00406 boost::shared_ptr< WModuleOutputConnector > WModuleConnector::toOutputConnector() 00407 { 00408 return boost::dynamic_pointer_cast< WModuleOutputConnector >( shared_from_this() ); 00409 } 00410