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