~noskcaj/ubuntu/saucy/openwalnut/liberation

« back to all changes in this revision

Viewing changes to .pc/boost153/src/core/kernel/WModuleConnector.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-05-24 03:12:03 UTC
  • Revision ID: package-import@ubuntu.com-20130524031203-l5g1lzm1vd83fupi
Tags: 1.3.1+hg5849-1ubuntu1
Cherrypick boost1.53 pointer cast fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//---------------------------------------------------------------------------
 
2
//
 
3
// Project: OpenWalnut ( http://www.openwalnut.org )
 
4
//
 
5
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
 
6
// For more information see http://www.openwalnut.org/copying
 
7
//
 
8
// This file is part of OpenWalnut.
 
9
//
 
10
// OpenWalnut is free software: you can redistribute it and/or modify
 
11
// it under the terms of the GNU Lesser General Public License as published by
 
12
// the Free Software Foundation, either version 3 of the License, or
 
13
// (at your option) any later version.
 
14
//
 
15
// OpenWalnut is distributed in the hope that it will be useful,
 
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
// GNU Lesser General Public License for more details.
 
19
//
 
20
// You should have received a copy of the GNU Lesser General Public License
 
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
 
22
//
 
23
//---------------------------------------------------------------------------
 
24
 
 
25
#include <iostream>
 
26
#include <list>
 
27
#include <string>
 
28
#include <sstream>
 
29
#include <set>
 
30
 
 
31
#include <boost/version.hpp>
 
32
#if ( BOOST_VERSION >= 104200 ) // exception.hpp is deprecated in Boost 1.42
 
33
    #include <boost/exception/all.hpp>
 
34
#else
 
35
    #include <boost/exception.hpp>
 
36
#endif
 
37
 
 
38
#include <boost/signals2/signal.hpp>
 
39
#include <boost/signals2/connection.hpp>
 
40
 
 
41
#include "../common/exceptions/WSignalSubscriptionFailed.h"
 
42
#include "WModule.h"
 
43
#include "WModuleConnectorSignals.h"
 
44
#include "WModuleContainer.h"
 
45
#include "WModuleInputConnector.h"
 
46
#include "WModuleOutputConnector.h"
 
47
#include "combiner/WDisconnectCombiner.h"
 
48
#include "exceptions/WModuleConnectionFailed.h"
 
49
#include "exceptions/WModuleConnectionInvalid.h"
 
50
#include "exceptions/WModuleConnectorsIncompatible.h"
 
51
#include "exceptions/WModuleDisconnectFailed.h"
 
52
#include "exceptions/WModuleConnectorModuleLockFailed.h"
 
53
 
 
54
#include "WModuleConnector.h"
 
55
 
 
56
WModuleConnector::WModuleConnector( boost::shared_ptr< WModule > module, std::string name, std::string description ):
 
57
    boost::enable_shared_from_this<WModuleConnector>()
 
58
{
 
59
    // initialize members
 
60
    m_module = module;
 
61
    m_moduleName = module->getName();
 
62
 
 
63
    m_name = name;
 
64
    m_description = description;
 
65
 
 
66
    // connect standard signals
 
67
    // NOTE: these signals are NOT emitted by the connector this one is connected to, since a module can't send a "connection
 
68
    // closed" message if the connection is closed.
 
69
    subscribeSignal( CONNECTION_ESTABLISHED, boost::bind( &WModuleConnector::notifyConnectionEstablished, this, _1, _2 ) );
 
70
    subscribeSignal( CONNECTION_CLOSED, boost::bind( &WModuleConnector::notifyConnectionClosed, this, _1, _2 ) );
 
71
 
 
72
    signal_ConnectionEstablished.connect( getSignalHandler( CONNECTION_ESTABLISHED ) );
 
73
    signal_ConnectionClosed.connect( getSignalHandler( CONNECTION_CLOSED ) );
 
74
}
 
75
 
 
76
WModuleConnector::~WModuleConnector()
 
77
{
 
78
    disconnectAll();
 
79
 
 
80
    // cleanup
 
81
    signal_ConnectionEstablished.disconnect_all_slots();
 
82
    signal_ConnectionClosed.disconnect_all_slots();
 
83
}
 
84
 
 
85
bool WModuleConnector::isConnectedTo( boost::shared_ptr<WModuleConnector> con )
 
86
{
 
87
    boost::shared_lock<boost::shared_mutex> slock;
 
88
    slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock );
 
89
    int c1 = m_connected.count( con );
 
