LCOV - code coverage report
Current view: top level - eq/server - config.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 314 615 51.1 %
Date: 2016-09-29 05:02:09 Functions: 40 75 53.3 %

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

Generated by: LCOV version 1.11