Line data Source code
1 :
2 : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2010, Cedric Stalder <cedric.stalder@gmail.com>
4 : * 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 "init.h"
21 :
22 : #include "client.h"
23 : #include "config.h"
24 : #include "global.h"
25 : #include "nodeFactory.h"
26 : #include "os.h"
27 : #include "server.h"
28 :
29 : #include <eq/client/version.h>
30 : #include <eq/fabric/configParams.h>
31 : #include <eq/fabric/init.h>
32 : #include <co/global.h>
33 : #include <lunchbox/pluginRegistry.h>
34 :
35 : #ifdef _WIN32
36 : #pragma warning( push )
37 : #pragma warning( disable : 4275 4251 )
38 : #endif
39 : #include <boost/filesystem.hpp>
40 : #include <boost/program_options/options_description.hpp>
41 : #include <boost/program_options/parsers.hpp>
42 : #include <boost/program_options/variables_map.hpp>
43 : #ifdef _WIN32
44 : #pragma warning( pop )
45 : #endif
46 :
47 : #include <fstream>
48 :
49 : #ifdef _MSC_VER
50 : # include <direct.h>
51 : # define getcwd _getcwd
52 : # define atoll _atoi64
53 : #endif
54 : #ifndef MAXPATHLEN
55 : # define MAXPATHLEN 1024
56 : #endif
57 :
58 : #ifdef EQ_USE_PARACOMP
59 : # include <pcapi.h>
60 : #endif
61 :
62 : namespace arg = boost::program_options;
63 :
64 : namespace eq
65 : {
66 : namespace
67 : {
68 : static std::ofstream* _logFile = 0;
69 12 : static lunchbox::a_int32_t _initialized;
70 : }
71 :
72 : const char EQ_HELP[] = "eq-help";
73 : const char EQ_LOGFILE[] = "eq-logfile";
74 : const char EQ_SERVER[] = "eq-server";
75 : const char EQ_CLIENT[] = "eq-client";
76 : const char EQ_CONFIG[] = "eq-config";
77 : const char EQ_CONFIG_FLAGS[] = "eq-config-flags";
78 : const char EQ_CONFIG_PREFIXES[] = "eq-config-prefixes";
79 : const char EQ_RENDER_CLIENT[] = "eq-render-client";
80 :
81 : static bool _parseArguments( const int argc, char** argv );
82 : static void _initPlugins();
83 : static void _exitPlugins();
84 :
85 9 : bool _init( const int argc, char** argv, NodeFactory* nodeFactory )
86 : {
87 9 : const char *env = getenv( "EQ_LOG_LEVEL" );
88 9 : if( env )
89 0 : lunchbox::Log::level = lunchbox::Log::getLogLevel( env );
90 :
91 9 : env = getenv( "EQ_LOG_TOPICS" );
92 9 : if( env )
93 0 : lunchbox::Log::topics |= atoll( env );
94 :
95 9 : lunchbox::Log::instance().setThreadName( "Main" );
96 9 : if( !_parseArguments( argc, argv ))
97 0 : return false;
98 45 : LBINFO << "Equalizer v" << Version::getString() << " initializing"
99 36 : << std::endl;
100 :
101 9 : if( ++_initialized > 1 ) // not first
102 : {
103 0 : LBINFO << "Equalizer client library initialized more than once"
104 0 : << std::endl;
105 0 : return true;
106 : }
107 :
108 : #ifdef AGL
109 : GetCurrentEventQueue();
110 : #endif
111 : #ifdef GLX
112 9 : ::XInitThreads();
113 : #endif
114 :
115 : #ifdef EQ_USE_PARACOMP
116 : LBINFO << "Initializing Paracomp library" << std::endl;
117 : PCerr err = pcSystemInitialize( 0 );
118 : if( err != PC_NO_ERROR )
119 : {
120 : LBERROR << "Paracomp initialization failed: " << err << std::endl;
121 : return false;
122 : }
123 : #endif
124 :
125 9 : LBASSERT( nodeFactory );
126 9 : Global::_nodeFactory = nodeFactory;
127 :
128 9 : const std::string& programName = Global::getProgramName();
129 9 : if( programName.empty() && argc > 0 )
130 7 : Global::setProgramName( argv[0] );
131 :
132 9 : const std::string& workDir = Global::getWorkDir();
133 9 : if( workDir.empty( ))
134 : {
135 : char cwd[MAXPATHLEN];
136 9 : Global::setWorkDir( getcwd( cwd, MAXPATHLEN ));
137 : }
138 :
139 9 : _initPlugins();
140 9 : return fabric::init( argc, argv );
141 : }
142 :
143 9 : bool exit()
144 : {
145 9 : if( _initialized <= 0 )
146 : {
147 0 : LBERROR << "Equalizer client library not initialized" << std::endl;
148 0 : return false;
149 : }
150 9 : if( --_initialized > 0 ) // not last
151 0 : return true;
152 :
153 : #ifdef EQ_USE_PARACOMP
154 : pcSystemFinalize();
155 : #endif
156 :
157 9 : Global::_nodeFactory = 0;
158 : // _exitErrors();
159 9 : _exitPlugins();
160 9 : const bool ret = fabric::exit();
161 :
162 9 : if( _logFile )
163 : {
164 : #ifdef NDEBUG
165 : lunchbox::Log::setOutput( std::cout );
166 : #else
167 0 : lunchbox::Log::setOutput( std::cerr );
168 : #endif
169 0 : _logFile->close();
170 0 : delete _logFile;
171 0 : _logFile = 0;
172 : }
173 9 : return ret;
174 : }
175 :
176 9 : bool _parseArguments( const int argc, char** argv )
177 : {
178 : typedef stde::hash_map< std::string, uint32_t > Flags;
179 9 : Flags configFlags;
180 9 : configFlags["multiprocess"] = fabric::ConfigParams::FLAG_MULTIPROCESS;
181 9 : configFlags["multiprocess_db"] = fabric::ConfigParams::FLAG_MULTIPROCESS_DB;
182 9 : configFlags["ethernet"] = fabric::ConfigParams::FLAG_NETWORK_ETHERNET;
183 9 : configFlags["infiniband"] = fabric::ConfigParams::FLAG_NETWORK_INFINIBAND;
184 18 : configFlags["2D_horizontal"] =
185 9 : fabric::ConfigParams::FLAG_LOAD_EQ_HORIZONTAL;
186 18 : configFlags["2D_vertical"] =
187 9 : fabric::ConfigParams::FLAG_LOAD_EQ_VERTICAL;
188 18 : configFlags["2D_tiles"] =
189 9 : fabric::ConfigParams::FLAG_LOAD_EQ_2D;
190 :
191 18 : arg::options_description options( "Equalizer library options" );
192 : options.add_options()
193 18 : ( EQ_HELP, "Display usage information and exit" )
194 9 : ( EQ_LOGFILE, arg::value< std::string >(),
195 9 : "Redirect log output to given file" )
196 18 : ( EQ_SERVER, arg::value< std::string >(), "The server address" )
197 9 : ( EQ_CONFIG, arg::value< std::string >(),
198 9 : "The config filename or autoconfig session name" )
199 9 : ( EQ_CONFIG_FLAGS, arg::value< Strings >()->multitoken(),
200 9 : "The autoconfig flags" )
201 9 : ( EQ_CONFIG_PREFIXES, arg::value< Strings >()->multitoken(),
202 : "The network prefix filter(s) in CIDR notation for autoconfig "
203 9 : "(white-space separated)" )
204 9 : ( EQ_RENDER_CLIENT, arg::value< std::string >(),
205 : "The render client executable filename" )
206 9 : ;
207 :
208 18 : arg::variables_map vm;
209 : try
210 : {
211 9 : Strings args;
212 16 : for( int i = 0; i < argc; ++i )
213 : {
214 7 : if( strcmp( argv[i], "--" ) != 0 )
215 7 : args.push_back( argv[i] );
216 : }
217 : arg::store( arg::command_line_parser( args )
218 9 : .options( options ).allow_unregistered().run(), vm );
219 9 : arg::notify( vm );
220 : }
221 : catch( const std::exception& e )
222 : {
223 : LBERROR << "Error in argument parsing: " << e.what() << std::endl;
224 : return false;
225 : }
226 :
227 9 : if( vm.count( EQ_HELP ))
228 : {
229 0 : std::cout << options << std::endl;
230 0 : return false;
231 : }
232 :
233 9 : if( vm.count( EQ_LOGFILE ))
234 : {
235 0 : const std::string& newFile = vm["eq-logfile"].as< std::string >();
236 0 : std::ofstream* oldLog = _logFile;
237 0 : std::ofstream* newLog = new std::ofstream( newFile.c_str( ));
238 :
239 0 : if( newLog->is_open( ))
240 : {
241 0 : _logFile = newLog;
242 0 : lunchbox::Log::setOutput( *newLog );
243 :
244 0 : if( oldLog )
245 : {
246 0 : *oldLog << "Redirected log to " << newFile << std::endl;
247 0 : oldLog->close();
248 0 : delete oldLog;
249 : }
250 : else
251 0 : std::cout << "Redirected log to " << newFile << std::endl;
252 : }
253 : else
254 : {
255 0 : LBWARN << "Can't open log file " << newFile << ": "
256 0 : << lunchbox::sysError << std::endl;
257 0 : delete newLog;
258 0 : newLog = 0;
259 : }
260 : }
261 :
262 9 : if( vm.count( EQ_SERVER ))
263 0 : Global::setServer( vm[EQ_SERVER].as< std::string >( ));
264 :
265 9 : if( vm.count( EQ_CONFIG ))
266 0 : Global::setConfigFile( vm[EQ_CONFIG].as< std::string >( ));
267 :
268 9 : if( vm.count( EQ_CONFIG_FLAGS ))
269 : {
270 0 : const Strings& flagStrings = vm[EQ_CONFIG_FLAGS].as< Strings >( );
271 0 : uint32_t flags = Global::getFlags();
272 0 : for( StringsCIter i = flagStrings.begin(); i != flagStrings.end(); ++i )
273 : {
274 0 : Flags::const_iterator j = configFlags.find( *i );
275 0 : if( j != configFlags.end( ))
276 0 : flags |= j->second;
277 : else
278 0 : LBWARN << "Unknown argument for --eq-config-flags: " << *i
279 0 : << std::endl;
280 : }
281 0 : Global::setFlags( flags );
282 : }
283 :
284 9 : if( vm.count( EQ_CONFIG_PREFIXES ))
285 : {
286 0 : const Strings& prefixes = vm[EQ_CONFIG_PREFIXES].as< Strings >( );
287 0 : Global::setPrefixes( prefixes );
288 : }
289 :
290 9 : if( vm.count( EQ_CLIENT ))
291 : {
292 0 : const std::string& renderClient = vm[EQ_CLIENT].as< std::string >();
293 0 : const boost::filesystem::path path( renderClient );
294 :
295 0 : Global::setProgramName( renderClient );
296 0 : Global::setWorkDir( path.parent_path().string( ));
297 : }
298 :
299 18 : return true;
300 : }
301 :
302 9 : void _initPlugins()
303 : {
304 9 : lunchbox::PluginRegistry& plugins = co::Global::getPluginRegistry();
305 :
306 9 : plugins.addDirectory( "/usr/share/Equalizer/plugins" );
307 9 : plugins.addDirectory( "/usr/local/share/Equalizer/plugins" );
308 : #ifdef _WIN32 // final INSTALL_DIR is not known at compile time
309 : plugins.addDirectory( "../share/Equalizer/plugins" );
310 : #else
311 18 : plugins.addDirectory( std::string( EQ_INSTALL_DIR ) +
312 9 : std::string( "share/Equalizer/plugins" ));
313 : #endif
314 :
315 9 : plugins.addDirectory( ".eqPlugins" );
316 9 : plugins.addDirectory( "/opt/local/lib" ); // MacPorts
317 :
318 9 : const char* home = getenv( "HOME" );
319 9 : if( home )
320 9 : plugins.addDirectory( std::string( home ) + "/.eqPlugins" );
321 :
322 : #ifdef EQUALIZER_DSO_NAME
323 9 : if( plugins.addPlugin( EQUALIZER_DSO_NAME )) // Found by LDD
324 18 : return;
325 :
326 : // Hard-coded compile locations as backup:
327 0 : std::string absDSO = std::string( EQ_BUILD_DIR ) + "lib/" +
328 0 : EQUALIZER_DSO_NAME;
329 0 : if( plugins.addPlugin( absDSO ))
330 0 : return;
331 :
332 : # ifdef NDEBUG
333 : absDSO = std::string( EQ_BUILD_DIR ) + "lib/Release/" + EQUALIZER_DSO_NAME;
334 : # else
335 0 : absDSO = std::string( EQ_BUILD_DIR ) + "lib/Debug/" + EQUALIZER_DSO_NAME;
336 : # endif
337 :
338 0 : if( plugins.addPlugin( absDSO ))
339 0 : return;
340 :
341 0 : LBWARN << "Built-in Equalizer plugins not loaded: " << EQUALIZER_DSO_NAME
342 0 : << " not in library search path and " << absDSO << " not found"
343 0 : << std::endl;
344 : #else
345 : # ifndef NDEBUG
346 : # error "EQUALIZER_DSO_NAME not defined"
347 : # endif
348 : LBWARN << "Built-in Equalizer plugins not loaded: EQUALIZER_DSO_NAME not "
349 : << "defined" << std::endl;
350 : #endif
351 : }
352 :
353 9 : void _exitPlugins()
354 : {
355 9 : lunchbox::PluginRegistry& plugins = co::Global::getPluginRegistry();
356 :
357 : #ifdef _WIN32 // final INSTALL_DIR is not known at compile time
358 : plugins.removeDirectory( "../share/Equalizer/plugins" );
359 : #else
360 18 : plugins.removeDirectory( std::string( EQ_INSTALL_DIR ) +
361 9 : std::string( "share/Equalizer/plugins" ));
362 : #endif
363 9 : plugins.removeDirectory( "/usr/local/share/Equalizer/plugins" );
364 9 : plugins.removeDirectory( ".eqPlugins" );
365 :
366 9 : const char* home = getenv( "HOME" );
367 9 : if( home )
368 9 : plugins.removeDirectory( std::string( home ) + "/.eqPlugins" );
369 9 : }
370 :
371 0 : Config* getConfig( const int argc, char** argv )
372 : {
373 : // 1. initialization of a local client node
374 0 : ClientPtr client = new Client;
375 0 : if( client->initLocal( argc, argv ))
376 : {
377 : // 2. connect to server
378 0 : ServerPtr server = new Server;
379 0 : if( client->connectServer( server ))
380 : {
381 : // 3. choose configuration
382 0 : fabric::ConfigParams configParams;
383 0 : Config* config = server->chooseConfig( configParams );
384 0 : if( config )
385 0 : return config;
386 :
387 0 : LBERROR << "No matching config on server" << std::endl;
388 :
389 : // -2. disconnect server
390 0 : client->disconnectServer( server );
391 : }
392 : else
393 0 : LBERROR << "Can't open server" << std::endl;
394 :
395 : // -1. exit local client node
396 0 : client->exitLocal();
397 : }
398 : else
399 0 : LBERROR << "Can't init local client node" << std::endl;
400 :
401 0 : return 0;
402 : }
403 :
404 0 : void releaseConfig( Config* config )
405 : {
406 0 : if( !config )
407 0 : return;
408 :
409 0 : ServerPtr server = config->getServer();
410 0 : LBASSERT( server.isValid( ));
411 0 : server->releaseConfig( config );
412 :
413 0 : ClientPtr client = server->getClient();
414 0 : LBASSERT( client.isValid( ));
415 :
416 0 : client->disconnectServer( server );
417 0 : client->exitLocal();
418 :
419 0 : LBASSERTINFO( client->getRefCount() == 1, client->getRefCount( ));
420 0 : LBASSERTINFO( server->getRefCount() == 1, server->getRefCount( ));
421 : }
422 :
423 36 : }
|