90
    slock.unlock();
 
91
 
 
92
    slock = boost::shared_lock<boost::shared_mutex>( con->m_connectionListLock );
 
93
    int c2 = con->m_connected.count( shared_from_this() );
 
94
    slock.unlock();
 
95
 
 
96
    // if the count is different the connection is invalid
 
97
    if( c1 != c2 )
 
98
    {
 
99
        std::ostringstream s;
 
100
        s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
 
101
        throw WModuleConnectionInvalid( s.str() );
 
102
    }
 
103
 
 
104
    return ( c1 == 1 );
 
105
}
 
106
 
 
107
unsigned int WModuleConnector::isConnected()
 
108
{
 
109
    boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_connectionListLock );
 
110
    int count = m_connected.size();
 
111
    slock.unlock();
 
112
    return count;
 
113
}
 
114
 
 
115
void WModuleConnector::connect( boost::shared_ptr<WModuleConnector> con )
 
116
{
 
117
    boost::shared_ptr< WModule > module = m_module.lock();    // it is "unlocked" at the end of this function as "module" looses its scope
 
118
    std::string containerName = "Unknown";
 
119
    if( module )
 
120
    {
 
121
        boost::shared_ptr< WModuleContainer > container;
 
122
        container = module->getAssociatedContainer();
 
123
        containerName = container.get() ? container->getName() : "Unknown";
 
124
    }
 
125
    WLogger::getLogger()->addLogMessage( "Connecting " + con->getCanonicalName() + " with " + getCanonicalName(),
 
126
                                         "ModuleContainer (" + containerName + ")", LL_INFO );
 
127
 
 
128
    // are both partners compatible to each other?
 
129
    if( !( con->connectable( shared_from_this() ) && connectable( con ) ) )
 
130
    {
 
131
        std::ostringstream s;
 
132
        s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
 
133
        throw WModuleConnectorsIncompatible( s.str() );
 
134
    }
 
135
 
 
136
    // check whether they are already connected
 
137
    if( isConnectedTo( con ) )
 
138
    {
 
139
        WLogger::getLogger()->addLogMessage( con->getCanonicalName() + " and " + getCanonicalName() + " are already connected.",
 
140
                                             "ModuleContainer (" + containerName + ")", LL_INFO );
 
141
        return;
 
142
    }
 
143
 
 
144
    boost::unique_lock<boost::shared_mutex> lock;
 
145
    boost::unique_lock<boost::shared_mutex> lockRemote;
 
146
    try
 
147
    {
 
148
        // get locks
 
149
        lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock );
 
150
        lockRemote = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock );
 
151
 
 
152
        // is the input connected already?
 
153
        if( ( isInputConnector() && m_connected.size() ) || ( con->isInputConnector() && con->m_connected.size() ) )
 
154
        {
 
155
            throw WModuleConnectionFailed( std::string( "Input connector already connected. Disconnect it first." ) );
 
156
        }
 
157
 
 
158
        m_connected.insert( con );
 
159
        con->m_connected.insert( shared_from_this() );
 
160
 
 
161
        lock.unlock();
 
162
        lockRemote.unlock();
 
163
    }
 
164
    catch( const WException& e )
 
165
    {
 
166
        lock.unlock();
 
167
        lockRemote.unlock();
 
168
 
 
169
        // undo changes
 
170
        m_connected.erase( con );
 
171
        con->m_connected.erase( con );
 
172
 
 
173
        throw e;
 
174
    }
 
175
    catch( const std::exception& e )
 
176
    {
 
177
        lock.unlock();
 
178
        lockRemote.unlock();
 
179
 
 
180
        // undo changes
 
181
        m_connected.erase( con );
 
182
        con->m_connected.erase( con );
 
183
 
 
184
        std::ostringstream s;
 
185
        s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
 
186
        throw WModuleConnectionFailed( s.str() );
 
187
    }
 
188
    catch( const boost::exception& e )
 
189
    {
 
190
        lock.unlock();
 
191
        lockRemote.unlock();
 
192
 
 
193
        // undo changes
 
194
        m_connected.erase( con );
 
195
        con->m_connected.erase( con );
 
196
 
 
197
        std::ostringstream s;
 
198
        s << "Connection between " << getCanonicalName() << " and " << con->getCanonicalName() << " failed.";
 
199
        throw WModuleConnectionFailed( s.str() );
 
200
    }
 
201
 
 
202
    // let them connect their signals
 
203
    connectSignals( con );
 
204
    con->connectSignals( shared_from_this() );
 
