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