bool Logger::readLog(std::string &target) { bool success = false; LockGuard lock(m_mutex); for (size_t i=0; i<m_appenders.size(); ++i) { Appender *appender = m_appenders[i]; if (appender->getClass()->derivesFrom(MTS_CLASS(StreamAppender))) { StreamAppender *streamAppender = static_cast<StreamAppender *>(appender); if (streamAppender->logsToFile()) { streamAppender->readLog(target); success = true; break; } } } return success; }
int mtssrv(int argc, char **argv) { int optchar; char *end_ptr = NULL; try { /* Default settings */ int nprocs = getCoreCount(), listenPort = MTS_DEFAULT_PORT; std::string nodeName = getHostName(), networkHosts = ""; bool quietMode = false; ELogLevel logLevel = EInfo; std::string hostName = getFQDN(); FileResolver *fileResolver = Thread::getThread()->getFileResolver(); bool hostNameSet = false; optind = 1; /* Parse command-line arguments */ while ((optchar = getopt(argc, argv, "a:c:s:n:p:i:l:L:qhv")) != -1) { switch (optchar) { case 'a': { std::vector<std::string> paths = tokenize(optarg, ";"); for (int i=(int)paths.size()-1; i>=0; --i) fileResolver->prependPath(paths[i]); } break; case 'c': networkHosts = networkHosts + std::string(";") + std::string(optarg); break; case 'i': hostName = optarg; hostNameSet = true; break; case 's': { std::ifstream is(optarg); if (is.fail()) SLog(EError, "Could not open host file!"); std::string host; while (is >> host) { if (host.length() < 1 || host.c_str()[0] == '#') continue; networkHosts = networkHosts + std::string(";") + host; } } break; case 'n': nodeName = optarg; break; case 'p': nprocs = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the processor count!"); break; case 'v': logLevel = EDebug; break; case 'L': { std::string arg = boost::to_lower_copy(std::string(optarg)); if (arg == "trace") logLevel = ETrace; else if (arg == "debug") logLevel = EDebug; else if (arg == "info") logLevel = EInfo; else if (arg == "warn") logLevel = EWarn; else if (arg == "error") logLevel = EError; else SLog(EError, "Invalid log level!"); } break; case 'l': if (!strcmp("s", optarg)) { listenPort = -1; quietMode = true; } else { listenPort = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the port number"); } break; case 'q': quietMode = true; break; case 'h': default: cout << "Mitsuba version " << Version(MTS_VERSION).toStringComplete() << ", Copyright (c) " MTS_YEAR " Wenzel Jakob" << endl; cout << "Usage: mtssrv [options]" << endl; cout << "Options/Arguments:" << endl; cout << " -h Display this help text" << endl << endl; cout << " -a p1;p2;.. Add one or more entries to the resource search path" << endl << endl; cout << " -p count Override the detected number of processors. Useful for reducing" << endl; cout << " the load or creating scheduling-only nodes in conjunction with" << endl; cout << " the -c and -s parameters, e.g. -p 0 -c host1;host2;host3,..." << endl << endl; cout << " -q Quiet mode - do not print any log messages to stdout" << endl << endl; cout << " -c hosts Nesting: connect to additional mtssrv instances over a network." << endl; cout << " Requires a semicolon-separated list of host names of the form" << endl; cout << " host.domain[:port] for a direct connection" << endl; cout << " or" << endl; cout << " [email protected][:/path] for a SSH connection (where" << endl; cout << " 'path' denotes the place where Mitsuba is checked" << endl; cout << " out -- by default, \"~/mitsuba\" is used)" << endl << endl; cout << " -s file Connect to additional Mitsuba servers specified in a file" << endl; cout << " with one name per line (same format as in -c)" << endl<< endl; cout << " -i name IP address / host name on which to listen for connections" << endl << endl; cout << " -l port Listen for connections on a certain port (Default: " << MTS_DEFAULT_PORT << ")." << endl; cout << " To listen on stdin, specify \"-ls\" (implies -q)" << endl << endl; cout << " -n name Assign a node name to this instance (Default: host name)" << endl << endl; cout << " -v Be more verbose (can be specified twice)" << endl << endl; cout << " -L level Explicitly specify the log level (trace/debug/info/warn/error)" << endl << endl; cout << " For documentation, please refer to http://www.mitsuba-renderer.org/docs.html" << endl; return 0; } } /* Configure the logging subsystem */ ref<Logger> log = Thread::getThread()->getLogger(); log->setLogLevel(logLevel); /* Initialize OpenMP */ Thread::initializeOpenMP(nprocs); /* Disable the default appenders */ for (size_t i=0; i<log->getAppenderCount(); ++i) { Appender *appender = log->getAppender(i); if (appender->getClass()->derivesFrom(MTS_CLASS(StreamAppender))) log->removeAppender(appender); } log->addAppender(new StreamAppender(formatString("mtssrv.%s.log", nodeName.c_str()))); if (!quietMode) log->addAppender(new StreamAppender(&std::cout)); SLog(EInfo, "Mitsuba version %s, Copyright (c) " MTS_YEAR " Wenzel Jakob", Version(MTS_VERSION).toStringComplete().c_str()); #if defined(__WINDOWS__) /* Custom handler for Ctrl-C signals */ SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE); #endif /* Configure the scheduling subsystem */ Scheduler *scheduler = Scheduler::getInstance(); for (int i=0; i<nprocs; ++i) scheduler->registerWorker(new LocalWorker(i, formatString("wrk%i", i))); std::vector<std::string> hosts = tokenize(networkHosts, ";"); /* Establish network connections to nested servers */ for (size_t i=0; i<hosts.size(); ++i) { const std::string &hostName = hosts[i]; ref<Stream> stream; if (hostName.find("@") == std::string::npos) { int port = MTS_DEFAULT_PORT; std::vector<std::string> tokens = tokenize(hostName, ":"); if (tokens.size() == 0 || tokens.size() > 2) { SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } else if (tokens.size() == 2) { port = strtol(tokens[1].c_str(), &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } stream = new SocketStream(tokens[0], port); } else { std::string path = "~/mitsuba"; std::vector<std::string> tokens = tokenize(hostName, "@/:"); if (tokens.size() < 2 || tokens.size() > 3) { SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } else if (tokens.size() == 3) { path = tokens[2]; } std::vector<std::string> cmdLine; cmdLine.push_back(formatString("bash -c 'cd %s; . setpath.sh; mtssrv -ls'", path.c_str())); stream = new SSHStream(tokens[0], tokens[1], cmdLine); } try { scheduler->registerWorker(new RemoteWorker(formatString("net%i", i), stream)); } catch (std::runtime_error &e) { if (hostName.find("@") != std::string::npos) { #if defined(__WINDOWS__) SLog(EWarn, "Please ensure that passwordless authentication " "using plink.exe and pageant.exe is enabled (see the documentation for more information)"); #else SLog(EWarn, "Please ensure that passwordless authentication " "is enabled (e.g. using ssh-agent - see the documentation for more information)"); #endif } throw e; } } scheduler->start(); if (listenPort == -1) { ref<StreamBackend> backend = new StreamBackend("con0", scheduler, nodeName, new ConsoleStream(), false); backend->start(); backend->join(); return 0; } /* Allocate a socket of the proper type (IPv4/IPv6) */ struct addrinfo hints, *servinfo, *p = NULL; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; char portName[8]; int rv, one = 1; sock = INVALID_SOCKET; snprintf(portName, sizeof(portName), "%i", listenPort); if ((rv = getaddrinfo(hostNameSet ? hostName.c_str() : NULL, portName, &hints, &servinfo)) != 0) SLog(EError, "Error in getaddrinfo(%s:%i): %s", hostName.c_str(), listenPort, gai_strerror(rv)); for (p = servinfo; p != NULL; p = p->ai_next) { /* Allocate a socket */ sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (sock == -1) SocketStream::handleError("none", "socket"); /* Avoid "bind: socket already in use" */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) SocketStream::handleError("none", "setsockopt"); /* Bind the socket to the port number */ if (bind(sock, p->ai_addr, (socklen_t) p->ai_addrlen) == -1) { SocketStream::handleError("none", formatString("bind(%s:%i)", hostName.c_str(), listenPort), EError); #if defined(__WINDOWS__) closesocket(sock); #else close(sock); #endif continue; } break; } if (p == NULL) SLog(EError, "Failed to bind to port %i!", listenPort); freeaddrinfo(servinfo); if (listen(sock, CONN_BACKLOG) == -1) SocketStream::handleError("none", "bind"); SLog(EInfo, "Enter mtssrv -h for more options"); #if defined(__WINDOWS__) SLog(EInfo, "%s: Listening on port %i.. Send Ctrl-C to stop.", hostName.c_str(), listenPort); #else /* Avoid zombies processes */ struct sigaction sa; sa.sa_handler = collect_zombies; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) SLog(EError, "Error in sigaction(): %s!", strerror(errno)); sa.sa_handler = sigterm_handler; sa.sa_flags = 0; // we want SIGINT/SIGTERM to interrupt accept() if (sigaction(SIGTERM, &sa, NULL) == -1) SLog(EError, "Error in sigaction(): %s!", strerror(errno)); if (sigaction(SIGINT, &sa, NULL) == -1) SLog(EError, "Error in sigaction(): %s!", strerror(errno)); /* Ignore SIGPIPE */ signal(SIGPIPE, SIG_IGN); SLog(EInfo, "%s: Listening on port %i.. Send Ctrl-C or SIGTERM to stop.", hostName.c_str(), listenPort); #endif int connectionIndex = 0; /* Wait for connections */ while (running) { socklen_t addrlen = sizeof(sockaddr_storage); struct sockaddr_storage sockaddr; memset(&sockaddr, 0, addrlen); SOCKET newSocket = accept(sock, (struct sockaddr *) &sockaddr, &addrlen); if (newSocket == INVALID_SOCKET) { #if defined(__WINDOWS__) if(!running) break; #else if (errno == EINTR) continue; #endif SocketStream::handleError("none", "accept", EWarn); continue; } ref<StreamBackend> backend = new StreamBackend(formatString("con%i", connectionIndex++), scheduler, nodeName, new SocketStream(newSocket), true); backend->start(); } #if defined(__WINDOWS__) SLog(EInfo, "Caught signal - shutting down.."); #else close(sock); #endif } catch (const std::exception &e) { std::cerr << "Caught a critical exception: " << e.what() << endl; } catch (...) { std::cerr << "Caught a critical exception of unknown type!" << endl; } /* Shutdown */ Statistics::getInstance()->printStats(); return 0; }
int mitsuba_app(int argc, char **argv) { int optchar; char *end_ptr = NULL; try { /* Default settings */ int nprocs_avail = getCoreCount(), nprocs = nprocs_avail; int numParallelScenes = 1; std::string nodeName = getHostName(), networkHosts = "", destFile=""; bool quietMode = false, progressBars = true, skipExisting = false; ELogLevel logLevel = EInfo; ref<FileResolver> fileResolver = Thread::getThread()->getFileResolver(); bool treatWarningsAsErrors = false; std::map<std::string, std::string, SimpleStringOrdering> parameters; int blockSize = 32; int flushTimer = -1; if (argc < 2) { help(); return 0; } optind = 1; /* Parse command-line arguments */ while ((optchar = getopt(argc, argv, "a:c:D:s:j:n:o:r:b:p:qhzvtwx")) != -1) { switch (optchar) { case 'a': { std::vector<std::string> paths = tokenize(optarg, ";"); for (int i=(int) paths.size()-1; i>=0; --i) fileResolver->prependPath(paths[i]); } break; case 'c': networkHosts = networkHosts + std::string(";") + std::string(optarg); break; case 'w': treatWarningsAsErrors = true; break; case 'D': { std::vector<std::string> param = tokenize(optarg, "="); if (param.size() != 2) SLog(EError, "Invalid parameter specification \"%s\"", optarg); parameters[param[0]] = param[1]; } break; case 's': { std::ifstream is(optarg); if (is.fail()) SLog(EError, "Could not open host file!"); std::string host; while (is >> host) { if (host.length() < 1 || host.c_str()[0] == '#') continue; networkHosts = networkHosts + std::string(";") + host; } } break; case 'n': nodeName = optarg; break; case 'o': destFile = optarg; break; case 'v': if (logLevel != EDebug) logLevel = EDebug; else logLevel = ETrace; break; case 'x': skipExisting = true; break; case 'p': nprocs = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the processor count!"); break; case 'j': numParallelScenes = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the parallel scene count!"); break; case 'r': flushTimer = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the '-r' parameter argument!"); break; case 'b': blockSize = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the block size!"); if (blockSize < 2 || blockSize > 128) SLog(EError, "Invalid block size (should be in the range 2-128)"); break; case 'z': progressBars = false; break; case 'q': quietMode = true; break; case 'h': default: help(); return 0; } } ProgressReporter::setEnabled(progressBars); /* Initialize OpenMP */ Thread::initializeOpenMP(nprocs); /* Configure the logging subsystem */ ref<Logger> log = Thread::getThread()->getLogger(); log->setLogLevel(logLevel); log->setErrorLevel(treatWarningsAsErrors ? EWarn : EError); /* Disable the default appenders */ for (size_t i=0; i<log->getAppenderCount(); ++i) { Appender *appender = log->getAppender(i); if (appender->getClass()->derivesFrom(MTS_CLASS(StreamAppender))) log->removeAppender(appender); } log->addAppender(new StreamAppender(formatString("mitsuba.%s.log", nodeName.c_str()))); if (!quietMode) log->addAppender(new StreamAppender(&std::cout)); SLog(EInfo, "Mitsuba version %s, Copyright (c) " MTS_YEAR " Wenzel Jakob", Version(MTS_VERSION).toStringComplete().c_str()); /* Configure the scheduling subsystem */ Scheduler *scheduler = Scheduler::getInstance(); bool useCoreAffinity = nprocs == nprocs_avail; for (int i=0; i<nprocs; ++i) scheduler->registerWorker(new LocalWorker(useCoreAffinity ? i : -1, formatString("wrk%i", i))); std::vector<std::string> hosts = tokenize(networkHosts, ";"); /* Establish network connections to nested servers */ for (size_t i=0; i<hosts.size(); ++i) { const std::string &hostName = hosts[i]; ref<Stream> stream; if (hostName.find("@") == std::string::npos) { int port = MTS_DEFAULT_PORT; std::vector<std::string> tokens = tokenize(hostName, ":"); if (tokens.size() == 0 || tokens.size() > 2) { SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } else if (tokens.size() == 2) { port = strtol(tokens[1].c_str(), &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } stream = new SocketStream(tokens[0], port); } else { std::string path = "~/mitsuba"; // default path if not specified std::vector<std::string> tokens = tokenize(hostName, "@:"); if (tokens.size() < 2 || tokens.size() > 3) { SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } else if (tokens.size() == 3) { path = tokens[2]; } std::vector<std::string> cmdLine; cmdLine.push_back(formatString("bash -c 'cd %s; . setpath.sh; mtssrv -ls'", path.c_str())); stream = new SSHStream(tokens[0], tokens[1], cmdLine); } try { scheduler->registerWorker(new RemoteWorker(formatString("net%i", i), stream)); } catch (std::runtime_error &e) { if (hostName.find("@") != std::string::npos) { #if defined(__WINDOWS__) SLog(EWarn, "Please ensure that passwordless authentication " "using plink.exe and pageant.exe is enabled (see the documentation for more information)"); #else SLog(EWarn, "Please ensure that passwordless authentication " "is enabled (e.g. using ssh-agent - see the documentation for more information)"); #endif } throw e; } } scheduler->start(); #if !defined(__WINDOWS__) /* Initialize signal handlers */ struct sigaction sa; sa.sa_handler = signalHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL)) SLog(EError, "Could not install a custom signal handler!"); if (sigaction(SIGFPE, &sa, NULL)) SLog(EError, "Could not install a custom signal handler!"); #endif /* Prepare for parsing scene descriptions */ SAXParser* parser = new SAXParser(); fs::path schemaPath = fileResolver->resolveAbsolute("data/schema/scene.xsd"); /* Check against the 'scene.xsd' XML Schema */ parser->setDoSchema(true); parser->setValidationSchemaFullChecking(true); parser->setValidationScheme(SAXParser::Val_Always); parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str()); /* Set the handler */ SceneHandler *handler = new SceneHandler(parameters); parser->setDoNamespaces(true); parser->setDocumentHandler(handler); parser->setErrorHandler(handler); renderQueue = new RenderQueue(); ref<FlushThread> flushThread; if (flushTimer > 0) { flushThread = new FlushThread(flushTimer); flushThread->start(); } int jobIdx = 0; for (int i=optind; i<argc; ++i) { fs::path filename = fileResolver->resolve(argv[i]), filePath = fs::absolute(filename).parent_path(), baseName = filename.stem(); ref<FileResolver> frClone = fileResolver->clone(); frClone->prependPath(filePath); Thread::getThread()->setFileResolver(frClone); SLog(EInfo, "Parsing scene description from \"%s\" ..", argv[i]); parser->parse(filename.c_str()); ref<Scene> scene = handler->getScene(); scene->setSourceFile(filename); scene->setDestinationFile(destFile.length() > 0 ? fs::path(destFile) : (filePath / baseName)); scene->setBlockSize(blockSize); if (scene->destinationExists() && skipExisting) continue; ref<RenderJob> thr = new RenderJob(formatString("ren%i", jobIdx++), scene, renderQueue, -1, -1, -1, true, flushTimer > 0); thr->start(); renderQueue->waitLeft(numParallelScenes-1); if (i+1 < argc && numParallelScenes == 1) Statistics::getInstance()->resetAll(); } /* Wait for all render processes to finish */ renderQueue->waitLeft(0); if (flushThread) flushThread->quit(); renderQueue = NULL; delete handler; delete parser; Statistics::getInstance()->printStats(); } catch (const std::exception &e) { std::cerr << "Caught a critical exception: " << e.what() << endl; return -1; } catch (...) { std::cerr << "Caught a critical exception of unknown type!" << endl; return -1; } return 0; }
int mtsutil(int argc, char **argv) { char optchar, *end_ptr = NULL; try { /* Default settings */ int nprocs = getProcessorCount(); std::string nodeName = getHostName(), networkHosts = "", destFile=""; bool quietMode = false; ELogLevel logLevel = EInfo; FileResolver *fileResolver = Thread::getThread()->getFileResolver(); bool testCaseMode = false; if (argc < 2) { help(); return 0; } optind = 1; /* Parse command-line arguments */ while ((optchar = getopt(argc, argv, "+a:c:s:n:p:qhvt")) != -1) { switch (optchar) { case 'a': { std::vector<std::string> paths = tokenize(optarg, ";"); for (unsigned int i=0; i<paths.size(); ++i) fileResolver->addPath(paths[i]); } break; case 'c': networkHosts = networkHosts + std::string(";") + std::string(optarg); break; case 't': testCaseMode = true; break; case 's': { std::ifstream is(optarg); if (is.fail()) SLog(EError, "Could not open host file!"); std::string host; while (is >> host) { if (host.length() < 1 || host.c_str()[0] == '#') continue; networkHosts = networkHosts + std::string(";") + host; } } break; case 'n': nodeName = optarg; break; case 'v': logLevel = EDebug; break; case 'p': nprocs = strtol(optarg, &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Could not parse the processor count!"); break; case 'q': quietMode = true; break; case 'h': default: help(); return 0; } } /* Configure the logging subsystem */ ref<Logger> log = Thread::getThread()->getLogger(); log->setLogLevel(logLevel); /* Initialize OpenMP */ Thread::initializeOpenMP(nprocs); /* Disable the default appenders */ for (size_t i=0; i<log->getAppenderCount(); ++i) { Appender *appender = log->getAppender(i); if (appender->getClass()->derivesFrom(MTS_CLASS(StreamAppender))) log->removeAppender(appender); } log->addAppender(new StreamAppender(formatString("mitsuba.%s.log", nodeName.c_str()))); if (!quietMode) log->addAppender(new StreamAppender(&std::cout)); SLog(EInfo, "Mitsuba version %s, Copyright (c) " MTS_YEAR " Wenzel Jakob", Version(MTS_VERSION).toStringComplete().c_str()); /* Configure the scheduling subsystem */ Scheduler *scheduler = Scheduler::getInstance(); for (int i=0; i<nprocs; ++i) scheduler->registerWorker(new LocalWorker(formatString("wrk%i", i))); std::vector<std::string> hosts = tokenize(networkHosts, ";"); /* Establish network connections to nested servers */ for (size_t i=0; i<hosts.size(); ++i) { const std::string &hostName = hosts[i]; ref<Stream> stream; if (hostName.find("@") == std::string::npos) { int port = MTS_DEFAULT_PORT; std::vector<std::string> tokens = tokenize(hostName, ":"); if (tokens.size() == 0 || tokens.size() > 2) { SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } else if (tokens.size() == 2) { port = strtol(tokens[1].c_str(), &end_ptr, 10); if (*end_ptr != '\0') SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } stream = new SocketStream(tokens[0], port); } else { std::string path = "~/mitsuba"; // default path if not specified std::vector<std::string> tokens = tokenize(hostName, "@:"); if (tokens.size() < 2 || tokens.size() > 3) { SLog(EError, "Invalid host specification '%s'!", hostName.c_str()); } else if (tokens.size() == 3) { path = tokens[2]; } std::vector<std::string> cmdLine; cmdLine.push_back(formatString("bash -c 'cd %s; . setpath.sh; mtssrv -ls'", path.c_str())); stream = new SSHStream(tokens[0], tokens[1], cmdLine); } try { scheduler->registerWorker(new RemoteWorker(formatString("net%i", i), stream)); } catch (std::runtime_error &e) { if (hostName.find("@") != std::string::npos) { #if defined(WIN32) SLog(EWarn, "Please ensure that passwordless authentication " "using plink.exe and pageant.exe is enabled (see the documentation for more information)"); #else SLog(EWarn, "Please ensure that passwordless authentication " "is enabled (e.g. using ssh-agent - see the documentation for more information)"); #endif } throw e; } } scheduler->start(); if (testCaseMode) { std::vector<fs::path> dirPaths = fileResolver->resolveAll("plugins"); std::set<std::string> seen; int executed = 0, succeeded = 0; for (size_t i=0; i<dirPaths.size(); ++i) { fs::path dirPath = fs::complete(dirPaths[i]); if (!fs::exists(dirPath) || !fs::is_directory(dirPath)) break; fs::directory_iterator end, it(dirPath); for (; it != end; ++it) { if (!fs::is_regular_file(it->status())) continue; std::string extension(boost::to_lower_copy(it->path().extension())); #if defined(WIN32) if (extension != ".dll") continue; #elif defined(__OSX__) if (extension != ".dylib") continue; #elif defined(__LINUX__) if (extension != ".so") continue; #else #error Unknown operating system! #endif std::string shortName = it->path().stem(); if (seen.find(shortName) != seen.end() || !boost::starts_with(shortName, "test_")) continue; seen.insert(shortName); Plugin plugin(shortName, it->path()); if (!plugin.isUtility()) continue; ref<Utility> utility = plugin.createUtility(); TestCase *testCase = static_cast<TestCase *>(utility.get()); if (!utility->getClass()->derivesFrom(MTS_CLASS(TestCase))) SLog(EError, "This is not a test case!"); if (testCase->run(argc-optind, argv+optind) != 0) SLog(EError, "Testcase unexpectedly returned with a nonzero value."); executed += testCase->getExecuted(); succeeded += testCase->getSucceeded(); } } SLog(EInfo, "Ran %i tests, %i succeeded, %i failed.", executed, succeeded, executed-succeeded); } else { if (argc <= optind) { std::cerr << "A utility name must be supplied!" << endl; return -1; } fs::path pluginName(argv[optind]); /* Build the full plugin file name */ #if defined(WIN32) pluginName.replace_extension(".dll"); #elif defined(__OSX__) pluginName.replace_extension(".dylib"); #elif defined(__LINUX__) pluginName.replace_extension(".so"); #else #error Unknown operating system! #endif fs::path fullName = fileResolver->resolve(fs::path("plugins") / pluginName); if (!fs::exists(fullName)) { /* Plugin not found! */ SLog(EError, "Utility \"%s\" not found (run \"mtsutil\" without arguments to " "see a list of available utilities)", fullName.file_string().c_str()); } SLog(EInfo, "Loading utility \"%s\" ..", argv[optind]); Plugin *plugin = new Plugin(argv[optind], fullName); if (!plugin->isUtility()) SLog(EError, "This plugin does not implement the 'Utility' interface!"); Statistics::getInstance()->logPlugin(argv[optind], plugin->getDescription()); ref<Utility> utility = plugin->createUtility(); int retval = utility->run(argc-optind, argv+optind); scheduler->pause(); utility = NULL; delete plugin; return retval; } } catch (const std::exception &e) { std::cerr << "Caught a critical exeption: " << e.what() << std::endl; } catch (...) { std::cerr << "Caught a critical exeption of unknown type!" << endl; } return 0; }
int main(int argc, char *argv[]) { int retval; /* Initialize Xerces-C */ try { XMLPlatformUtils::Initialize(); } catch(const XMLException &toCatch) { fprintf(stderr, "Error during Xerces initialization: %s", XMLString::transcode(toCatch.getMessage())); return -1; } /* Initialize the core framework */ Class::staticInitialization(); PluginManager::staticInitialization(); Statistics::staticInitialization(); Thread::staticInitialization(); Thread::initializeOpenMP(getProcessorCount()); Logger::staticInitialization(); Spectrum::staticInitialization(); Scheduler::staticInitialization(); SHVector::staticInitialization(); #if defined(__LINUX__) XInitThreads(); #endif #if defined(__OSX__) MTS_AUTORELEASE_BEGIN() /* Required for the mouse relocation in GLWidget */ CGSetLocalEventsSuppressionInterval(0.0f); MTS_AUTORELEASE_END() #endif #ifdef WIN32 /* Initialize WINSOCK2 */ WSADATA wsaData; if (WSAStartup(MAKEWORD(2,2), &wsaData)) SLog(EError, "Could not initialize WinSock2!"); if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) SLog(EError, "Could not find the required version of winsock.dll!"); #endif #if !defined(WIN32) /* Avoid zombies processes when running the server */ struct sigaction sa; sa.sa_handler = collect_zombies; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) SLog(EWarn, "Error in sigaction(): %s!", strerror(errno)); #endif qRegisterMetaType<ELogLevel>("ELogLevel"); qRegisterMetaType<fs::path>("fs::path"); MitsubaApplication app(argc, argv); try { QFile stylesheet(":/resources/stylesheet.css"); if (!stylesheet.open(QFile::ReadOnly)) { QMessageBox::critical(NULL, "Internal error", "Could not open stylesheet!"); exit(-1); } app.setStyleSheet(QTextStream(&stylesheet).readAll().toAscii()); #if defined(__OSX__) app.setAttribute(Qt::AA_DontShowIconsInMenus); #endif /* Disable the default appenders */ ref<Logger> logger = Thread::getThread()->getLogger(); for (size_t i=0; i<logger->getAppenderCount(); ++i) { Appender *appender = logger->getAppender(i); if (appender->getClass()->derivesFrom(MTS_CLASS(StreamAppender))) logger->removeAppender(appender); } #if defined(__OSX__) /* Create a log file inside the application bundle */ MTS_AUTORELEASE_BEGIN() logger->addAppender(new StreamAppender(formatString("%s/mitsuba.%s.log", __ubi_bundlepath().c_str(), getHostName().c_str()))); MTS_AUTORELEASE_END() #else /* Create a log file inside the current working directory */ logger->addAppender(new StreamAppender(formatString("mitsuba.%s.log", getHostName().c_str()))); #endif #if !defined(WIN32) /* Correct number parsing on some locales (e.g. ru_RU) */ setlocale(LC_NUMERIC, "C"); #endif mainWindow = new MainWindow(); mainWindow->initWorkers(); retval = app.exec(); delete mainWindow; } catch (const std::exception &e) { SLog(EWarn, "Critical exception during startup: %s", e.what()); QMessageBox::critical(NULL, QString("Critical exception"), e.what(), QMessageBox::Ok); retval = -1; } Statistics::getInstance()->printStats(); XMLPlatformUtils::Terminate(); #ifdef WIN32 /* Shut down WINSOCK2 */ WSACleanup(); #endif /* Shutdown the core framework */ SHVector::staticShutdown(); Scheduler::staticShutdown(); Spectrum::staticShutdown(); Logger::staticShutdown(); Thread::staticShutdown(); Statistics::staticShutdown(); PluginManager::staticShutdown(); Class::staticShutdown(); return retval; }