root/juggler/branches/2.2/modules/gadgeteer/cluster/ClusterManager.cpp

Revision 20718, 31.2 kB (checked in by patrick, 1 year ago)

Fixed mis-ordered arguments to the clrOutBOLD() macro.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
<
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998-2007 by Iowa State University
4  *
5  * Original Authors:
6  *   Allen Bierbaum, Christopher Just,
7  *   Patrick Hartling, Kevin Meinert,
8  *   Carolina Cruz-Neira, Albert Baker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  *************** <auto-copyright.pl END do not edit this line> ***************/
26
27 #include <gadget/gadgetConfig.h>
28
29 #include <iomanip>
30 #include <sstream>
31 #include <boost/filesystem/path.hpp>
32 #include <boost/filesystem/exception.hpp>
33
34 #include <vpr/vprTypes.h>
35 #include <vpr/System.h>
36 #include <vpr/DynLoad/LibraryLoader.h>
37 #include <vpr/Util/FileUtils.h>
38
39 #include <jccl/Config/ConfigDefinitionPtr.h>
40 #include <jccl/Config/ConfigDefinition.h>
41 #include <jccl/RTRC/ConfigManager.h>
42 #include <jccl/RTRC/DependencyManager.h>
43
44 #include <gadget/gadgetParam.h>
45 #include <gadget/Type/DeviceFactory.h>
46 #include <gadget/Node.h>
47 #include <gadget/Util/Debug.h>
48 #include <gadget/Util/PathHelpers.h>
49 #include <gadget/Util/PluginVersionException.h>
50
51 #include <cluster/ClusterNetwork.h>
52 #include <cluster/ClusterPlugin.h>
53 #include <cluster/Packets/EndBlock.h>
54 #include <cluster/ClusterManager.h>
55
56
57 namespace fs = boost::filesystem;
58
59 namespace cluster
60 {
61    vprSingletonImp( ClusterManager );
62
63    /**
64     * This struct implements a callable object (a functor, basically).  An
65     * instance can be passed in where a boost::function1<bool, void*> is
66     * expected.  In cluster::ClusterManager::configAdd(), instances are used
67     * to handle version checking of cluster plug-ins via vpr::LibraryLoader.
68     */
69    struct VersionCheckCallable
70    {
71       VersionCheckCallable()
72       {
73       }
74
75       /**
76        * This will be invoked as a callback by methods of vpr::LibraryLoader.
77        *
78        * @param func A function pointer for the entry point in a dynamically
79        *             loaded cluster plug-in.  This must be cast to the correct
80        *             signature before being invoked.
81        */
82       bool operator()(void* func)
83       {
84          vpr::Uint32 (*version_func)();
85          version_func = (vpr::Uint32 (*)()) func;
86
87          // Call the entry point function, which, in this case, returns the
88          // version of Gadgeteer against which the plug-in was compiled.
89          const vpr::Uint32 plugin_gadget_ver = (*version_func)();
90
91          if ( plugin_gadget_ver != mGadgetVersion )
92          {
93             std::ostringstream msg_stream;
94             msg_stream << "Gadgeteer version mismatch!\n"
95                        << "Cluster plug-in was compiled against Gadgeteer "
96                        << "version " << plugin_gadget_ver << ",\n"
97                        << "but this is Gadgeteer version " << mGadgetVersion
98                        << std::endl;
99             throw gadget::PluginVersionException(msg_stream.str(),
100                                                  VPR_LOCATION);
101          }
102
103          return true;
104       }
105
106       static const vpr::Uint32 mGadgetVersion;
107    };
108
109    const vpr::Uint32 VersionCheckCallable::mGadgetVersion(__GADGET_version);
110
111    /**
112     * This struct implements a callable object (a functor, basically).  An
113     * instance can be passed in where a boost::function1<bool, void*> is
114     * expected.  In cluster::ClusterManager::configAdd(), instances are used
115     * to handle dynamic loading of cluster plugins via vpr::LibraryLoader.
116     */
117    struct PluginInitCallable
118    {
119       PluginInitCallable(cluster::ClusterManager* clusterMgr)
120          : mgr(clusterMgr)
121       {
122       }
123
124       /**
125        * This will be invoked as a callback by methods of vpr::LibraryLoader.
126        *
127        * @param func A function pointer for the entry point in a dynamically
128        *             loaded cluster plug-in.  This must be cast to the correct
129        *             signature before being invoked.
130        */
131       bool operator()( void* func )
132       {
133          void (*init_func)(ClusterManager*);
134
135          // Cast the entry point function to the correct signature so that we
136          // can call it.  All dynamically loaded plug-ins must have an entry
137          // point function that takes a pointer to a cluster::ClusterManager
138          // instance and returns nothing.
139          init_func = (void (*)(ClusterManager*)) func;
140
141          // Call the entry point function.
142          (*init_func)( mgr );
143
144          return true;
145       }
146
147       cluster::ClusterManager* mgr;
148    };
149
150    ClusterManager::ClusterManager()
151       : mClusterActive( false )
152       , mClusterReady( false )
153       , mPreDrawCallCount(0)
154       , mPostPostFrameCallCount(0)
155    {
156       mClusterNetwork = new ClusterNetwork();
157       jccl::ConfigManager::instance()->addConfigElementHandler( mClusterNetwork );
158       jccl::DependencyManager::instance()->registerChecker(&mDepChecker);
159    }
160
161    ClusterManager::~ClusterManager()
162    {
163       jccl::DependencyManager::instance()->unregisterChecker(&mDepChecker);
164    }
165
166    bool ClusterManager::isClusterReady()
167    {
168       // -If the cluster is active and not ready
169       //   -If a StartBarrier jccl::ConfigElement does not exist
170       //    -Warn the user and set cluster ready
171       //   -Get new value of mClusterReady from asking all plugins
172       // -Return the new mClusterReady
173
174       vpr::Guard<vpr::Mutex> ready_guard( mClusterReadyLock );
175       vpr::Guard<vpr::Mutex> active_guard( mClusterActiveLock );
176
177       if ( mClusterActive && !mClusterReady )
178       {
179          if ( !jccl::ConfigManager::instance()->hasElementType( "start_barrier_plugin" ) )
180          {
181             vprDEBUG(gadgetDBG_RIM, vprDBG_WARNING_LVL)
182                << clrOutBOLD(clrCYAN, "NOTE:") << std::endl << vprDEBUG_FLUSH;
183             vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_WARNING_LVL)
184                << "The start_barrier_plugin config element does not exist.\n"
185                << vprDEBUG_FLUSH;
186             vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_WARNING_LVL)
187                << "If your application depends on each node starting at the "
188                << "same time,\n" << vprDEBUG_FLUSH;
189             vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_WARNING_LVL)
190                << "then you should load and configure the Start Barrier "
191                << "Plug-in.\n" << vprDEBUG_FLUSH;
192
193             mClusterReady = true;
194          }
195       }
196       // Lock it here so that we can avoid confusion in pluginsReady()
197       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
198       return( mClusterReady && pluginsReady() );
199    }
200
201    bool ClusterManager::pluginsReady()
202    {
203       // Plugins are already locked since we only call this method from
204       // isClusterReady which is only called by
205       // StartBarrierPlugin::postPostFrame which has already locked the list
206       // of plugins.
207
208       //vpr::Guard<vpr::Mutex> guard(mPluginsLock);
209
210       for ( std::list<ClusterPlugin*>::iterator i = mPlugins.begin();
211             i != mPlugins.end();
212             ++i )
213       {
214          if ( !(*i)->isPluginReady() )
215          {
216             return false;
217          }
218       }
219
220       return true;
221    }
222
223    void ClusterManager::recoverFromLostNode( gadget::Node* lost_node )
224    {
225       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
226
227       for ( std::list<ClusterPlugin*>::iterator i = mPlugins.begin();
228             i != mPlugins.end();
229             ++i )
230       {
231          (*i)->recoverFromLostNode( lost_node );
232       }
233    }
234
235    /**
236     * Adds a new plugin to the ClusterManager.
237     */
238    void ClusterManager::addPlugin(ClusterPlugin* new_plugin)
239    {
240       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
241       if ( !doesPluginExist(new_plugin) )
242       {
243          mPlugins.push_back( new_plugin );
244          std::pair<vpr::GUID, ClusterPlugin*> p =
245             std::make_pair( new_plugin->getHandlerGUID(), new_plugin );
246          mPluginMap.insert( p );
247
248          // We should do this here, but since we do not add the manager until
249          // its configAdd currently you can see the problem
250          jccl::ConfigManager::instance()->addConfigElementHandler( new_plugin );
251          mClusterNetwork->addHandler( new_plugin );
252          //We can still unregister it when removed below though
253          vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_LVL )
254             << clrOutBOLD( clrCYAN, "[ClusterManager] " )
255             << "Adding Plugin: " << new_plugin->getPluginName()
256             << std::endl << vprDEBUG_FLUSH;
257       }
258    }
259
260    ClusterPlugin* ClusterManager::getPluginByGUID( const vpr::GUID& plugin_guid )
261    {
262       std::map<vpr::GUID, ClusterPlugin*>::const_iterator i =
263          mPluginMap.find( plugin_guid );
264       if( i != mPluginMap.end() )
265       {
266          return ( (*i).second );
267       }
268       return NULL;
269    }
270
271    /**
272     * Removes a plugin from the ClusterManager
273     */
274    void ClusterManager::removePlugin( ClusterPlugin* old_plugin )
275    {
276       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
277
278       mPluginMap.erase( old_plugin->getHandlerGUID() );
279
280       std::list<ClusterPlugin*>::iterator found
281          = std::find(mPlugins.begin(), mPlugins.end(), old_plugin);
282
283       if (mPlugins.end() != found)
284       {
285          vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_LVL )
286             << clrOutBOLD( clrCYAN, "[ClusterManager] " )
287             << "Removing Plugin: " << old_plugin->getPluginName()
288             << std::endl << vprDEBUG_FLUSH;
289          mPlugins.erase(found);
290          jccl::ConfigManager::instance()->removeConfigElementHandler(*found);
291       }
292    }
293
294    /**
295     * Checks if a plugin exists in the ClusterManager
296     */
297    bool ClusterManager::doesPluginExist( ClusterPlugin* old_plugin )
298    {
299       vprASSERT( mPluginsLock.test() == 1 &&
300                  "mManagers Lock must be aquired before calling ClusterManager::doesManagerExist()" );
301
302       std::list<ClusterPlugin*>::iterator found
303          = std::find(mPlugins.begin(), mPlugins.end(), old_plugin);
304
305       return (mPlugins.end() != found);
306    }
307
308    void ClusterManager::sendRequests()
309    {
310       // Idea is to not create frame lock if we do not need to
311       bool updateNeeded = false;
312       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
313
314       vprDEBUG( gadgetDBG_NET_MGR, vprDBG_HVERB_LVL )
315          << clrOutBOLD( clrCYAN,"[ClusterManager]" )
316          << " sendRequests" << std::endl << vprDEBUG_FLUSH;
317
318       for ( std::list<ClusterPlugin*>::iterator i = mPlugins.begin();
319             i != mPlugins.end();
320             ++i )
321       {
322          (*i)->sendRequests();
323          updateNeeded = true;
324       }
325
326       // Only send end blocks if we really need to.
327       if ( updateNeeded )
328       {
329          sendEndBlocksAndSignalUpdate(1);
330       }
331    }
332
333    void ClusterManager::preDraw()
334    {
335       // Idea is to not create frame lock if we do not need to
336       bool updateNeeded = false;
337       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
338
339       vprDEBUG( gadgetDBG_NET_MGR, vprDBG_HVERB_LVL )
340          << clrOutBOLD( clrCYAN,"[ClusterManager]" )
341          << " preDraw" << std::endl << vprDEBUG_FLUSH;
342
343       for ( std::list<ClusterPlugin*>::iterator i = mPlugins.begin();
344             i != mPlugins.end();
345             ++i )
346       {
347          (*i)->preDraw();
348          updateNeeded = true;
349       }
350       if ( updateNeeded )
351       {
352          mPreDrawCallCount++;
353          sendEndBlocksAndSignalUpdate(2);
354       }
355    }
356
357    void ClusterManager::postPostFrame()
358    {
359       // -If not running
360       //   -If all plugins ready
361       //     - isClusterReady
362
363
364       // Idea is to not create frame lock if we do not need to
365       bool updateNeeded = false;
366       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
367
368       vprDEBUG( gadgetDBG_NET_MGR, vprDBG_HVERB_LVL )
369          << clrOutBOLD( clrCYAN,"[ClusterManager]" )
370          << " postPostFrame" << std::endl << vprDEBUG_FLUSH;
371
372       for ( std::list<ClusterPlugin*>::iterator i = mPlugins.begin();
373             i != mPlugins.end();
374             ++i )
375       {
376          (*i)->postPostFrame();
377          updateNeeded = true;
378       }
379       if ( updateNeeded )
380       {
381          mPostPostFrameCallCount++;
382          sendEndBlocksAndSignalUpdate(3);
383       }
384    }
385
386    void ClusterManager::createBarrier()
387    {
388       vpr::Guard<vpr::Mutex> guard( mPluginsLock );
389
390       for ( std::list<ClusterPlugin*>::iterator i = mPlugins.begin();
391             i != mPlugins.end();
392             ++i )
393       {
394          //if ((*i)->isActive())
395          //{  // As soon as we find a plug-in that creates
396             // a barrier, we can continue. Maybe not since
397             // this will not match up on different machines
398             if ( (*i)->createBarrier() )
399             {
400                return;
401             }
402          //}
403       }
404    }
405
406    void ClusterManager::sendEndBlocksAndSignalUpdate( const int temp )
407    {
408       // If the network is not fully connected, then don't try to sync.
409       // Trying to sync a network that is not fully connected can lead to
410       // deadlock.
411       if ( mClusterNetwork->getNumPendingNodes() > 0 )
412       {
413          return;
414       }
415
416       cluster::EndBlock temp_end_block(temp);
417
418       // Used to accumulate the number of connected nodes.
419       size_t num_nodes(0);
420
421       typedef std::vector<gadget::Node*>::iterator iter_t;
422
423       for ( iter_t i = mClusterNetwork->getNodesBegin();
424             i != mClusterNetwork->getNodesEnd();
425             ++i )
426       {
427          if ( (*i)->isConnected() )
428          {
429             try
430             {
431                // Send End Block to the node.
432                (*i)->send(&temp_end_block);
433
434                // Indicate that this node is not up to date. It will be updated
435                // below.
436                (*i)->setUpdated(false);
437
438                ++num_nodes;
439             }
440             catch (cluster::ClusterException& ex)
441             {
442                vprDEBUG(gadgetDBG_RIM, vprDBG_CRITICAL_LVL)
443                   << clrOutBOLD(clrRED, "ERROR")
444                   << ": Failed to send end block to " << (*i)->getName()
445                   << std::endl << vprDEBUG_FLUSH;
446                vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_CRITICAL_LVL)
447                   << ex.what() << std::endl << vprDEBUG_FLUSH;
448                vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_CRITICAL_LVL)
449                   << "Shutting down the node." << std::endl << vprDEBUG_FLUSH;
450
451                (*i)->shutdown();
452             }
453          }
454       }
455
456       gadget::Reactor& reactor = mClusterNetwork->getReactor();
457       size_t completed_nodes(0);
458
459       while ( completed_nodes != num_nodes )
460       {
461          std::vector<gadget::Node*> ready_nodes =
462             //reactor.getReadyNodes(vpr::Interval::NoWait);
463             reactor.getReadyNodes(vpr::Interval::NoTimeout);
464
465          for ( iter_t i = ready_nodes.begin(); i != ready_nodes.end(); ++i )
466          {
467             // Make sure that we do not update nodes more than once simply
468             // because there is data ready to read from them. This is an
469             // unfortunate side effect of using a reactor in this clumsy way.
470             if ( (*i)->isUpdated() )
471             {
472                continue;
473             }
474
475             try
476             {
477                // Read network packets.
478                (*i)->update();
479             }
480             catch (cluster::ClusterException& ex)
481             {
482                vprDEBUG(gadgetDBG_RIM, vprDBG_CRITICAL_LVL)
483                   << clrOutBOLD(clrRED, "ERROR")
484                   << ": Failed to complete state update for "
485                   << (*i)->getName() << std::endl << vprDEBUG_FLUSH;
486                vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_CRITICAL_LVL)
487                   << ex.what() << std::endl << vprDEBUG_FLUSH;
488                vprDEBUG_NEXT(gadgetDBG_RIM, vprDBG_CRITICAL_LVL)
489                   << "Shutting down the node." << std::endl << vprDEBUG_FLUSH;
490
491                (*i)->shutdown();
492             }
493
494             // Record completed state. This happens regardless of whether
495             // the node update completed successfully. Since the node is
496             // shut down if update fails, we would never get completed_nodes
497             // to equal num_nodes otherwise.
498             ++completed_nodes;
499          }
500       }
501    }
502
503    bool ClusterManager::recognizeRemoteDeviceConfig( jccl::ConfigElementPtr element )
504    {
505       std::string tp("input_parent");
506       if ( element->getConfigDefinition()->isParent("input_device") &&
507            element->getNum("device_host") > 0 )
508       {
509          std::string device_host =
510             element->getProperty<std::string>( "device_host" );
511          //std::cout << "Checking: " << element->getName() << std::endl;
512          if ( !device_host.empty() )
513          {
514             // THIS IS A HACK: find a better way to do this
515             jccl::ConfigElementPtr device_host_ptr =
516                getConfigElementPointer( device_host );
517             if ( device_host_ptr.get() != NULL )
518             {
519                std::string host_name =
520                   device_host_ptr->getProperty<std::string>( "host_name" );
521                if ( !cluster::ClusterNetwork::isLocalHost( host_name ) )
522                {
523                   return true;
524                }// Device is on the local machine
525             }// Could not find the deviceHost in the configuration
526          }// Device is not a remote device since there is no name in the deviceHost field
527       }// Else it is not a device, or does not have a deviceHost property
528       return false;
529    }
530
531    bool ClusterManager::recognizeClusterManagerConfig( jccl::ConfigElementPtr element )
532    {
533      return( element->getID() == ClusterManager::getElementType() );
534    }
535
536    /** Adds the pending element to the configuration.
537     *  @pre configCanHandle(element) == true.
538     *  @return true iff element was successfully added to configuration.
539     */
540    bool ClusterManager::configAdd( jccl::ConfigElementPtr element )
541    {
542       vpr::DebugOutputGuard dbg_output( gadgetDBG_RIM, vprDBG_STATE_LVL,
543                               std::string( "Cluster Manager: Adding config element.\n" ),
544                               std::string( "...done adding element.\n" ) );
545
546       vprASSERT(configCanHandle(element));
547       vprASSERT(recognizeClusterManagerConfig(element));
548
549       bool ret_val = false;      // Flag to return success
550
551       {
552          vprDEBUG( gadgetDBG_RIM,vprDBG_CONFIG_STATUS_LVL)
553             << clrOutBOLD(clrCYAN,"[ClusterManager] ")
554             << "Configure the Cluster: " << element->getName()
555             << std::endl << vprDEBUG_FLUSH;
556
557          // Get a list of cluster nodes to use for this cluster.
558          int num_nodes = element->getNum( std::string( "cluster_node" ) );
559
560          vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_STATUS_LVL )
561             << clrOutBOLD( clrCYAN, "[ClusterManager] " )
562             << "configAdd() Number of nodes: " << num_nodes
563             << std::endl << vprDEBUG_FLUSH;
564
565          for ( int i = 0 ; i < num_nodes ; ++i )
566          {
567             std::string new_node =
568                element->getProperty<std::string>( "cluster_node" , i );
569             vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_STATUS_LVL )
570                << clrOutBOLD( clrCYAN, "[ClusterManager] " )
571                << "configAdd() New Node Name: " << new_node
572                << std::endl << vprDEBUG_FLUSH;
573
574             jccl::ConfigElementPtr new_node_element =
575                getConfigElementPointer( new_node );
576             std::string new_node_hostname =
577                new_node_element->getProperty<std::string>( "host_name" );
578
579             vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_STATUS_LVL )
580                << clrOutBOLD( clrCYAN, "[ClusterManager] " )
581                << "configAdd() New Node Hostname: " << new_node_hostname
582                << std::endl << vprDEBUG_FLUSH;
583
584             if ( !cluster::ClusterNetwork::isLocalHost( new_node_hostname ) )
585             {
586                vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_STATUS_LVL )
587                   << clrOutBOLD( clrCYAN, "[ClusterManager] " )
588                   << "configAdd() Added Node since it is non-local"
589                   << std::endl << vprDEBUG_FLUSH;
590
591                vpr::Guard<vpr::Mutex> guard( mNodesLock );
592                mNodes.push_back( new_node_hostname );
593             }
594          }
595
596
597          // Load the plugins.
598
599          vpr::DebugOutputGuard dbg_output( gadgetDBG_RIM, vprDBG_STATE_LVL,
600                                            std::string( "Handling cluster_manager element:\n" ),
601                                            std::string( "-- end state -- \n" ) );
602
603          // Keep this up to date with the version of the element definition we're
604          // expecting to handle.
605          const unsigned int cur_version(2);
606
607          // If the element version is less than cur_version, we will not try to
608          // proceed.  Instead, we'll print an error message and return false so
609          // that the Config Manager knows this element wasn't consumed.
610          if ( element->getVersion() < cur_version )
611          {
612             vprDEBUG( gadgetDBG_RIM, vprDBG_CRITICAL_LVL )
613                << clrOutBOLD( clrRED, "ERROR" )
614                << " [gadget::ClusterManager::configAdd()]: Element named '"
615                << element->getName() << "'" << std::endl << vprDEBUG_FLUSH;
616             vprDEBUG_NEXT( gadgetDBG_RIM, vprDBG_CRITICAL_LVL )
617                << "is version " << element->getVersion()
618                << ", but we require at least version " << cur_version
619                << std::endl << vprDEBUG_FLUSH;
620             vprDEBUG_NEXT( gadgetDBG_RIM, vprDBG_CRITICAL_LVL )
621                << "Ignoring this element and moving on." << std::endl
622                << vprDEBUG_FLUSH;
623
624             ret_val = false;
625          }
626          // We got the right version of the config element and can proceed.
627          else
628          {
629             const std::string plugin_path_prop_name( "plugin_path" );
630             const int path_count( element->getNum( plugin_path_prop_name ) );
631             std::vector<fs::path> search_path( path_count );
632
633             for ( unsigned int i = 0; i < search_path.size(); ++i )
634             {
635                std::string temp_str =
636                   vpr::replaceEnvVars( element->getProperty<std::string>( plugin_path_prop_name, i ) );
637
638                try
639                {
640                   search_path[i] = fs::path( temp_str, fs::native );
641                }
642                catch( fs::filesystem_error& fsEx )
643                {
644                   vprDEBUG( vprDBG_ERROR, vprDBG_CRITICAL_LVL )
645                      << clrOutNORM( clrRED, "ERROR:" )
646                      << "[cluster::ClusterManager::configAdd()] File system "
647                      << "exception caught while converting"
648                      << std::endl << vprDEBUG_FLUSH;
649                   vprDEBUG_NEXT( vprDBG_ERROR, vprDBG_CRITICAL_LVL )
650                      << "'" << temp_str << "'"
651                      << std::endl << vprDEBUG_FLUSH;
652                   vprDEBUG_NEXT( vprDBG_ERROR, vprDBG_CRITICAL_LVL )
653                      << "to a Boost.Filesystem path."
654                      << std::endl << vprDEBUG_FLUSH;
655                   vprDEBUG_NEXT( vprDBG_ERROR, vprDBG_CRITICAL_LVL )
656                      << fsEx.what() << std::endl << vprDEBUG_FLUSH;
657                }
658             }
659
660             // Append a default plug-in search path to search_path.
661             const fs::path default_search_dir =
662                gadget::getDefaultPluginRoot() / std::string("plugins");
663
664             vprDEBUG( gadgetDBG_RIM, vprDBG_VERB_LVL )
665                << "[cluster::ClusterManager::configAdd()] Appending "
666                << "default search path '"
667                << default_search_dir.native_directory_string() << "'\n"
668                << vprDEBUG_FLUSH;
669
670 #if defined(GADGET_DEBUG)
671             // For a debug build, search in the debug subdirectory of
672             // default_search_dir before looking in default_search_dir.
673             search_path.push_back(default_search_dir / std::string("debug"));
674 #endif
675
676             search_path.push_back( default_search_dir );
677
678             // --- Load cluster plugin dsos -- //
679             // - Load individual plugins
680             const std::string plugin_prop_name( "plugin" );
681             const std::string get_version_func( "getGadgeteerVersion" );
682             const std::string plugin_init_func( "initPlugin" );
683
684             int plugin_count = element->getNum( plugin_prop_name );
685             std::string plugin_dso_name;
686
687             for ( int i = 0; i < plugin_count; ++i )
688             {
689                plugin_dso_name =
690                   element->getProperty<std::string>(plugin_prop_name, i);
691
692                if ( !plugin_dso_name.empty() )
693                {
694                   vprDEBUG( gadgetDBG_RIM, vprDBG_STATE_LVL )
695                      << "[cluster::ClusterManager::configAdd()] Loading "
696                      << "plugin DSO '" << plugin_dso_name << "'"
697                      << std::endl << vprDEBUG_FLUSH;
698
699                   vpr::LibraryPtr dso =
700                      vpr::LibraryLoader::findDSO(plugin_dso_name, search_path);
701
702                   if ( dso.get() != NULL )
703                   {
704                      try
705                      {
706                         VersionCheckCallable version_functor;
707                         vpr::LibraryLoader::callEntryPoint(dso,
708                                                            get_version_func,
709                                                            version_functor);
710
711                         PluginInitCallable init_functor(this);
712                         vpr::LibraryLoader::callEntryPoint(dso,
713                                                            plugin_init_func,
714                                                            init_functor);
715
716                         mLoadedPlugins.push_back(dso);
717                      }
718                      catch (gadget::PluginVersionException& ex)
719                      {
720                         vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
721                            << clrOutBOLD(clrRED, "ERROR")
722                            << ": Version mismatch while loading cluster "
723                            << "plug-in DSO '" << plugin_dso_name << "'\n"
724                            << vprDEBUG_FLUSH;
725                         vprDEBUG_NEXT(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
726                            << "This plug-in will not be usable.\n"
727                            << vprDEBUG_FLUSH;
728                         vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
729                            << ex.getExtendedDescription() << std::endl
730                            << vprDEBUG_FLUSH;
731                      }
732                      catch (vpr::Exception& ex)
733                      {
734                         vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
735                            << clrOutBOLD(clrRED, "ERROR")
736                            << ": Failed to load cluster plug-in DSO '"
737                            << plugin_dso_name << "'\n" << vprDEBUG_FLUSH;
738                         vprDEBUG_NEXT(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
739                            << "This plug-in will not be usable.\n"
740                            << vprDEBUG_FLUSH;
741                         vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
742                            << ex.what() << std::endl << vprDEBUG_FLUSH;
743                      }
744                   }
745                   else
746                   {
747                      vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
748                         << clrOutBOLD(clrRED, "ERROR")
749                         << ": Failed to find cluster plug-in DSO '"
750                         << plugin_dso_name << "'\n" << vprDEBUG_FLUSH;
751                   }
752                }
753             }
754
755             ret_val = true;
756          }
757
758          // Dump the status
759          {
760             vpr::DebugOutputGuard dbg_output( gadgetDBG_RIM, vprDBG_CONFIG_LVL,
761                                     std::string( "New Cluster Manager state:\n" ),
762                                     std::string( "-- end state -- \n" ) );
763             vprDEBUG( gadgetDBG_RIM, vprDBG_CONFIG_LVL )
764                << (*this) << std::endl << vprDEBUG_FLUSH;
765          }
766       }
767
768       vpr::Guard<vpr::Mutex> guard( mClusterActiveLock );
769       mClusterActive = true;
770
771       return ret_val;         // Return the success flag if we added at all
772     }
773
774     /** Remove the pending element from the current configuration.
775      *  @pre configCanHandle(element) == true.
776      *  @return true iff the element (and any objects it represented)
777      *          were successfully removed.
778      */
779    bool ClusterManager::configRemove( jccl::ConfigElementPtr element )
780    {
781       if ( recognizeClusterManagerConfig( element ) )
782       {
783          vprDEBUG( gadgetDBG_RIM,vprDBG_CONFIG_LVL )
784             << "[ClusterManager] Shutdown the Cluster: " << element->getName()
785             << std::endl << vprDEBUG_FLUSH;
786