LCOV - code coverage report
Current view: top level - eq/server - config.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 419 609 68.8 %
Date: 2014-06-18 Functions: 53 75 70.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2010, Cedric Stalder <cedric Stalder@gmail.com>
       4             :  *               2010-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include "config.h"
      21             : 
      22             : #include "canvas.h"
      23             : #include "changeLatencyVisitor.h"
      24             : #include "compound.h"
      25             : #include "compoundVisitor.h"
      26             : #include "configUpdateDataVisitor.h"
      27             : #include "equalizers/equalizer.h"
      28             : #include "global.h"
      29             : #include "layout.h"
      30             : #include "log.h"
      31             : #include "node.h"
      32             : #include "observer.h"
      33             : #include "segment.h"
      34             : #include "server.h"
      35             : #include "view.h"
      36             : #include "window.h"
      37             : 
      38             : #include <eq/client/error.h>
      39             : 
      40             : #include <eq/fabric/commands.h>
      41             : #include <eq/fabric/iAttribute.h>
      42             : #include <eq/fabric/paths.h>
      43             : 
      44             : #include <co/objectICommand.h>
      45             : 
      46             : #include <lunchbox/sleep.h>
      47             : 
      48             : #include "channelStopFrameVisitor.h"
      49             : #include "configDeregistrator.h"
      50             : #include "configRegistrator.h"
      51             : #include "configUpdateVisitor.h"
      52             : #include "configUpdateSyncVisitor.h"
      53             : #include "nodeFailedVisitor.h"
      54             : 
      55             : namespace eq
      56             : {
      57             : namespace server
      58             : {
      59             : typedef co::CommandFunc<Config> ConfigFunc;
      60             : using fabric::ON;
      61             : using fabric::OFF;
      62             : 
      63         215 : Config::Config( ServerPtr parent )
      64             :         : Super( parent )
      65             :         , _currentFrame( 0 )
      66             :         , _incarnation( 1 )
      67             :         , _finishedFrame( 0 )
      68             :         , _state( STATE_UNUSED )
      69             :         , _needsFinish( false )
      70         215 :         , _lastCheck( 0 )
      71             : {
      72         215 :     const Global* global = Global::instance();
      73        1720 :     for( int i=0; i < FATTR_ALL; ++i )
      74             :     {
      75        1505 :         const FAttribute attr = static_cast< FAttribute >( i );
      76        1505 :         setFAttribute( attr, global->getConfigFAttribute( attr ));
      77             :     }
      78        1505 :     for( int i=0; i < IATTR_ALL; ++i )
      79             :     {
      80        1290 :         const IAttribute attr = static_cast< IAttribute >( i );
      81        1290 :         setIAttribute( attr, global->getConfigIAttribute( attr ));
      82             :     }
      83         215 : }
      84             : 
      85         642 : Config::~Config()
      86             : {
      87         821 :     while( !_compounds.empty( ))
      88             :     {
      89         393 :         Compound* compound = _compounds.back();
      90         393 :         removeCompound( compound );
      91         393 :         delete compound;
      92             :     }
      93         428 : }
      94             : 
      95          10 : void Config::attach( const uint128_t& id, const uint32_t instanceID )
      96             : {
      97          10 :     Super::attach( id, instanceID );
      98             : 
      99          10 :     co::CommandQueue* mainQ = getMainThreadQueue();
     100          10 :     co::CommandQueue* cmdQ = getCommandThreadQueue();
     101             : 
     102             :     registerCommand( fabric::CMD_CONFIG_INIT,
     103          10 :                      ConfigFunc( this, &Config::_cmdInit), mainQ );
     104             :     registerCommand( fabric::CMD_CONFIG_EXIT,
     105          10 :                      ConfigFunc( this, &Config::_cmdExit ), mainQ );
     106             :     registerCommand( fabric::CMD_CONFIG_UPDATE,
     107          10 :                      ConfigFunc( this, &Config::_cmdUpdate ), mainQ );
     108             :     registerCommand( fabric::CMD_CONFIG_CREATE_REPLY,
     109          10 :                      ConfigFunc( this, &Config::_cmdCreateReply ), cmdQ );
     110             :     registerCommand( fabric::CMD_CONFIG_START_FRAME,
     111          10 :                      ConfigFunc( this, &Config::_cmdStartFrame ), mainQ );
     112             :     registerCommand( fabric::CMD_CONFIG_STOP_FRAMES,
     113          10 :                      ConfigFunc( this, &Config::_cmdStopFrames ), mainQ );
     114             :     registerCommand( fabric::CMD_CONFIG_FINISH_ALL_FRAMES,
     115          10 :                      ConfigFunc( this, &Config::_cmdFinishAllFrames ), mainQ );
     116             :     registerCommand( fabric::CMD_CONFIG_CHECK_FRAME,
     117          10 :                      ConfigFunc( this, &Config::_cmdCheckFrame ), mainQ );
     118          10 : }
     119             : 
     120             : namespace
     121             : {
     122             : class ChannelViewFinder : public ConfigVisitor
     123             : {
     124             : public:
     125        1142 :     ChannelViewFinder( const Segment* const segment, const View* const view )
     126        1142 :             : _segment( segment ), _view( view ), _result( 0 ) {}
     127             : 
     128        1142 :     virtual ~ChannelViewFinder(){}
     129             : 
     130       10039 :     virtual VisitorResult visit( Channel* channel )
     131             :         {
     132       10039 :             if( channel->getView() != _view )
     133        8589 :                 return TRAVERSE_CONTINUE;
     134             : 
     135        1450 :             if( channel->getSegment() != _segment )
     136         944 :                 return TRAVERSE_CONTINUE;
     137             : 
     138         506 :             _result = channel;
     139         506 :             return TRAVERSE_TERMINATE;
     140             :         }
     141             : 
     142        1142 :     Channel* getResult() { return _result; }
     143             : 
     144             : private:
     145             :     const Segment* const _segment;
     146             :     const View* const    _view;
     147             :     Channel*             _result;
     148             : };
     149             : 
     150           8 : class UpdateEqualizersVisitor : public ConfigVisitor
     151             : {
     152             : public:
     153           8 :     UpdateEqualizersVisitor() {}
     154             : 
     155             :     // No need to go down on nodes.
     156          13 :     VisitorResult visitPre( Node* ) override { return TRAVERSE_PRUNE; }
     157             : 
     158         381 :     VisitorResult visit( Compound* compound ) override
     159             :     {
     160         381 :         Channel* dest = compound->getInheritChannel();
     161         381 :         if( !dest )
     162          55 :             return TRAVERSE_CONTINUE;
     163             : 
     164         326 :         View* view = dest->getView();
     165         326 :         if( !view )
     166           0 :             return TRAVERSE_CONTINUE;
     167             : 
     168         326 :         const Equalizers& equalizers = compound->getEqualizers();
     169         368 :         for( EqualizersCIter i = equalizers.begin(); i != equalizers.end(); ++i)
     170          42 :             view->getEqualizer() = *(*i);
     171             : 
     172         326 :         return TRAVERSE_CONTINUE;
     173             :     }
     174             : };
     175             : }
     176             : 
     177         200 : const Channel* Config::findChannel( const std::string& name ) const
     178             : {
     179         200 :     return Super::find< Channel >( name );
     180             : }
     181             : 
     182        1142 : Channel* Config::findChannel( const Segment* segment, const View* view )
     183             : {
     184        1142 :     ChannelViewFinder finder( segment, view );
     185        1142 :     accept( finder );
     186        1142 :     return finder.getResult();
     187             : }
     188             : 
     189         243 : Node* Config::findApplicationNode()
     190             : {
     191         243 :     const Nodes& nodes = getNodes();
     192         243 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     193             :     {
     194         243 :         Node* node = *i;
     195         243 :         if( node->isApplicationNode( ))
     196         243 :             return node;
     197             :     }
     198           0 :     return 0;
     199             : }
     200             : 
     201          18 : co::NodePtr Config::findApplicationNetNode()
     202             : {
     203          18 :     Node* node = findApplicationNode();
     204          18 :     LBASSERT( node );
     205          18 :     return node ? node->getNode() : 0;
     206             : }
     207             : 
     208         223 : void Config::activateCanvas( Canvas* canvas )
     209             : {
     210         223 :     LBASSERT( canvas->isStopped( ));
     211         223 :     LBASSERT( lunchbox::find( getCanvases(), canvas ) != getCanvases().end( ));
     212             : 
     213         223 :     const Layouts& layouts = canvas->getLayouts();
     214         223 :     const Segments& segments = canvas->getSegments();
     215             : 
     216        1827 :     for( Layouts::const_iterator i = layouts.begin();
     217        1218 :          i != layouts.end(); ++i )
     218             :     {
     219         386 :         const Layout* layout = *i;
     220         386 :         if( !layout )
     221           2 :             continue;
     222             : 
     223         384 :         const Views& views = layout->getViews();
     224        2406 :         for( Views::const_iterator j = views.begin();
     225        1604 :              j != views.end(); ++j )
     226             :         {
     227         418 :             View* view = *j;
     228             : 
     229        3810 :             for( Segments::const_iterator k = segments.begin();
     230        2540 :                  k != segments.end(); ++k )
     231             :             {
     232         852 :                 Segment* segment = *k;
     233         852 :                 Viewport viewport = segment->getViewport();
     234         852 :                 viewport.intersect( view->getViewport( ));
     235             : 
     236         852 :                 if( !viewport.hasArea( ))
     237             :                 {
     238         216 :                     LBLOG( LOG_VIEW )
     239           0 :                         << "View " << view->getName() << view->getViewport()
     240           0 :                         << " doesn't intersect " << segment->getName()
     241         216 :                         << segment->getViewport() << std::endl;
     242             : 
     243         432 :                     continue;
     244             :                 }
     245             : 
     246         636 :                 Channel* segmentChannel = segment->getChannel();
     247         636 :                 if( !segmentChannel )
     248             :                 {
     249           0 :                     LBWARN << "Segment " << segment->getName()
     250           0 :                            << " has no output channel" << std::endl;
     251           0 :                     continue;
     252             :                 }
     253             : 
     254         636 :                 if ( findChannel( segment, view ))
     255           0 :                     continue;
     256             : 
     257             :                 // create and add new channel
     258         636 :                 Channel* channel = new Channel( *segmentChannel );
     259         636 :                 channel->init(); // not in ctor, virtual method
     260         636 :                 channel->setOutput( view, segment );
     261             : 
     262             :                 //----- compute channel viewport:
     263             :                 // segment/view intersection in canvas space...
     264         636 :                 Viewport contribution = viewport;
     265             :                 // ... in segment space...
     266         636 :                 contribution.transform( segment->getViewport( ));
     267             : 
     268             :                 // segment output area
     269         636 :                 if( segmentChannel->hasFixedViewport( ))
     270             :                 {
     271         630 :                     Viewport subViewport = segmentChannel->getViewport();
     272         630 :                     LBASSERT( subViewport.isValid( ));
     273         630 :                     if( !subViewport.isValid( ))
     274           0 :                         subViewport = eq::fabric::Viewport::FULL;
     275             : 
     276             :                     // ...our part of it
     277         630 :                     subViewport.apply( contribution );
     278         630 :                     channel->setViewport( subViewport );
     279         630 :                     LBLOG( LOG_VIEW )
     280           0 :                         << "View @" << (void*)view << ' ' << view->getViewport()
     281           0 :                         << " intersects " << segment->getName()
     282           0 :                         << segment->getViewport() << " at " << subViewport
     283         630 :                         << " using channel @" << (void*)channel << std::endl;
     284             :                 }
     285             :                 else
     286             :                 {
     287           6 :                     PixelViewport pvp = segmentChannel->getPixelViewport();
     288           6 :                     LBASSERT( pvp.isValid( ));
     289           6 :                     pvp.apply( contribution );
     290           6 :                     channel->setPixelViewport( pvp );
     291           6 :                     LBLOG( LOG_VIEW )
     292           0 :                         << "View @" << (void*)view << ' ' << view->getViewport()
     293           0 :                         << " intersects " << segment->getName()
     294           0 :                         << segment->getViewport() << " at " << pvp
     295           6 :                         << " using channel @" << (void*)channel << std::endl;
     296             :                 }
     297             : 
     298         636 :                 if( channel->getWindow()->isAttached() )
     299             :                     // parent is already registered - register channel as well
     300           0 :                     getServer()->registerObject( channel );
     301             :             }
     302             :         }
     303             :     }
     304         223 : }
     305             : 
     306           0 : void Config::updateCanvas( Canvas* canvas )
     307             : {
     308           0 :     postNeedsFinish();
     309           0 :     activateCanvas( canvas );
     310             : 
     311             :     // Create one compound group for all new output channels of each layout
     312           0 :     const Layouts& layouts = canvas->getLayouts();
     313           0 :     for( LayoutsCIter i = layouts.begin(); i != layouts.end(); ++i )
     314             :     {
     315           0 :         Compound* group = new Compound( this );
     316             : 
     317           0 :         const Layout* layout = *i;
     318           0 :         const Views& views = layout->getViews();
     319           0 :         for( ViewsCIter j = views.begin(); j != views.end(); ++j )
     320             :         {
     321           0 :             const View* view = *j;
     322           0 :             const Channels& channels = view->getChannels();
     323             : 
     324           0 :             if( channels.empty( ))
     325           0 :                 LBWARN << "New view without destination channels will be ignored"
     326           0 :                        << std::endl;
     327             : 
     328           0 :             for( ChannelsCIter k = channels.begin(); k != channels.end(); ++k )
     329             :             {
     330           0 :                 Channel* channel = *k;
     331           0 :                 LBASSERT( !channel->isActive( ));
     332             : 
     333           0 :                 Compound* compound = new Compound( group );
     334             :                 compound->setIAttribute( Compound::IATTR_STEREO_MODE,
     335           0 :                                          fabric::AUTO );
     336           0 :                 compound->setChannel( channel );
     337             :             }
     338             :         }
     339           0 :         group->init();
     340             :     }
     341             : 
     342           0 :     canvas->init();
     343           0 :     LBINFO << *this << std::endl;
     344           0 : }
     345             : 
     346           0 : Observer* Config::createObserver()
     347             : {
     348           0 :     return new Observer( this );
     349             : }
     350             : 
     351           0 : void Config::releaseObserver( Observer* observer )
     352             : {
     353           0 :     delete observer;
     354           0 : }
     355             : 
     356           0 : Layout* Config::createLayout()
     357             : {
     358           0 :     return new Layout( this );
     359             : }
     360             : 
     361           0 : void Config::releaseLayout( Layout* layout )
     362             : {
     363           0 :     delete layout;
     364           0 : }
     365             : 
     366           0 : Canvas* Config::createCanvas()
     367             : {
     368           0 :     return new Canvas( this );
     369             : }
     370             : 
     371           0 : void Config::releaseCanvas( Canvas* canvas )
     372             : {
     373           0 :     delete canvas;
     374           0 : }
     375             : 
     376           0 : template< class T > bool Config::_postDelete( const uint128_t& id )
     377             : {
     378           0 :     T* child = find< T >( id );
     379           0 :     if( !child )
     380           0 :         return false;
     381             : 
     382           0 :     child->postDelete();
     383           0 :     return true;
     384             : }
     385             : 
     386           0 : void Config::removeChild( const uint128_t& id )
     387             : {
     388           0 :     LBASSERT( isRunning( ));
     389             : 
     390           0 :     if( _postDelete< Observer >( id ) || _postDelete< Layout >( id ) ||
     391           0 :         _postDelete< Canvas >( id ))
     392             :     {
     393           0 :         return;
     394             :     }
     395           0 :     LBUNIMPLEMENTED;
     396             : }
     397             : 
     398         393 : void Config::addCompound( Compound* compound )
     399             : {
     400         393 :     LBASSERT( compound->_config == this );
     401         393 :     _compounds.push_back( compound );
     402         393 : }
     403             : 
     404         786 : bool Config::removeCompound( Compound* compound )
     405             : {
     406         786 :     LBASSERT( compound->_config == this );
     407         786 :     Compounds::iterator i = lunchbox::find( _compounds, compound );
     408         786 :     if( i == _compounds.end( ))
     409         393 :         return false;
     410             : 
     411         393 :     _compounds.erase( i );
     412         393 :     return true;
     413             : }
     414             : 
     415          12 : void Config::setApplicationNetNode( co::NodePtr netNode )
     416             : {
     417          12 :     if( netNode.isValid( ))
     418             :     {
     419          10 :         LBASSERT( _state == STATE_UNUSED );
     420          10 :         _state = STATE_STOPPED;
     421          10 :         setAppNodeID( netNode->getNodeID( ));
     422             :     }
     423             :     else
     424             :     {
     425           2 :         LBASSERT( _state == STATE_STOPPED );
     426           2 :         _state = STATE_UNUSED;
     427           2 :         setAppNodeID( uint128_t( ));
     428             :     }
     429             : 
     430          12 :     Node* node = findApplicationNode();
     431          12 :     LBASSERT( node );
     432          12 :     if( node )
     433          12 :         node->setNode( netNode );
     434          12 : }
     435             : 
     436           0 : Channel* Config::getChannel( const ChannelPath& path )
     437             : {
     438           0 :     Nodes nodes = getNodes();
     439           0 :     LBASSERTINFO( nodes.size() > path.nodeIndex,
     440             :                   nodes.size() << " <= " << path.nodeIndex );
     441             : 
     442           0 :     if( nodes.size() <= path.nodeIndex )
     443           0 :         return 0;
     444             : 
     445           0 :     return nodes[ path.nodeIndex ]->getChannel( path );
     446             : }
     447             : 
     448         708 : Segment* Config::getSegment( const SegmentPath& path )
     449             : {
     450         708 :     Canvas* canvas = getCanvas( path );
     451         708 :     LBASSERT( canvas );
     452             : 
     453         708 :     if( canvas )
     454         708 :         return canvas->getSegment( path );
     455             : 
     456           0 :     return 0;
     457             : }
     458             : 
     459         611 : View* Config::getView( const ViewPath& path )
     460             : {
     461         611 :     Layout* layout = getLayout( path );
     462         611 :     LBASSERT( layout );
     463             : 
     464         611 :     if( layout )
     465         611 :         return layout->getView( path );
     466             : 
     467           0 :     return 0;
     468             : }
     469             : 
     470             : namespace
     471             : {
     472             : template< class C >
     473        1665 : static VisitorResult _accept( C* config, ConfigVisitor& visitor )
     474             : {
     475        1665 :     VisitorResult result = TRAVERSE_CONTINUE;
     476        1665 :     const Compounds& compounds = config->getCompounds();
     477       17775 :     for( Compounds::const_iterator i = compounds.begin();
     478       11850 :          i != compounds.end(); ++i )
     479             :     {
     480        4473 :         switch( (*i)->accept( visitor ))
     481             :         {
     482             :             case TRAVERSE_TERMINATE:
     483         213 :                 return TRAVERSE_TERMINATE;
     484             : 
     485             :             case TRAVERSE_PRUNE:
     486        3145 :                 result = TRAVERSE_PRUNE;
     487        3145 :                 break;
     488             : 
     489             :             case TRAVERSE_CONTINUE:
     490             :             default:
     491        1115 :                 break;
     492             :         }
     493             :     }
     494        1452 :     return result;
     495             : }
     496             : }
     497             : 
     498        1665 : VisitorResult Config::_acceptCompounds( ConfigVisitor& visitor )
     499             : {
     500        1665 :     return _accept( this, visitor );
     501             : }
     502             : 
     503           0 : VisitorResult Config::_acceptCompounds( ConfigVisitor& visitor ) const
     504             : {
     505           0 :     return _accept( this, visitor );
     506             : }
     507             : 
     508             : //===========================================================================
     509             : // operations
     510             : //===========================================================================
     511             : 
     512          10 : void Config::register_()
     513             : {
     514          10 :     ConfigRegistrator registrator;
     515          10 :     accept( registrator );
     516          10 : }
     517             : 
     518          10 : void Config::deregister()
     519             : {
     520          10 :     sync();
     521          10 :     ConfigDeregistrator deregistrator;
     522          10 :     accept( deregistrator );
     523          10 : }
     524             : 
     525        4614 : uint128_t Config::commit()
     526             : {
     527        4614 :     return Super::commit( _incarnation );
     528             : }
     529             : 
     530           2 : void Config::restore()
     531             : {
     532           2 :     _currentFrame = 0;
     533           2 :     _finishedFrame = 0;
     534           2 :     setApplicationNetNode( 0 );
     535           2 :     _workDir.clear();
     536           2 :     _renderClient.clear();
     537           2 :     Super::restore();
     538           2 : }
     539             : 
     540           0 : EventOCommand Config::sendError( const uint32_t type,
     541             :                                  const uint128_t& originator,
     542             :                                  const uint32_t error )
     543             : {
     544           0 :     return Super::sendError( findApplicationNetNode(), type, originator, error);
     545             : }
     546             : 
     547             : //---------------------------------------------------------------------------
     548             : // update running entities (init/exit/runtime change)
     549             : //---------------------------------------------------------------------------
     550          16 : bool Config::_updateRunning()
     551             : {
     552          16 :     if( _state == STATE_STOPPED )
     553           0 :         return true;
     554             : 
     555          16 :     const bool canFail = (getIAttribute( IATTR_ROBUSTNESS ) != OFF);
     556             : 
     557          16 :     LBASSERT( _state == STATE_RUNNING || _state == STATE_INITIALIZING ||
     558             :               _state == STATE_EXITING );
     559             : 
     560          16 :     if( !_connectNodes() && !canFail )
     561           0 :         return false;
     562             : 
     563          16 :     _startNodes();
     564          16 :     _updateCanvases();
     565          16 :     const bool result = _updateNodes() ? true : canFail;
     566          16 :     _stopNodes();
     567             : 
     568             :     // Don't use visitor, it would get confused with modified child vectors
     569          16 :     _deleteEntities( getCanvases( ));
     570          16 :     _deleteEntities( getLayouts( ));
     571          16 :     _deleteEntities( getObservers( ));
     572          16 :     const Nodes& nodes = getNodes();
     573          42 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     574             :     {
     575          26 :         const Pipes& pipes = (*i)->getPipes();
     576          66 :         for( Pipes::const_iterator j = pipes.begin(); j != pipes.end(); ++j )
     577             :         {
     578          40 :             const Windows& windows = (*j)->getWindows();
     579          40 :             _deleteEntities( windows );
     580             :         }
     581             :     }
     582             : 
     583          16 :     return result;
     584             : }
     585             : 
     586          16 : bool Config::_connectNodes()
     587             : {
     588          16 :     bool success = true;
     589          16 :     lunchbox::Clock clock;
     590          16 :     const Nodes& nodes = getNodes();
     591          42 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     592             :     {
     593          26 :         Node* node = *i;
     594          26 :         if( !node->isActive( ))
     595          18 :             continue;
     596             : 
     597           8 :         if( !node->connect( ))
     598           0 :             success = false;
     599             :     }
     600             : 
     601          42 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     602             :     {
     603          26 :         Node* node = *i;
     604          26 :         if( node->isActive() && !node->syncLaunch( clock ))
     605           0 :             success = false;
     606             :     }
     607             : 
     608          16 :     return success;
     609             : }
     610             : 
     611          16 : void Config::_startNodes()
     612             : {
     613             :     // start up newly running nodes
     614          16 :     std::vector< lunchbox::Request< void > > requests;
     615          16 :     const Nodes& nodes = getNodes();
     616          16 :     requests.reserve( nodes.size( ));
     617             : 
     618          42 :     BOOST_FOREACH( Node* node, nodes )
     619             :     {
     620          26 :         if( node->isActive() && node->isStopped( ))
     621             :         {
     622           8 :             if( !node->isApplicationNode( ))
     623           0 :                 requests.push_back( _createConfig( node ));
     624             :         }
     625             :         else
     626             :         {
     627          18 :             LBASSERT( !node->isActive() || node->getState() == STATE_FAILED ||
     628             :                       node->getState() == STATE_RUNNING );
     629             :         }
     630          16 :     }
     631             :     // Request dtor waits for finish
     632          16 : }
     633             : 
     634          16 : void Config::_updateCanvases()
     635             : {
     636          16 :     const Canvases& canvases = getCanvases();
     637          32 :     for( Canvases::const_iterator i = canvases.begin(); i != canvases.end();++i)
     638             :     {
     639          16 :         Canvas* canvas = *i;
     640          16 :         if( canvas->needsDelete( ))
     641           0 :             canvas->exit();
     642             :     }
     643          16 : }
     644             : 
     645          16 : void Config::_stopNodes()
     646             : {
     647             :     // wait for the nodes to stop, destroy entities, disconnect
     648          16 :     Nodes stoppingNodes;
     649          16 :     const Nodes& nodes = getNodes();
     650          42 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     651             :     {
     652          26 :         Node* node = *i;
     653          26 :         const State state = node->getState();
     654          26 :         if( state != STATE_STOPPED && state != STATE_FAILED )
     655          34 :             continue;
     656             : 
     657          18 :         LBASSERT( !node->isActive() || state == STATE_FAILED );
     658          18 :         if( node->isApplicationNode( ))
     659           8 :             continue;
     660             : 
     661          10 :         co::NodePtr netNode = node->getNode();
     662          10 :         if( !netNode ) // already disconnected
     663          10 :             continue;
     664             : 
     665           0 :         LBLOG( LOG_INIT ) << "Exiting node" << std::endl;
     666             : 
     667           0 :         if( state == STATE_FAILED )
     668           0 :             node->setState( STATE_STOPPED );
     669             : 
     670           0 :         stoppingNodes.push_back( node );
     671           0 :         LBASSERT( netNode.isValid( ));
     672             : 
     673             :         netNode->send( fabric::CMD_SERVER_DESTROY_CONFIG )
     674           0 :                 << getID() << LB_UNDEFINED_UINT32;
     675           0 :         netNode->send( fabric::CMD_CLIENT_EXIT );
     676           0 :     }
     677             : 
     678             :     // now wait that the render clients disconnect
     679          16 :     uint32_t nSleeps = 50; // max 5 seconds for all clients
     680          48 :     for( Nodes::const_iterator i = stoppingNodes.begin();
     681          32 :          i != stoppingNodes.end(); ++i )
     682             :     {
     683           0 :         Node*        node    = *i;
     684           0 :         co::NodePtr netNode = node->getNode();
     685           0 :         node->setNode( 0 );
     686             : 
     687           0 :         if( nSleeps )
     688           0 :             while( netNode->isConnected() && --nSleeps )
     689           0 :                 lunchbox::sleep( 100 ); // ms
     690             : 
     691           0 :         if( netNode->isConnected( ))
     692             :         {
     693           0 :             co::LocalNodePtr localNode = getLocalNode();
     694           0 :             LBASSERT( localNode.isValid( ));
     695             : 
     696           0 :             LBWARN << "Forcefully disconnecting exited render client node"
     697           0 :                    << std::endl;
     698           0 :             localNode->disconnect( netNode );
     699             :         }
     700             : 
     701           0 :         LBLOG( LOG_INIT ) << "Disconnected node" << std::endl;
     702          16 :     }
     703          16 : }
     704             : 
     705          16 : bool Config::_updateNodes()
     706             : {
     707          16 :     ConfigUpdateVisitor update( _initID, _currentFrame );
     708          16 :     accept( update );
     709             : 
     710          32 :     ConfigUpdateSyncVisitor syncUpdate;
     711          16 :     accept( syncUpdate );
     712             : 
     713          16 :     const bool result = syncUpdate.getResult();
     714             : 
     715          16 :     if( syncUpdate.needsSync( )) // init failure, call again (exit pending)
     716             :     {
     717           0 :         LBASSERT( !result );
     718           0 :         accept( syncUpdate );
     719           0 :         LBASSERT( !syncUpdate.needsSync( ));
     720             :     }
     721             : 
     722          32 :     return result;
     723             : }
     724             : 
     725             : template< class T >
     726          88 : void Config::_deleteEntities( const std::vector< T* >& entities )
     727             : {
     728         358 :     for( size_t i = 0; i < entities.size(); ) // don't use iterator! (delete)
     729             :     {
     730         182 :         T* entity = entities[ i ];
     731         182 :         if( entity->needsDelete( ))
     732             :         {
     733           0 :             LBASSERT( entity->isAttached( ));
     734           0 :             getServer()->deregisterObject( entity );
     735           0 :             delete entity;
     736             :         }
     737             :         else
     738         182 :             ++i;
     739             :     }
     740          88 : }
     741             : 
     742           0 : lunchbox::Request< void > Config::_createConfig( Node* node )
     743             : {
     744           0 :     LBASSERT( !node->isApplicationNode( ));
     745           0 :     LBASSERT( node->isActive( ));
     746             : 
     747             :     // create config on each non-app node
     748             :     //   app-node already has config from chooseConfig
     749           0 :     lunchbox::Request< void > request = getLocalNode()->registerRequest<void>();
     750             : 
     751             :     node->getNode()->send( fabric::CMD_SERVER_CREATE_CONFIG )
     752           0 :             << co::ObjectVersion( this ) << request;
     753           0 :     return request;
     754             : }
     755             : 
     756           5 : void Config::_syncClock()
     757             : {
     758           5 :     const Nodes& nodes = getNodes();
     759          10 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     760             :     {
     761           5 :         Node* node = *i;
     762           5 :         if( node->isRunning() || node->isApplicationNode( ))
     763             :         {
     764           5 :             LBASSERT( node->isApplicationNode() || node->isActive( ));
     765           5 :             co::NodePtr netNode = node->getNode();
     766           5 :             LBASSERT( netNode->isConnected( ));
     767             : 
     768             :             send( netNode,
     769           5 :                   fabric::CMD_CONFIG_SYNC_CLOCK ) << getServer()->getTime();
     770             :         }
     771             :     }
     772           5 : }
     773             : 
     774             : //---------------------------------------------------------------------------
     775             : // init
     776             : //---------------------------------------------------------------------------
     777           8 : bool Config::_init( const uint128_t& initID )
     778             : {
     779           8 :     LBASSERT( _state == STATE_STOPPED );
     780           8 :     _state = STATE_INITIALIZING;
     781           8 :     _currentFrame  = 0;
     782           8 :     _finishedFrame = 0;
     783           8 :     _initID = initID;
     784             : 
     785          63 :     for( CompoundsCIter i = _compounds.begin(); i != _compounds.end(); ++i )
     786          55 :         (*i)->init();
     787             : 
     788           8 :     const Observers& observers = getObservers();
     789          16 :     for( ObserversCIter i = observers.begin(); i != observers.end(); ++i )
     790           8 :         (*i)->init();
     791             : 
     792           8 :     const Canvases& canvases = getCanvases();
     793          16 :     for( CanvasesCIter i = canvases.begin(); i != canvases.end(); ++i )
     794           8 :         (*i)->init();
     795             : 
     796           8 :     if( !_updateRunning( ))
     797           0 :         return false;
     798             : 
     799             :     // Needed to set up active state for first LB update
     800          63 :     for( CompoundsCIter i = _compounds.begin(); i != _compounds.end(); ++i )
     801          55 :         (*i)->update( 0 );
     802             : 
     803             :     // Update equalizer properties in views
     804           8 :     UpdateEqualizersVisitor updater;
     805           8 :     accept( updater );
     806             : 
     807           8 :     _needsFinish = false;
     808           8 :     _state = STATE_RUNNING;
     809           8 :     return true;
     810             : }
     811             : 
     812             : //---------------------------------------------------------------------------
     813             : // exit
     814             : //---------------------------------------------------------------------------
     815           8 : bool Config::exit()
     816             : {
     817           8 :     if( _state != STATE_RUNNING )
     818           0 :         LBWARN << "Exiting non-initialized config" << std::endl;
     819             : 
     820           8 :     LBASSERT( _state == STATE_RUNNING || _state == STATE_INITIALIZING );
     821           8 :     _state = STATE_EXITING;
     822             : 
     823           8 :     const Canvases& canvases = getCanvases();
     824          48 :     for( Canvases::const_iterator i = canvases.begin();
     825          32 :          i != canvases.end(); ++i )
     826             :     {
     827           8 :         Canvas* canvas = *i;
     828           8 :         canvas->exit();
     829             :     }
     830             : 
     831         189 :     for( Compounds::const_iterator i = _compounds.begin();
     832         126 :          i != _compounds.end(); ++i )
     833             :     {
     834          55 :         Compound* compound = *i;
     835          55 :         compound->exit();
     836             :     }
     837             : 
     838           8 :     const bool success = _updateRunning();
     839             : 
     840             :     // TODO: is this needed? sender of CMD_CONFIG_EXIT is the appNode itself
     841             :     // which sets the running state to false anyway. Besides, this event is
     842             :     // not handled by the appNode because it is already in exiting procedure
     843             :     // and does not call handleEvents anymore
     844             :     // eile: May be needed for reliability?
     845           8 :     send( findApplicationNetNode(), fabric::CMD_CONFIG_EVENT ) << Event::EXIT;
     846             : 
     847           8 :     _needsFinish = false;
     848           8 :     _state = STATE_STOPPED;
     849           8 :     return success;
     850             : }
     851             : 
     852             : //---------------------------------------------------------------------------
     853             : // frame
     854             : //---------------------------------------------------------------------------
     855           5 : void Config::_startFrame( const uint128_t& frameID )
     856             : {
     857           5 :     LBASSERT( _state == STATE_RUNNING );
     858           5 :     _verifyFrameFinished( _currentFrame );
     859           5 :     _syncClock();
     860             : 
     861           5 :     ++_currentFrame;
     862           5 :     ++_incarnation;
     863           5 :     LBLOG( lunchbox::LOG_ANY ) << "----- Start Frame ----- " << _currentFrame
     864           5 :                                << std::endl;
     865             : 
     866          66 :     for( Compounds::const_iterator i = _compounds.begin();
     867          44 :          i != _compounds.end(); ++i )
     868             :     {
     869          17 :         Compound* compound = *i;
     870          17 :         compound->update( _currentFrame );
     871             :     }
     872             : 
     873           5 :     ConfigUpdateDataVisitor configDataVisitor;
     874           5 :     accept( configDataVisitor );
     875             : 
     876           5 :     const Nodes& nodes = getNodes();
     877          10 :     co::NodePtr appNode = findApplicationNetNode();
     878          10 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     879             :     {
     880           5 :         Node* node = *i;
     881           5 :         node->update( frameID, _currentFrame );
     882           5 :         if( node->isRunning() && node->isApplicationNode( ))
     883           5 :             appNode = 0; // release sent (see below)
     884             :     }
     885             : 
     886           5 :     if( appNode.isValid( )) // release appNode local sync
     887             :         send( appNode,
     888           0 :               fabric::CMD_CONFIG_RELEASE_FRAME_LOCAL ) << _currentFrame;
     889             : 
     890             :     // Fix 2976899: Config::finishFrame deadlocks when no nodes are active
     891          10 :     notifyNodeFrameFinished( _currentFrame );
     892           5 : }
     893             : 
     894           5 : void Config::_verifyFrameFinished( const uint32_t frameNumber )
     895             : {
     896           5 :     const Nodes& nodes = getNodes();
     897          10 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     898             :     {
     899           5 :         Node* node = *i;
     900          10 :         if( node->isRunning() &&
     901           5 :             node->getFinishedFrame() + getLatency() < frameNumber )
     902             :         {
     903           0 :             NodeFailedVisitor nodeFailedVisitor;
     904           0 :             node->accept( nodeFailedVisitor );
     905             :         }
     906             :     }
     907           5 : }
     908             : 
     909          10 : void Config::notifyNodeFrameFinished( const uint32_t frameNumber )
     910             : {
     911          10 :     if( _finishedFrame >= frameNumber ) // node finish already done
     912           0 :         return;
     913             : 
     914          10 :     const Nodes& nodes = getNodes();
     915          15 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     916             :     {
     917          10 :         const Node* node = *i;
     918          10 :         if( node->isRunning() && node->getFinishedFrame() < frameNumber )
     919             :         {
     920           5 :             LBASSERT( _needsFinish || node->isActive( ));
     921          10 :             return;
     922             :         }
     923             :     }
     924             : 
     925           5 :     _finishedFrame = frameNumber;
     926             : 
     927             :     // All nodes have finished the frame. Notify the application's config that
     928             :     // the frame is finished
     929             : 
     930             :     // do not use send/_bufferedTasks, not thread-safe!
     931             :     send( findApplicationNetNode(),
     932          10 :           fabric::CMD_CONFIG_FRAME_FINISH ) << frameNumber;
     933           5 :     LBLOG( LOG_TASKS ) << "TASK config frame finished  " << " frame "
     934           5 :                        << frameNumber << std::endl;
     935             : }
     936             : 
     937           3 : void Config::_flushAllFrames()
     938             : {
     939           3 :     if( _currentFrame == 0 )
     940           3 :         return;
     941             : 
     942           3 :     const Nodes& nodes = getNodes();
     943           6 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
     944             :     {
     945           3 :         Node* node = *i;
     946           3 :         if( node->isRunning( ))
     947           3 :             node->flushFrames( _currentFrame );
     948             :     }
     949             : 
     950           3 :     LBLOG( lunchbox::LOG_ANY ) << "--- Flush All Frames -- " << std::endl;
     951             : }
     952             : 
     953           0 : void Config::changeLatency( const uint32_t latency )
     954             : {
     955           0 :     if( getLatency() == latency )
     956           0 :         return;
     957             : 
     958           0 :     setLatency( latency );
     959             : 
     960             :     // update latency on all frames and barriers
     961           0 :     ChangeLatencyVisitor visitor( latency );
     962           0 :     accept( visitor );
     963             : }
     964             : 
     965             : 
     966             : //---------------------------------------------------------------------------
     967             : // command handlers
     968             : //---------------------------------------------------------------------------
     969           8 : bool Config::_cmdInit( co::ICommand& cmd )
     970             : {
     971           8 :     co::ObjectICommand command( cmd );
     972             : 
     973           8 :     LB_TS_THREAD( _mainThread );
     974           8 :     LBVERB << "handle config start init " << command << std::endl;
     975             : 
     976           8 :     sync();
     977           8 :     commit();
     978             : 
     979           8 :     const uint128_t& initID = command.read< uint128_t >();
     980           8 :     const uint32_t requestID = command.read< uint32_t >();
     981           8 :     const bool result = _init( initID );
     982             : 
     983           8 :     if( !result )
     984           0 :         exit();
     985             : 
     986           8 :     sync();
     987           8 :     LBINFO << "Config init " << (result ? "successful" : "failed") << std::endl;
     988             : 
     989           8 :     const uint128_t version = commit();
     990             :     send( command.getRemoteNode(),
     991           8 :           fabric::CMD_CONFIG_INIT_REPLY ) << version << requestID << result;
     992           8 :     return true;
     993             : }
     994             : 
     995           8 : bool Config::_cmdExit( co::ICommand& cmd )
     996             : {
     997           8 :     co::ObjectICommand command( cmd );
     998           8 :     LBVERB << "handle config exit " << command << std::endl;
     999             : 
    1000             :     bool result;
    1001           8 :     if( _state == STATE_RUNNING )
    1002           8 :         result = exit();
    1003             :     else
    1004             :     {
    1005           0 :         LBINFO << "Exit of non-running config?" << std::endl;
    1006           0 :         result = false;
    1007             :     }
    1008             : 
    1009           8 :     LBINFO << "Config exit " << (result ? "successful" : "failed") << std::endl;
    1010             :     send( command.getRemoteNode(), fabric::CMD_CONFIG_EXIT_REPLY )
    1011           8 :             << command.read< uint32_t >() << result;
    1012           8 :     return true;
    1013             : }
    1014             : 
    1015        4586 : bool Config::_cmdUpdate( co::ICommand& cmd )
    1016             : {
    1017        4586 :     co::ObjectICommand command( cmd );
    1018             : 
    1019        4586 :     LBVERB << "handle config update " << command << std::endl;
    1020             : 
    1021        4586 :     const uint32_t versionID = command.read< uint32_t >();
    1022        4586 :     const uint32_t finishID = command.read< uint32_t >();
    1023             : 
    1024        4586 :     sync();
    1025        4586 :     commit();
    1026             : 
    1027        9172 :     co::NodePtr node = command.getRemoteNode();
    1028        4586 :     if( !_needsFinish )
    1029             :     {
    1030             :         send( node, fabric::CMD_CONFIG_UPDATE_VERSION )
    1031        4586 :                 << getVersion() << versionID << finishID << LB_UNDEFINED_UINT32;
    1032        4586 :         return true;
    1033             :     }
    1034             : 
    1035           0 :     co::LocalNodePtr localNode = getLocalNode();
    1036           0 :     lunchbox::Request< void > request = localNode->registerRequest< void >();
    1037             : 
    1038             :     send( node, fabric::CMD_CONFIG_UPDATE_VERSION )
    1039           0 :         << getVersion() << versionID << finishID << request;
    1040             : 
    1041           0 :     _flushAllFrames();
    1042           0 :     _finishedFrame.waitEQ( _currentFrame ); // wait for render clients idle
    1043           0 :     request.wait(); // wait for app sync
    1044           0 :     _needsFinish = false;
    1045             : 
    1046           0 :     const bool result = _updateRunning();
    1047           0 :     if( !result && getIAttribute( IATTR_ROBUSTNESS ) == OFF )
    1048             :     {
    1049           0 :         LBWARN << "Config update failed, exiting config" << std::endl;
    1050           0 :         exit();
    1051             :     }
    1052             : 
    1053           0 :     const uint128_t version = commit();
    1054             :     send( command.getRemoteNode(), fabric::CMD_CONFIG_UPDATE_REPLY )
    1055           0 :             << version << command.read< uint32_t >() << result;
    1056        4586 :     return true;
    1057             : }
    1058             : 
    1059           5 : bool Config::_cmdStartFrame( co::ICommand& cmd )
    1060             : {
    1061           5 :     co::ObjectICommand command( cmd );
    1062             : 
    1063           5 :     LBVERB << "handle config frame start " << command << std::endl;
    1064             : 
    1065           5 :     _startFrame( command.read< uint128_t >( ));
    1066             : 
    1067           5 :     if( _state == STATE_STOPPED )
    1068             :     {
    1069             :         // unlock app
    1070             :         send( command.getRemoteNode(), fabric::CMD_CONFIG_FRAME_FINISH )
    1071           0 :                 << _currentFrame;
    1072             :     }
    1073           5 :     return true;
    1074             : }
    1075             : 
    1076           3 : bool Config::_cmdFinishAllFrames( co::ICommand& cmd )
    1077             : {
    1078           3 :     co::ObjectICommand command( cmd );
    1079             : 
    1080           3 :     LBVERB << "handle config all frames finish " << command << std::endl;
    1081             : 
    1082           3 :     _flushAllFrames();
    1083           3 :     return true;
    1084             : }
    1085             : 
    1086           0 : bool Config::_cmdStopFrames( co::ICommand& cmd )
    1087             : {
    1088           0 :     co::ObjectICommand command( cmd );
    1089             : 
    1090           0 :     LBVERB << "handle config stop frames " << command << std::endl;
    1091             : 
    1092           0 :     ChannelStopFrameVisitor visitor( _currentFrame );
    1093           0 :     accept( visitor );
    1094             : 
    1095           0 :     return true;
    1096             : }
    1097             : 
    1098           0 : bool Config::_cmdCreateReply( co::ICommand& cmd )
    1099             : {
    1100           0 :     co::ObjectICommand command( cmd );
    1101             : 
    1102           0 :     LB_TS_THREAD( _cmdThread );
    1103           0 :     LB_TS_NOT_THREAD( _mainThread );
    1104             : 
    1105           0 :     getLocalNode()->serveRequest( command.read< uint32_t >( ));
    1106           0 :     return true;
    1107             : }
    1108             : 
    1109           0 : bool Config::_cmdCheckFrame( co::ICommand& cmd )
    1110             : {
    1111           0 :     const int64_t lastInterval = getServer()->getTime() - _lastCheck;
    1112           0 :     _lastCheck = getServer()->getTime();
    1113             : 
    1114           0 :     co::ObjectICommand command( cmd );
    1115           0 :     LBVERB << "Check nodes for frame finish " << command << std::endl;
    1116             : 
    1117           0 :     const uint32_t frameNumber = command.read< uint32_t >();
    1118           0 :     const uint32_t timeout = getTimeout();
    1119             : 
    1120           0 :     bool retry = false;
    1121           0 :     const Nodes& nodes = getNodes();
    1122           0 :     for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
    1123             :     {
    1124           0 :         Node* node = *i;
    1125           0 :         if( node->isRunning() && node->isActive() )
    1126             :         {
    1127           0 :             co::NodePtr netNode = node->getNode();
    1128           0 :             if ( netNode->isClosed() )
    1129           0 :                 continue;
    1130             : 
    1131           0 :             if ( node->getFinishedFrame() >= frameNumber )
    1132           0 :                 continue;
    1133             : 
    1134           0 :             const int64_t interval = getServer()->getTime() -
    1135           0 :                                      netNode->getLastReceiveTime();
    1136           0 :             getLocalNode()->ping( netNode );
    1137             : 
    1138             :             // TODO?: handle timed out nodes.
    1139             :             // currently we get a false positive due to lack of communication
    1140             :             // from client to server. we do not get ping responses in time.
    1141             :             // running clients should inform the server about their status with
    1142             :             // a timeout/2 period.
    1143             : 
    1144           0 :             if ( interval > timeout && lastInterval <= timeout )
    1145           0 :                 continue;
    1146             : 
    1147             :             // retry
    1148           0 :             LBINFO << "Retry waiting for node " << node->getName()
    1149           0 :                    << " to finish frame " << frameNumber << " last seen "
    1150           0 :                    << interval << " ms ago" << " last run " << lastInterval
    1151           0 :                    << std::endl;
    1152           0 :             retry = true;
    1153             :             // else node timeout
    1154             :         }
    1155             :     }
    1156             : 
    1157           0 :     if( retry )
    1158           0 :         return true;
    1159             : 
    1160             :     send( command.getRemoteNode(), fabric::CMD_CONFIG_FRAME_FINISH )
    1161           0 :         << _currentFrame;
    1162           0 :     return true;
    1163             : }
    1164             : 
    1165         120 : void Config::output( std::ostream& os ) const
    1166             : {
    1167         120 :     os << std::endl << lunchbox::disableFlush << lunchbox::disableHeader;
    1168             : 
    1169        1227 :     for( Compounds::const_iterator i = _compounds.begin();
    1170         818 :          i != _compounds.end(); ++i )
    1171             :     {
    1172         289 :         os << **i;
    1173             :     }
    1174             : 
    1175         120 :     os << lunchbox::enableHeader << lunchbox::enableFlush;
    1176         120 : }
    1177             : 
    1178             : }
    1179             : }
    1180             : 
    1181             : #include "nodeFactory.h"
    1182             : #include "../fabric/config.ipp"
    1183             : template class eq::fabric::Config< eq::server::Server, eq::server::Config,
    1184             :                                    eq::server::Observer, eq::server::Layout,
    1185             :                                    eq::server::Canvas, eq::server::Node,
    1186             :                                    eq::server::ConfigVisitor >;
    1187             : 
    1188             : /** @cond IGNORE */
    1189             : template std::ostream& eq::fabric::operator <<
    1190             :     ( std::ostream&, const eq::server::Config::Super& );
    1191             : /** @endcond */
    1192             : 
    1193             : #define FIND_ID_TEMPLATE1( type )                                       \
    1194             :     template void eq::server::Config::Super::find< type >( const uint128_t&, \
    1195             :                                                            type** );
    1196             : 
    1197             : FIND_ID_TEMPLATE1( eq::server::Canvas );
    1198             : FIND_ID_TEMPLATE1( eq::server::Channel );
    1199             : FIND_ID_TEMPLATE1( eq::server::Layout );
    1200             : FIND_ID_TEMPLATE1( eq::server::Node );
    1201             : FIND_ID_TEMPLATE1( eq::server::Observer );
    1202             : FIND_ID_TEMPLATE1( eq::server::Pipe );
    1203             : FIND_ID_TEMPLATE1( eq::server::Segment );
    1204             : FIND_ID_TEMPLATE1( eq::server::View );
    1205             : FIND_ID_TEMPLATE1( eq::server::Window );
    1206             : 
    1207             : #define FIND_ID_TEMPLATE2( type )                                       \
    1208             :     template type* eq::server::Config::Super::find< type >( const uint128_t& );
    1209             : 
    1210             : FIND_ID_TEMPLATE2( eq::server::Canvas );
    1211             : FIND_ID_TEMPLATE2( eq::server::Channel );
    1212             : FIND_ID_TEMPLATE2( eq::server::Layout );
    1213             : FIND_ID_TEMPLATE2( eq::server::Node );
    1214             : FIND_ID_TEMPLATE2( eq::server::Observer );
    1215             : FIND_ID_TEMPLATE2( eq::server::Pipe );
    1216             : FIND_ID_TEMPLATE2( eq::server::Segment );
    1217             : FIND_ID_TEMPLATE2( eq::server::View );
    1218             : FIND_ID_TEMPLATE2( eq::server::Window );
    1219             : 
    1220             : 
    1221             : #define FIND_NAME_TEMPLATE1( type )\
    1222             :     template void eq::server::Config::Super::find< type >( const std::string&, \
    1223             :                                                            const type** ) const;
    1224             : FIND_NAME_TEMPLATE1( eq::server::Canvas );
    1225             : FIND_NAME_TEMPLATE1( eq::server::Channel );
    1226             : FIND_NAME_TEMPLATE1( eq::server::Layout );
    1227             : FIND_NAME_TEMPLATE1( eq::server::Node );
    1228             : FIND_NAME_TEMPLATE1( eq::server::Observer );
    1229             : FIND_NAME_TEMPLATE1( eq::server::Pipe );
    1230             : FIND_NAME_TEMPLATE1( eq::server::Segment );
    1231             : FIND_NAME_TEMPLATE1( eq::server::View );
    1232             : FIND_NAME_TEMPLATE1( eq::server::Window );
    1233             : 
    1234             : #define FIND_NAME_TEMPLATE2( type )                                     \
    1235             :     template type*                                                      \
    1236             :     eq::server::Config::Super::find< type >( const std::string& );
    1237             : 
    1238             : FIND_NAME_TEMPLATE2( eq::server::Canvas );
    1239             : FIND_NAME_TEMPLATE2( eq::server::Channel );
    1240             : FIND_NAME_TEMPLATE2( eq::server::Layout );
    1241             : FIND_NAME_TEMPLATE2( eq::server::Node );
    1242             : FIND_NAME_TEMPLATE2( eq::server::Observer );
    1243             : FIND_NAME_TEMPLATE2( eq::server::Pipe );
    1244             : FIND_NAME_TEMPLATE2( eq::server::Segment );
    1245             : FIND_NAME_TEMPLATE2( eq::server::View );
    1246             : FIND_NAME_TEMPLATE2( eq::server::Window );
    1247             : 
    1248             : #define CONST_FIND_NAME_TEMPLATE2( type )                               \
    1249             :     template const type*                                                \
    1250             :     eq::server::Config::Super::find< type >( const std::string& ) const;
    1251             : 
    1252             : CONST_FIND_NAME_TEMPLATE2( eq::server::Canvas );
    1253             : CONST_FIND_NAME_TEMPLATE2( eq::server::Channel );
    1254             : CONST_FIND_NAME_TEMPLATE2( eq::server::Layout );
    1255             : CONST_FIND_NAME_TEMPLATE2( eq::server::Node );
    1256             : CONST_FIND_NAME_TEMPLATE2( eq::server::Observer );
    1257             : CONST_FIND_NAME_TEMPLATE2( eq::server::Pipe );
    1258             : CONST_FIND_NAME_TEMPLATE2( eq::server::Segment );
    1259             : CONST_FIND_NAME_TEMPLATE2( eq::server::View );
    1260          27 : CONST_FIND_NAME_TEMPLATE2( eq::server::Window );

Generated by: LCOV version 1.10