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