205
 
 
206
    // signal "connection established"
 
207
    signal_ConnectionEstablished( shared_from_this(), con );
 
208
    // signal to my partner, of course with the parameters the other way round
 
209
    con->signal_ConnectionEstablished( con, shared_from_this() );
 
210
}
 
211
 
 
212
void WModuleConnector::connectSignals( boost::shared_ptr<WModuleConnector> /*con*/ )
 
213
{
 
214
    // Add extra signal- connections here that are COMMON to ALL connectors.
 
215
    // NOTE: connection established and connection closed are not signals to connect, since you can not send an connection closed
 
216
    // signal to somebody with whom you are not connected anymore ;-).
 
217
}
 
218
 
 
219
void WModuleConnector::disconnectSignals( boost::shared_ptr<WModuleConnector> /*con*/ )
 
220
{
 
221
    // The base module does not subscribe to any signal -> no disconnection needed here
 
222
}
 
223
 
 
224
boost::signals2::connection WModuleConnector::subscribeSignal( MODULE_CONNECTOR_SIGNAL signal,
 
225
                                                               t_GenericSignalHandlerType notifier )
 
226
{
 
227
    switch( signal)
 
228
    {
 
229
        case CONNECTION_ESTABLISHED:
 
230
            return signal_ConnectionEstablished.connect( notifier );
 
231
        case CONNECTION_CLOSED:
 
232
            return signal_ConnectionClosed.connect( notifier );
 
233
        default:
 
234
            std::ostringstream s;
 
235
            s << "Could not subscribe to unknown signal. You need to implement this signal type explicitly.";
 
236
            throw WSignalSubscriptionFailed( s.str() );
 
237
            break;
 
238
    }
 
239
}
 
240
 
 
241
const t_GenericSignalHandlerType WModuleConnector::getSignalHandler( MODULE_CONNECTOR_SIGNAL signal )
 
242
{
 
243
    // the module instance knows that
 
244
    boost::shared_ptr< WModule > module = m_module.lock();    // it is "unlocked" at the end of this function as "module" looses its scope
 
245
    if( !module )
 
246
    {
 
247
        throw WModuleConnectorModuleLockFailed();
 
248
    }
 
249
    return module->getSignalHandler( signal );
 
250
}
 
251
 
 
252
boost::shared_ptr< WModule > WModuleConnector::getModule() const
 
253
{
 
254
    return m_module.lock();    // it is "unlocked" at the end of this function as "module" looses its scope
 
255
}
 
256
 
 
257
void WModuleConnector::disconnect( boost::shared_ptr<WModuleConnector> con, bool removeFromOwnList )
 
258
{
 
259
    boost::shared_ptr< WModule > module = m_module.lock();    // it is "unlocked" at the end of this function as "module" looses its scope
 
260
    std::string containerName = "Unknown";
 
261
    if( module )
 
262
    {
 
263
        boost::shared_ptr< WModuleContainer > container;
 
264
        container = module->getAssociatedContainer();
 
265
        containerName = container.get() ? container->getName() : "Unknown";
 
266
    }
 
267
 
 
268
    if( !isConnectedTo( con ) )
 
269
    {
 
270
        WLogger::getLogger()->addLogMessage( "Could not disconnect " + con->getCanonicalName() + " from " + getCanonicalName() + " as they are"+
 
271
                                             " not connected.", "ModuleContainer (" + containerName + ")", LL_INFO );
 
272
        return;
 
273
    }
 
274
 
 
275
    WLogger::getLogger()->addLogMessage( "Disconnecting " + con->getCanonicalName() + " from " + getCanonicalName(),
 
276
                                         "ModuleContainer (" + containerName + ")", LL_INFO );
 
277
 
 
278
    // write lock
 
279
    boost::unique_lock<boost::shared_mutex> lock;
 
280
    try
 
281
    {
 
282
        // disconnect all signals
 
283
        con->disconnectSignals( shared_from_this() );
 
284
        disconnectSignals( con );
 
285
 
 
286
        // remove from list
 
287
        if( removeFromOwnList )
 
288
        {
 
289
            lock = boost::unique_lock<boost::shared_mutex>( m_connectionListLock );
 
290
            // since we use shared pointers, erasing the item should be enough
 
291
            m_connected.erase( con );
 
292
            lock.unlock();
 
293
        }
 
294
 
 
295
        // remove me from his list
 
296
        lock = boost::unique_lock<boost::shared_mutex>( con->m_connectionListLock );
 
297
        con->m_connected.erase( shared_from_this() );
 
298
        lock.unlock();
 
299
 
 
300
        // signal "closed connection"
 
301
        // NOTE: at this point, there might be an connected input connector even though we disconnected it. This is because of removeFromOwnList.
 
302
        // The input connectors handle this with an additional member variable denoting their disconnect state
 
303
        signal_ConnectionClosed( shared_from_this(), con );
 
304
        con->signal_ConnectionClosed( shared_from_this(), con );
 
305
    }
 
306
    catch( const std::exception& e )
 
307
    {
 
308
        lock.unlock();
 
309
 
 
310
        std::ostringstream s;
 
311
        s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << ".";
 
312
        throw WModuleDisconnectFailed( s.str() );
 
313
    }
 
314
    catch( const boost::exception& e )
 
315
    {
 
316
        lock.unlock();
 
317
 
 
318
        std::ostringstream s;
 
319
        s << "Unable to disconnect " << getCanonicalName() << " from " << con->getCanonicalName() << ".";
 
320
        throw WModuleDisconnectFailed( s.str() );
 
321
    }
 
322
}
 
