Line data Source code
1 :
2 : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Cedric Stalder <cedric.stalder@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 "node.h"
21 :
22 : #include "channel.h"
23 : #include "config.h"
24 : #include "global.h"
25 : #include "log.h"
26 : #include "nodeFactory.h"
27 : #include "pipe.h"
28 : #include "server.h"
29 : #include "window.h"
30 :
31 : #include <eq/fabric/commands.h>
32 : #include <eq/fabric/elementVisitor.h>
33 : #include <eq/fabric/event.h>
34 : #include <eq/fabric/paths.h>
35 :
36 : #include <co/barrier.h>
37 : #include <co/global.h>
38 : #include <co/objectICommand.h>
39 :
40 : #include <lunchbox/clock.h>
41 : #include <lunchbox/os.h>
42 : #include <lunchbox/sleep.h>
43 :
44 : #include <boost/filesystem/operations.hpp>
45 : #include <boost/filesystem/path.hpp>
46 :
47 : namespace eq
48 : {
49 : namespace server
50 : {
51 : typedef fabric::Node< Config, Node, Pipe, NodeVisitor > Super;
52 : typedef co::CommandFunc<Node> NodeFunc;
53 : namespace
54 : {
55 : #define S_MAKE_ATTR_STRING( attr ) ( std::string("EQ_NODE_") + #attr )
56 56 : std::string _sAttributeStrings[] = {
57 : S_MAKE_ATTR_STRING( SATTR_LAUNCH_COMMAND )
58 28 : };
59 56 : std::string _cAttributeStrings[] = {
60 : S_MAKE_ATTR_STRING( CATTR_LAUNCH_COMMAND_QUOTE )
61 28 : };
62 :
63 0 : void _addEnv( std::ostringstream& stream, const char* key )
64 : {
65 0 : char* env = getenv( key );
66 0 : if( env )
67 0 : stream << key << "=" << env << " ";
68 0 : }
69 :
70 0 : bool _containsPrefix( const std::string& str, const Strings& prefixes )
71 : {
72 0 : for( const auto& prefix : { "LB_", "CO_", "EQ_", "DEFLECT_" })
73 0 : if( str.find( prefix ) == 0 )
74 0 : return true;
75 :
76 0 : for( const auto& prefix : prefixes )
77 0 : if( str.find( prefix ) == 0 )
78 0 : return true;
79 :
80 0 : return false;
81 : }
82 : }
83 :
84 862 : Node::Node( Config* parent )
85 : : Super( parent )
86 : , _active( 0 )
87 : , _finishedFrame( 0 )
88 : , _flushedFrame( 0 )
89 : , _state( STATE_STOPPED )
90 862 : , _bufferedTasks( new co::BufferConnection )
91 1724 : , _lastDrawPipe( 0 )
92 : {
93 862 : const Global* global = Global::instance();
94 1724 : for( int i=0; i < Node::SATTR_LAST; ++i )
95 : {
96 862 : const SAttribute attr = static_cast< SAttribute >( i );
97 862 : setSAttribute( attr, global->getNodeSAttribute( attr ));
98 : }
99 1724 : for( int i=0; i < Node::CATTR_LAST; ++i )
100 : {
101 862 : const CAttribute attr = static_cast< CAttribute >( i );
102 862 : setCAttribute( attr, global->getNodeCAttribute( attr ));
103 : }
104 3448 : for( int i = 0; i < IATTR_LAST; ++i )
105 : {
106 2586 : const IAttribute attr = static_cast< IAttribute >( i );
107 2586 : setIAttribute( attr, global->getNodeIAttribute( attr ));
108 : }
109 862 : }
110 :
111 1720 : Node::~Node()
112 : {
113 1720 : }
114 :
115 4 : void Node::attach( const uint128_t& id, const uint32_t instanceID )
116 : {
117 4 : Super::attach( id, instanceID );
118 :
119 4 : co::CommandQueue* cmdQ = getCommandThreadQueue();
120 : registerCommand( fabric::CMD_OBJECT_SYNC,
121 4 : NodeFunc( this, &Node::_cmdSync ), cmdQ );
122 : registerCommand( fabric::CMD_NODE_CONFIG_INIT_REPLY,
123 4 : NodeFunc( this, &Node::_cmdConfigInitReply ), cmdQ );
124 : registerCommand( fabric::CMD_NODE_CONFIG_EXIT_REPLY,
125 4 : NodeFunc( this, &Node::_cmdConfigExitReply ), cmdQ );
126 : registerCommand( fabric::CMD_NODE_FRAME_FINISH_REPLY,
127 4 : NodeFunc( this, &Node::_cmdFrameFinishReply ), cmdQ );
128 4 : }
129 :
130 20 : ServerPtr Node::getServer()
131 : {
132 20 : return getConfig() ? getConfig()->getServer() : 0;
133 : }
134 :
135 0 : ConstServerPtr Node::getServer() const
136 : {
137 0 : return getConfig() ? getConfig()->getServer() : 0;
138 : }
139 :
140 12 : co::CommandQueue* Node::getMainThreadQueue()
141 : {
142 12 : return getConfig()->getMainThreadQueue();
143 : }
144 :
145 20 : co::CommandQueue* Node::getCommandThreadQueue()
146 : {
147 20 : return getConfig()->getCommandThreadQueue();
148 : }
149 :
150 0 : Channel* Node::getChannel( const ChannelPath& path )
151 : {
152 0 : const Pipes& pipes = getPipes();
153 0 : LBASSERT( pipes.size() > path.pipeIndex );
154 :
155 0 : if( pipes.size() <= path.pipeIndex )
156 0 : return 0;
157 :
158 0 : return pipes[ path.pipeIndex ]->getChannel( path );
159 : }
160 :
161 4 : void Node::addTasks( const uint32_t tasks )
162 : {
163 4 : setTasks( getTasks() | tasks );
164 4 : }
165 :
166 2 : void Node::activate()
167 : {
168 2 : ++_active;
169 2 : LBLOG( LOG_VIEW ) << "activate: " << _active << std::endl;
170 2 : }
171 :
172 2 : void Node::deactivate()
173 : {
174 2 : LBASSERT( _active != 0 );
175 2 : --_active;
176 2 : LBLOG( LOG_VIEW ) << "deactivate: " << _active << std::endl;
177 2 : };
178 :
179 862 : void Node::setSAttribute( const SAttribute attr, const std::string& value )
180 : {
181 862 : _sAttributes[attr] = value;
182 862 : }
183 :
184 432 : const std::string& Node::getSAttribute( const SAttribute attr ) const
185 : {
186 432 : return _sAttributes[attr];
187 : }
188 :
189 682 : const std::string& Node::getSAttributeString( const SAttribute attr )
190 : {
191 682 : return _sAttributeStrings[attr];
192 : }
193 :
194 862 : void Node::setCAttribute( const CAttribute attr, const char value )
195 : {
196 862 : _cAttributes[attr] = value;
197 862 : }
198 :
199 432 : char Node::getCAttribute( const CAttribute attr ) const
200 : {
201 432 : return _cAttributes[attr];
202 : }
203 :
204 682 : const std::string& Node::getCAttributeString( const CAttribute attr )
205 : {
206 682 : return _cAttributeStrings[attr];
207 : }
208 :
209 : //===========================================================================
210 : // Operations
211 : //===========================================================================
212 :
213 : //---------------------------------------------------------------------------
214 : // launch and connect
215 : //---------------------------------------------------------------------------
216 :
217 : namespace
218 : {
219 0 : class NetNode : public co::Node
220 : {
221 : public:
222 0 : NetNode( server::Node& node ) : co::Node(), _node( node ) {}
223 :
224 : private:
225 : server::Node& _node;
226 :
227 0 : std::string getWorkDir() const override
228 0 : { return _node.getConfig()->getWorkDir(); }
229 :
230 0 : std::string getLaunchQuote() const override
231 : {
232 : return std::string( 1, _node.getCAttribute(
233 0 : server::Node::CATTR_LAUNCH_COMMAND_QUOTE ));
234 : }
235 : };
236 :
237 0 : static co::NodePtr _createNetNode( Node* node )
238 : {
239 0 : co::NodePtr netNode = new NetNode( *node );
240 : const co::ConnectionDescriptions& descriptions =
241 0 : node->getConnectionDescriptions();
242 0 : for( co::ConnectionDescriptionPtr desc : descriptions )
243 : {
244 : netNode->addConnectionDescription(
245 0 : new co::ConnectionDescription( *desc ));
246 :
247 0 : if( node->getHost().empty( ))
248 : {
249 0 : node->setHost( desc->getHostname( ));
250 0 : LBWARN << "No host specified, guessing " << node->getHost()
251 0 : << " from " << desc << std::endl;
252 : }
253 0 : }
254 :
255 0 : netNode->setHostname( node->getHost( ));
256 0 : return netNode;
257 : }
258 : }
259 :
260 2 : bool Node::connect()
261 : {
262 2 : LBASSERT( isActive( ));
263 :
264 2 : if( _node )
265 2 : return _node->isConnected();
266 :
267 0 : if( !isStopped( ))
268 : {
269 0 : LBASSERT( _state == STATE_FAILED );
270 0 : return true;
271 : }
272 :
273 0 : co::LocalNodePtr localNode = getLocalNode();
274 0 : LBASSERT( localNode );
275 :
276 0 : _node = _createNetNode( this );
277 :
278 0 : LBLOG( LOG_INIT ) << "Connecting node" << std::endl;
279 0 : if( localNode->connect( _node ) ||
280 0 : localNode->launch( _node, _createLaunchCommand( )))
281 : {
282 0 : return true;
283 : }
284 :
285 0 : LBWARN << "Connection to " << _node->getNodeID() << " failed" << std::endl;
286 0 : _state = STATE_FAILED;
287 0 : _node = nullptr;
288 0 : return false;
289 : }
290 :
291 2 : bool Node::syncLaunch( const lunchbox::Clock& clock )
292 : {
293 2 : LBASSERT( isActive( ));
294 :
295 2 : if( !_node )
296 0 : return false;
297 :
298 2 : if( _node->isConnected( ))
299 2 : return true;
300 :
301 0 : LBASSERT( !isApplicationNode( ));
302 :
303 0 : co::LocalNodePtr localNode = getLocalNode();
304 0 : const int64_t timeOut = getIAttribute( IATTR_LAUNCH_TIMEOUT );
305 0 : _node = localNode->syncLaunch( _node->getNodeID(),
306 : std::max( int64_t( 0 ),
307 0 : timeOut - clock.getTime64( )));
308 0 : if( _node )
309 0 : return true;
310 :
311 0 : sendError( fabric::ERROR_NODE_CONNECT ) << _host;
312 0 : _state = STATE_FAILED;
313 0 : return false;
314 : }
315 :
316 0 : std::string Node::_createLaunchCommand() const
317 : {
318 0 : const std::string& command = getSAttribute( SATTR_LAUNCH_COMMAND );
319 0 : const size_t commandPos = command.find( "%c" );
320 0 : if( commandPos == std::string::npos )
321 0 : return command + " " + _createRemoteCommand();
322 :
323 0 : return command.substr( 0, commandPos ) + _createRemoteCommand() +
324 0 : command.substr( commandPos + 2 );
325 : }
326 :
327 0 : std::string Node::_createRemoteCommand() const
328 : {
329 0 : const Config* config = getConfig();
330 0 : std::string program = config->getRenderClient();
331 0 : if( program.empty( ))
332 : {
333 0 : LBWARN << "No render client name, auto-launch will fail" << std::endl;
334 0 : return program;
335 : }
336 :
337 : //----- environment
338 0 : std::ostringstream os;
339 0 : const std::string& quote = _node->getLaunchQuote();
340 :
341 : //----- program + args
342 : #ifndef WIN32
343 : # ifdef Darwin
344 : const char libPath[] = "DYLD_LIBRARY_PATH";
345 : # else
346 0 : const char libPath[] = "LD_LIBRARY_PATH";
347 : # endif
348 :
349 0 : os << "env ";
350 0 : _addEnv( os, libPath );
351 0 : _addEnv( os, "PATH" );
352 0 : _addEnv( os, "PYTHONPATH" );
353 : #ifdef EQUALIZER_USE_DEFLECT
354 0 : _addEnv( os, "DEFLECT_HOST" );
355 0 : _addEnv( os, "DEFLECT_ID" );
356 : #endif
357 :
358 0 : const Strings& prefixes = config->getRenderClientEnvPrefixes();
359 0 : for( int i=0; environ[i] != 0; ++i )
360 : {
361 0 : const std::string var = environ[i];
362 0 : if( _containsPrefix( var, prefixes ))
363 0 : os << quote << var << quote << " ";
364 0 : }
365 :
366 0 : os << "LB_LOG_LEVEL=" <<lunchbox::Log::getLogLevelString() << " ";
367 0 : if( lunchbox::Log::topics != 0 )
368 0 : os << "LB_LOG_TOPICS=" <<lunchbox::Log::topics << " ";
369 : #endif
370 :
371 : const boost::filesystem::path absolute =
372 0 : boost::filesystem::system_complete( boost::filesystem::path( program ));
373 0 : program = absolute.string();
374 :
375 0 : std::string options;
376 0 : for( const std::string& arg : config->getRenderClientArgs( ))
377 0 : options += std::string( " " ) + quote + arg + quote;
378 0 : return os.str() + quote + program + quote + options + " -- --eq-client %o ";
379 : }
380 :
381 : //---------------------------------------------------------------------------
382 : // init
383 : //---------------------------------------------------------------------------
384 2 : void Node::configInit( const uint128_t& initID, const uint32_t frameNumber )
385 : {
386 2 : LBASSERT( _state == STATE_STOPPED );
387 2 : _state = STATE_INITIALIZING;
388 :
389 2 : const Config* config = getConfig();
390 2 : _flushedFrame = config->getFinishedFrame();
391 2 : _finishedFrame = config->getFinishedFrame();
392 2 : _frameIDs.clear();
393 :
394 2 : LBLOG( LOG_INIT ) << "Create node" << std::endl;
395 2 : getConfig()->send( _node, fabric::CMD_CONFIG_CREATE_NODE ) << getID();
396 :
397 2 : LBLOG( LOG_INIT ) << "Init node" << std::endl;
398 2 : send( fabric::CMD_NODE_CONFIG_INIT ) << initID << frameNumber;
399 2 : }
400 :
401 2 : bool Node::syncConfigInit()
402 : {
403 2 : LBASSERT( _state == STATE_INITIALIZING || _state == STATE_INIT_SUCCESS ||
404 : _state == STATE_INIT_FAILED );
405 :
406 2 : _state.waitNE( STATE_INITIALIZING );
407 :
408 2 : if( _state == STATE_INIT_SUCCESS )
409 : {
410 2 : _state = STATE_RUNNING;
411 2 : return true;
412 : }
413 :
414 0 : LBWARN << "Node initialization failed" << std::endl;
415 0 : configExit();
416 0 : return false;
417 : }
418 :
419 : //---------------------------------------------------------------------------
420 : // exit
421 : //---------------------------------------------------------------------------
422 2 : void Node::configExit()
423 : {
424 2 : if( _state == STATE_EXITING )
425 2 : return;
426 :
427 2 : LBASSERT( _state == STATE_RUNNING || _state == STATE_INIT_FAILED );
428 2 : _state = STATE_EXITING;
429 :
430 2 : LBLOG( LOG_INIT ) << "Exit node" << std::endl;
431 2 : send( fabric::CMD_NODE_CONFIG_EXIT );
432 2 : flushSendBuffer();
433 : }
434 :
435 2 : bool Node::syncConfigExit()
436 : {
437 2 : LBASSERT( _state == STATE_EXITING || _state == STATE_EXIT_SUCCESS ||
438 : _state == STATE_EXIT_FAILED );
439 :
440 2 : _state.waitNE( STATE_EXITING );
441 2 : const bool success = ( _state == STATE_EXIT_SUCCESS );
442 2 : LBASSERT( success || _state == STATE_EXIT_FAILED );
443 :
444 2 : _state = isActive() ? STATE_FAILED : STATE_STOPPED;
445 2 : setTasks( fabric::TASK_NONE );
446 2 : _frameIDs.clear();
447 2 : _flushBarriers();
448 2 : return success;
449 : }
450 :
451 : //---------------------------------------------------------------------------
452 : // update
453 : //---------------------------------------------------------------------------
454 0 : void Node::update( const uint128_t& frameID, const uint32_t frameNumber )
455 : {
456 0 : if( !isRunning( ))
457 0 : return;
458 :
459 0 : LBVERB << "Start frame " << frameNumber << std::endl;
460 0 : LBASSERT( isActive( ));
461 :
462 0 : _frameIDs[ frameNumber ] = frameID;
463 :
464 0 : uint128_t configVersion = co::VERSION_INVALID;
465 0 : if( !isApplicationNode( )) // synced in Config::_cmdFrameStart
466 0 : configVersion = getConfig()->getVersion();
467 :
468 : send( fabric::CMD_NODE_FRAME_START )
469 0 : << getVersion() << configVersion << frameID << frameNumber;
470 0 : LBLOG( LOG_TASKS ) << "TASK node start frame " << std::endl;
471 :
472 0 : const Pipes& pipes = getPipes();
473 0 : for( Pipes::const_iterator i = pipes.begin(); i != pipes.end(); ++i )
474 0 : (*i)->update( frameID, frameNumber );
475 :
476 0 : if( !_lastDrawPipe ) // no FrameDrawFinish sent
477 : {
478 0 : send( fabric::CMD_NODE_FRAME_DRAW_FINISH ) << frameID << frameNumber;
479 0 : LBLOG( LOG_TASKS ) << "TASK node draw finish " << getName() << " "
480 0 : << std::endl;
481 : }
482 0 : _lastDrawPipe = 0;
483 :
484 0 : send( fabric::CMD_NODE_FRAME_TASKS_FINISH ) << frameID << frameNumber;
485 0 : LBLOG( LOG_TASKS ) << "TASK node tasks finish " << std::endl;
486 :
487 0 : _finish( frameNumber );
488 0 : flushSendBuffer();
489 : }
490 :
491 0 : uint32_t Node::_getFinishLatency() const
492 : {
493 0 : switch( getIAttribute( Node::IATTR_THREAD_MODEL ))
494 : {
495 : case fabric::UNDEFINED:
496 : case fabric::DRAW_SYNC:
497 0 : if( getTasks() & fabric::TASK_DRAW )
498 : {
499 : // More than one frame latency doesn't make sense, since the
500 : // draw sync for frame+1 does not allow for more
501 0 : const Config* config = getConfig();
502 0 : const uint32_t latency = config->getLatency();
503 :
504 0 : return LB_MIN( latency, 1 );
505 : }
506 0 : break;
507 :
508 : case fabric::LOCAL_SYNC:
509 0 : if( getTasks() != fabric::TASK_NONE )
510 : // local sync enforces no latency
511 0 : return 0;
512 0 : break;
513 :
514 : case fabric::ASYNC:
515 0 : break;
516 : default:
517 0 : LBUNIMPLEMENTED;
518 : }
519 :
520 0 : const Config* config = getConfig();
521 0 : return config->getLatency();
522 : }
523 :
524 0 : void Node::_finish( const uint32_t currentFrame )
525 : {
526 0 : const Pipes& pipes = getPipes();
527 0 : for( Pipes::const_iterator i = pipes.begin(); i != pipes.end(); ++i )
528 : {
529 0 : const Pipe* pipe = *i;
530 0 : if( pipe->getIAttribute( Pipe::IATTR_HINT_THREAD ) && pipe->isRunning())
531 : {
532 0 : const uint32_t latency = _getFinishLatency();
533 0 : if( currentFrame > latency )
534 0 : flushFrames( currentFrame - latency );
535 0 : return;
536 : }
537 : }
538 :
539 : // else only non-threaded pipes, all local tasks are done, send finish now.
540 0 : flushFrames( currentFrame );
541 : }
542 :
543 0 : void Node::flushFrames( const uint32_t frameNumber )
544 : {
545 0 : LBLOG( LOG_TASKS ) << "Flush frames including " << frameNumber << std::endl;
546 :
547 0 : while( _flushedFrame < frameNumber )
548 : {
549 0 : ++_flushedFrame;
550 0 : _sendFrameFinish( _flushedFrame );
551 : }
552 :
553 0 : flushSendBuffer();
554 0 : }
555 :
556 0 : void Node::_sendFrameFinish( const uint32_t frameNumber )
557 : {
558 0 : FrameIDHash::iterator i = _frameIDs.find( frameNumber );
559 0 : if( i == _frameIDs.end( ))
560 0 : return; // finish already send
561 :
562 0 : send( fabric::CMD_NODE_FRAME_FINISH ) << i->second << frameNumber;
563 0 : _frameIDs.erase( i );
564 0 : LBLOG( LOG_TASKS ) << "TASK node finish frame " << frameNumber << std::endl;
565 : }
566 :
567 : //---------------------------------------------------------------------------
568 : // Barrier cache
569 : //---------------------------------------------------------------------------
570 0 : co::Barrier* Node::getBarrier()
571 : {
572 0 : if( _barriers.empty( ))
573 : {
574 : co::Barrier* barrier = new co::Barrier( getServer(),
575 0 : _node->getNodeID( ));
576 0 : barrier->setAutoObsolete( getConfig()->getLatency() + 1 );
577 0 : return barrier;
578 : }
579 : // else
580 :
581 0 : co::Barrier* barrier = _barriers.back();
582 0 : _barriers.pop_back();
583 0 : barrier->setHeight( 0 );
584 0 : return barrier;
585 : }
586 :
587 0 : void Node::changeLatency( const uint32_t latency )
588 : {
589 0 : for( co::Barriers::const_iterator i = _barriers.begin();
590 0 : i != _barriers.end(); ++ i )
591 : {
592 0 : co::Barrier* barrier = *i;
593 0 : barrier->setAutoObsolete( latency + 1 );
594 : }
595 0 : }
596 :
597 0 : void Node::releaseBarrier( co::Barrier* barrier )
598 : {
599 0 : _barriers.push_back( barrier );
600 0 : }
601 :
602 2 : void Node::_flushBarriers()
603 : {
604 2 : for( co::BarriersCIter i =_barriers.begin(); i != _barriers.end(); ++i )
605 0 : delete *i;
606 2 : _barriers.clear();
607 2 : }
608 :
609 0 : bool Node::removeConnectionDescription( co::ConnectionDescriptionPtr cd )
610 : {
611 : // Don't use std::find, RefPtr::operator== compares pointers, not values.
612 0 : for(co::ConnectionDescriptions::iterator i=_connectionDescriptions.begin();
613 0 : i != _connectionDescriptions.end(); ++i )
614 : {
615 0 : if( *cd != **i )
616 0 : continue;
617 :
618 0 : _connectionDescriptions.erase( i );
619 0 : return true;
620 : }
621 0 : return false;
622 : }
623 :
624 4 : co::ObjectOCommand Node::send( const uint32_t cmd )
625 : {
626 4 : return send( cmd, getID( ));
627 : }
628 :
629 22 : co::ObjectOCommand Node::send( const uint32_t cmd, const uint128_t& id )
630 : {
631 : return co::ObjectOCommand( co::Connections( 1, _bufferedTasks ), cmd,
632 22 : co::COMMANDTYPE_OBJECT, id, CO_INSTANCE_ALL );
633 : }
634 :
635 0 : EventOCommand Node::sendError( const uint32_t error )
636 : {
637 0 : return getConfig()->sendError( Event::NODE_ERROR, Error( error, getID( )));
638 : }
639 :
640 12 : void Node::flushSendBuffer()
641 : {
642 12 : _bufferedTasks->sendBuffer( _node->getConnection( ));
643 12 : }
644 :
645 : //===========================================================================
646 : // command handling
647 : //===========================================================================
648 2 : bool Node::_cmdConfigInitReply( co::ICommand& cmd )
649 : {
650 2 : co::ObjectICommand command( cmd );
651 2 : LBVERB << "handle configInit reply " << command << std::endl;
652 2 : LBASSERT( _state == STATE_INITIALIZING );
653 2 : _state = command.read< uint64_t >() ? STATE_INIT_SUCCESS : STATE_INIT_FAILED;
654 :
655 2 : return true;
656 : }
657 :
658 2 : bool Node::_cmdConfigExitReply( co::ICommand& cmd )
659 : {
660 2 : co::ObjectICommand command( cmd );
661 2 : LBVERB << "handle configExit reply " << command << std::endl;
662 2 : LBASSERT( _state == STATE_EXITING );
663 :
664 2 : _state = command.read< bool >() ? STATE_EXIT_SUCCESS : STATE_EXIT_FAILED;
665 2 : return true;
666 : }
667 :
668 0 : bool Node::_cmdFrameFinishReply( co::ICommand& cmd )
669 : {
670 0 : co::ObjectICommand command( cmd );
671 0 : LBVERB << "handle frame finish reply " << command << std::endl;
672 :
673 0 : const uint32_t frameNumber = command.read< uint32_t >();
674 :
675 0 : _finishedFrame = frameNumber;
676 0 : getConfig()->notifyNodeFrameFinished( frameNumber );
677 :
678 0 : return true;
679 : }
680 :
681 432 : void Node::output( std::ostream& os ) const
682 : {
683 432 : if( !_host.empty( ))
684 258 : os << "host \"" << _host << '"' << std::endl;
685 :
686 432 : const co::ConnectionDescriptions& descriptions = _connectionDescriptions;
687 2202 : for( co::ConnectionDescriptions::const_iterator i = descriptions.begin();
688 1468 : i != descriptions.end(); ++i )
689 : {
690 302 : co::ConnectionDescriptionPtr desc = *i;
691 302 : os << *desc;
692 302 : }
693 :
694 432 : bool attrPrinted = false;
695 :
696 1728 : for( Node::SAttribute i = static_cast<Node::SAttribute>( 0 );
697 864 : i < Node::SATTR_LAST;
698 : i = static_cast<Node::SAttribute>( static_cast<uint32_t>( i )+1))
699 : {
700 432 : const std::string& value = getSAttribute( i );
701 432 : if( value == Global::instance()->getNodeSAttribute( i ))
702 432 : continue;
703 :
704 0 : if( !attrPrinted )
705 : {
706 0 : os << std::endl << "attributes" << std::endl;
707 0 : os << "{" << std::endl << lunchbox::indent;
708 0 : attrPrinted = true;
709 : }
710 :
711 : os << ( i==Node::SATTR_LAUNCH_COMMAND ? "launch_command " :
712 0 : "ERROR" )
713 0 : << "\"" << value << "\"" << std::endl;
714 : }
715 :
716 1728 : for( Node::CAttribute i = static_cast<Node::CAttribute>( 0 );
717 864 : i < Node::CATTR_LAST;
718 : i = static_cast<Node::CAttribute>( static_cast<uint32_t>( i )+1))
719 : {
720 432 : const char value = getCAttribute( i );
721 432 : if( value == Global::instance()->getNodeCAttribute( i ))
722 432 : continue;
723 :
724 0 : if( !attrPrinted )
725 : {
726 0 : os << std::endl << "attributes" << std::endl;
727 0 : os << "{" << std::endl << lunchbox::indent;
728 0 : attrPrinted = true;
729 : }
730 :
731 : os << ( i==Node::CATTR_LAUNCH_COMMAND_QUOTE ? "launch_command_quote " :
732 0 : "ERROR" )
733 0 : << "'" << value << "'" << std::endl;
734 : }
735 :
736 3456 : for( Node::IAttribute i = static_cast< Node::IAttribute>( 0 );
737 1728 : i < Node::IATTR_LAST;
738 : i = static_cast< Node::IAttribute >( static_cast<uint32_t>( i )+1))
739 : {
740 1296 : const int value = getIAttribute( i );
741 1296 : if( value == Global::instance()->getNodeIAttribute( i ))
742 1296 : continue;
743 :
744 0 : if( !attrPrinted )
745 : {
746 0 : os << std::endl << "attributes" << std::endl;
747 0 : os << "{" << std::endl << lunchbox::indent;
748 0 : attrPrinted = true;
749 : }
750 :
751 : os << ( i== Node::IATTR_LAUNCH_TIMEOUT ? "launch_timeout " :
752 : i== Node::IATTR_THREAD_MODEL ? "thread_model " :
753 : i== Node::IATTR_HINT_AFFINITY ? "hint_affinity " :
754 0 : "ERROR" )
755 0 : << static_cast< fabric::IAttribute >( value ) << std::endl;
756 : }
757 :
758 432 : if( attrPrinted )
759 0 : os << lunchbox::exdent << "}" << std::endl << std::endl;
760 432 : }
761 :
762 : }
763 : }
764 :
765 : #include "../fabric/node.ipp"
766 : template class eq::fabric::Node< eq::server::Config, eq::server::Node,
767 : eq::server::Pipe, eq::server::NodeVisitor >;
768 : /** @cond IGNORE */
769 : template std::ostream& eq::fabric::operator << ( std::ostream&,
770 84 : const eq::server::Super& );
771 : /** @endcond */
|