323
 
 
324
void WModuleConnector::disconnectAll()
 
325
{
 
326
    // remove from list
 
327
 
 
328
    // acquire read lock
 
329
    boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock );
 
330
 
 
331
    // each connector needs to be notified and disconnected properly
 
332
    for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end();
 
333
         ++listIter )
 
334
    {
 
335
        disconnect( *listIter, false );
 
336
    }
 
337
    rlock.unlock();
 
338
 
 
339
    // lock it for writing
 
340
    boost::unique_lock<boost::shared_mutex> lock( m_connectionListLock );
 
341
    m_connected.clear();
 
342
    lock.unlock();
 
343
}
 
344
 
 
345
const std::string WModuleConnector::getDescription() const
 
346
{
 
347
    return m_description;
 
348
}
 
349
 
 
350
const std::string WModuleConnector::getName() const
 
351
{
 
352
    return m_name;
 
353
}
 
354
 
 
355
const std::string WModuleConnector::getCanonicalName() const
 
356
{
 
357
    std::ostringstream s;
 
358
    s << m_moduleName << ":" << getName();
 
359
 
 
360
    return s.str();
 
361
}
 
362
 
 
363
void WModuleConnector::setDescription( std::string desc )
 
364
{
 
365
    m_description = desc;
 
366
}
 
367
 
 
368
void WModuleConnector::setName( std::string name )
 
369
{
 
370
    m_name = name;
 
371
}
 
372
 
 
373
WCombinerTypes::WOneToOneCombiners WModuleConnector::getPossibleDisconnections()
 
374
{
 
375
    WCombinerTypes::WOneToOneCombiners l;
 
376
 
 
377
    // acquire read lock
 
378
    boost::shared_lock<boost::shared_mutex> rlock( m_connectionListLock );
 
379
 
 
380
    // for each connector
 
381
    for( std::set<boost::shared_ptr<WModuleConnector> >::iterator listIter = m_connected.begin(); listIter != m_connected.end(); ++listIter )
 
382
    {
 
383
        // simply create the combiner
 
384
        l.push_back( boost::shared_ptr< WDisconnectCombiner >( new WDisconnectCombiner( shared_from_this(), ( *listIter ) ) ) );
 
385
    }
 
386
    rlock.unlock();
 
387
 
 
388
    return l;
 
389
}
 
390
 
 
391
void WModuleConnector::notifyConnectionEstablished( boost::shared_ptr<WModuleConnector> /*here*/, boost::shared_ptr<WModuleConnector> /*there*/ )
 
392
{
 
393
    // by default: do nothing.
 
394
}
 
395
 
 
396
void WModuleConnector::notifyConnectionClosed( boost::shared_ptr<WModuleConnector> /*here*/, boost::shared_ptr<WModuleConnector> /*there*/ )
 
397
{
 
398
    // do nothing by default
 
399
}
 
400
 
 
401
boost::shared_ptr< WModuleInputConnector > WModuleConnector::toInputConnector()
 
402
{
 
403
    return boost::shared_dynamic_cast< WModuleInputConnector >( shared_from_this() );
 
404
}
 
405
 
 
406
boost::shared_ptr< WModuleOutputConnector > WModuleConnector::toOutputConnector()
 
407
{
 
408
    return boost::shared_dynamic_cast< WModuleOutputConnector >( shared_from_this() );
 
409
}
 
410