OpenASIP 2.2
Loading...
Searching...
No Matches
Application.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2009 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file Application.cc
26 *
27 * Implementation of Application class.
28 *
29 * Application is a class for generic services that are project-wide
30 * applicable to standalone applications or modules. These services include
31 * assertion, program exiting, debugging to a log file, catching unexpected
32 * exceptions, "control-c" signal handling.
33 *
34 * @author Atte Oksman 2003 (oksman-no.spam-cs.tut.fi)
35 * @author Pekka J��skel�inen 2005-2009 (pjaaskel-no.spam-cs.tut.fi)
36 */
37
38#include <string>
39#include <iostream>
40#include <fstream>
41#include <cstddef>
42#include <exception>
43#include <cstdio>
44
45// for backtrace printing:
46#include <signal.h>
47
48#include <sys/types.h>
49// macros to evaluate exit status of pclose() (from autoconf manual)
50#ifdef HAVE_SYS_WAIT_H
51# include <sys/wait.h>
52#endif
53#ifndef WEXITSTATUS
54# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
55#endif
56#ifndef WIFEXITED
57# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
58#endif
59
60#include "Environment.hh"
61#include "Application.hh"
62#include "Exception.hh"
63#include "tce_version_string.h" // automatically generated by make
64#include "CmdLineOptions.hh"
65#include "tce_config.h"
66#include "FileSystem.hh"
67
68using std::fgets; // cstdio
69using std::exit;
70using std::abort;
71using std::atexit;
72using std::string;
73using std::cerr;
74using std::cout;
75using std::endl;
76using std::ofstream;
77using std::ios;
78using std::set_unexpected;
79
80
81// static member variable initializations
82bool Application::initialized_ = false;
83std::ostream* Application::logStream_ = NULL;
84std::ostream* Application::errorStream_ = NULL;
85std::ostream* Application::warningStream_ = NULL;
86std::map<int, Application::UnixSignalHandler*> Application::signalHandlers_;
87
90
94
95/**
96 * Initializes the state data needed by the application services.
97 */
98void
100
101 // ensure that initialization is done only once per application
102 if (initialized_) {
103 return;
104 }
105
106 // if this is a developer version, we can output debug messages to
107 // cerr, in 'distributed version', we'll output the debug messages to
108 // a file
110 logStream_ = &cerr;
111 } else {
112 ofstream* fileLog = new ofstream;
113 fileLog->open(Environment::errorLogFilePath().c_str(), ios::app);
114 if (!fileLog->is_open()) {
115 logStream_ = &cerr;
116 } else {
117 logStream_ = fileLog;
118 }
119 }
120
122
123 errorStream_ = &cerr;
124 warningStream_ = &cerr;
125
126 // set the unexpected exception callback
128
129 // register finalization function to be called when exit() is called
130 // so Application is finalized automatically on program exit
131 if (atexit(Application::finalize) != 0) {
132 writeToErrorLog(__FILE__, __LINE__, __FUNCTION__,
133 "Application initialization failed.");
134 abortProgram();
135 }
136
137 initialized_ = true;
138}
139
140void
141Application::initialize(int argc, char* argv[]) {
143 argc_ = argc;
144 argv_ = argv;
145}
146
147/**
148 * Allows writing to the log stream with stream operators.
149 *
150 * Usage example: logStream() << "Debug output" << i << endl;
151 *
152 * @return A reference to the log stream.
153 */
154std::ostream&
156 initialize();
157 return *logStream_;
158}
159
160/**
161 * Stream where error messages that should be printed immediately to the user
162 * should be written.
163 *
164 * Errors are fatal which means the action performed could not be finished.
165 *
166 * Usage example: errorStream() << "Compilation error: "...
167 *
168 * @return A reference to the error stream.
169 */
170std::ostream&
175
176/**
177 * Stream where warning messages that should be printed immediately to the user
178 * should be written.
179 *
180 * Warnings are non-fatal notifications to the user. The action performed
181 * might still be able to be finished.
182 *
183 * Usage example: warningStream() << "warning: uninitialized thing "...
184 *
185 * @return A reference to the warning stream.
186 */
187std::ostream&
192
193/**
194 * Cleans up the state data used by the application services.
195 *
196 * This method is called automatically when program is terminated.
197 */
198void
200
201 if (!initialized_) {
202 return;
203 }
204
205 if (logStream_ != &cerr && logStream_ != &cout && logStream_ != NULL) {
206 logStream_->flush();
207 delete logStream_;
208 logStream_ = NULL;
209 }
210 delete cmdLineOptions_;
211 cmdLineOptions_ = NULL;
212 initialized_ = false;
213}
214
215/**
216 * Records a message into the error log.
217 *
218 * @param fileName Source file of the code where the error occurred.
219 * @param lineNumber Source line where the error occurred.
220 * @param functionName Function where the error occurred.
221 * @param message The error message.
222 */
223void
225 const string fileName,
226 const int lineNumber,
227 const string functionName,
228 const string message,
229 const int neededVerbosity) {
230
231 if (neededVerbosity > verboseLevel_) {
232 return;
233 }
234
235 if (!initialized_) {
236 initialize();
237 }
238
239 *logStream_ << fileName << ":" << lineNumber << ": ";
240
241 if (functionName != UNKNOWN_FUNCTION) {
242 *logStream_ << "In function \'" << functionName << "\': ";
243 }
244
245 *logStream_ << message << endl;
246}
247
248
249/**
250 * Exits the program in a normal situation.
251 *
252 * This method must be used when the program terminates due to nominal
253 * conditions without returning from main().
254 *
255 * @param status Program's status of exit.
256 */
257void
258Application::exitProgram(const int status) {
259 exit(status);
260}
261
262/**
263 * Exit the program in an abnormal situation.
264 */
265void
267 abort();
268}
269
270/**
271 * Default callback for unexpected exceptions.
272 */
273void
276 << std::endl
277 << "Program aborted because of leaked unexpected exception. "
278 << std::endl << std::endl <<
279 "Information of the last thrown TCE exception: " << std::endl
280 << Exception::lastExceptionInfo() << std::endl;
281 abortProgram();
282}
283
284/**
285 * Returns true if all commands separated by space are found.
286 *
287 * Otherwise return false;
288 */
289bool
290Application::shellCommandsExists(const std::string& commands) {
291 return runShellCommandSilently(std::string("type ") + commands) == 0;
292}
293
294/**
295 * Runs a shell command and redirects all output to /dev/null
296 *
297 * @param command Command to execute.
298 * @return The return value of the program. -1 if some weird error occurred.
299 */
300int
302 const std::string& command) {
303
304 char line[MAX_OUTPUT_LINE_LENGTH];
305 // flush all streams to avoid: "...the output from a
306 // command opened for writing may become intermingled with that of
307 // the original process." (man popen)
308 fflush(NULL);
309
310 std::string fullCommand = command + " 2>&1 ";
311 FILE* pipe = popen(fullCommand.c_str(), "r");
312
313 while (fgets(line, MAX_OUTPUT_LINE_LENGTH, pipe) == line) {
314 // Drain stdout and stderr data.
315 }
316
317 int exitStatus = pclose(pipe);
318
319 // see man wait4 for info about macros WIFEXITED and WEXITSTATUS
320 if (WIFEXITED(exitStatus)) {
321 return WEXITSTATUS(exitStatus);
322 }
323
324 return -1;
325}
326
327/**
328 * Runs a shell command and captures its output (stdout) in the given vector.
329 *
330 * Assumes that the executed program does not block and wait for input.
331 *
332 * @param command Command to execute.
333 * @param outputLines Vector to which put the output lines.
334 * @param maxOutputLines Maximum lines to capture.
335 * @return The return value of the program. -1 if some weird error occured.
336 */
337int
339 const std::string& command,
340 std::vector<std::string>& outputLines,
341 std::size_t maxOutputLines,
342 bool includeStdErr) {
343
344 char line[MAX_OUTPUT_LINE_LENGTH];
345
346 // flush all streams to avoid: "...the output from a
347 // command opened for writing may become intermingled with that of
348 // the original process." (man popen)
349 fflush(NULL);
350
351 string shellCommand = command;
352 if (includeStdErr) {
353 shellCommand += " 2>1";
354 }
355 FILE* pipe = popen(shellCommand.c_str(), "r");
356
357 while (fgets(line, MAX_OUTPUT_LINE_LENGTH, pipe) == line) {
358
359 if (outputLines.size() < maxOutputLines) {
360 outputLines.push_back(string(line));
361 }
362 }
363
364 int exitStatus = pclose(pipe);
365
366 // see man wait4 for info about macros WIFEXITED and WEXITSTATUS
367 if (WIFEXITED(exitStatus)) {
368 return WEXITSTATUS(exitStatus);
369 }
370
371 return -1;
372}
373
374/**
375 * Set the command line options instance for the application.
376 *
377 * The object becomes owned by Application class. It should be
378 * fully built (parsed) before passed to Application.
379 */
380void
395
400
401/**
402 * Sets a new signal handler for the given signal
403 *
404 * Note in platforms which do not support signals (e.g. Windows),
405 * this function does nothing.
406 *
407 * @param signalNum signal number
408 * @param handler The handler to be set
409 */
410#ifdef __MINGW32__
411void
412Application::setSignalHandler(int, UnixSignalHandler&) {
413 return;
414}
415#else
416void
418 signalHandlers_[signalNum] = &handler;
419
420 struct sigaction action;
421 action.sa_flags = SA_SIGINFO;
422 action.sa_sigaction = signalRedirector;
423 // valgrind complains if this is uninitialized
424 sigemptyset(&action.sa_mask);
425 sigaction(signalNum, &action, NULL);
426}
427#endif
428
429/**
430 * Returns a pointer to the signal's current handler
431 *
432 * In platforms which do not support signals this method always
433 * returns NULL.
434 *
435 * @return a pointer to the signal's current handler
436 * @exception InstanceNotFound if the signal has not been set a custom handler
437 */
438#ifdef __MINGW32__
441 return NULL;
442}
443#else
446 std::map<int, UnixSignalHandler*>::iterator it =
447 signalHandlers_.find(signalNum);
448 if (it != signalHandlers_.end()) {
449 return it->second;
450 } else {
451 throw InstanceNotFound(__FILE__, __LINE__, __FUNCTION__);
452 }
453}
454#endif
455
456/**
457 * Restores to the signal its original handler
458 *
459 * Note in platforms which do not support signals (e.g. Windows),
460 * this function does nothing.
461 *
462 * @param signalNum signal number
463 */
464#ifdef __MINGW32__
465void
467 return;
468}
469#else
470void
472 signal(signalNum, SIG_DFL);
473 signalHandlers_.erase(signalNum);
474}
475#endif
476
477/**
478 * Redirects the signal received to the current signal handler
479 *
480 * Note in platforms which do not support signals (e.g. Windows),
481 * this function does nothing.
482 *
483 * @param data Data from the signal.
484 * @param info signal information struct
485 * @param context signal context
486 */
487#ifdef __MINGW32__
488void
489Application::signalRedirector(int, siginfo_t*, void*) {
490 return;
491}
492#else
493void
494Application::signalRedirector(int data, siginfo_t* info, void* /*context*/) {
495 UnixSignalHandler* handler = getSignalHandler(info->si_signo);
496 assert(handler != NULL);
497 handler->execute(data, info);
498}
499#endif
500
501/**
502 * Returns the version string of the TCE build.
503 *
504 * This string includes the version control revision (if available),
505 * automatically generated during build. This cannot be in headers
506 * as it would induce a (almost) complete build of TCE on every
507 * revision change.
508 */
509std::string
511 return TCE_VERSION_STRING;
512}
513
514/**
515 * Returns true if the application is running from an install path.
516 *
517 * Since there is no reliable way to detect this from the binary name
518 * or such since TCE can be used as a library, we just assume we are
519 * using an installed TCE in case the developer mode is not set.
520 */
521bool
525
526/**
527 * Returns the path to TCE installation root
528 *
529 * Installation root can be one created by 'make install' or .deb package
530 * unpacked to homedir for example. Environment variable TCE_INSTALL_DIR
531 * should be set in the second case pointing to that dir where .deb was
532 * installed or tce installation manually copied/moved to.
533 *
534 * @return Path to TCE installation root
535 */
536string
538
539 if (installationRoot_ != "") {
540 return installationRoot_;
541 }
542
543 string userRoot = Environment::environmentVariable("TCE_INSTALL_DIR");
544
545 // .deb check: check if envvar TCE_INSTALL_DIR is set
546 // and that dir exists ("icons" dir in our case)
547 if (userRoot != "" && FileSystem::fileExists(
548 userRoot + "/share/openasip/data/icons")) {
549 return userRoot;
550 }
551 return string(TCE_INSTALLATION_ROOT);
552}
#define WIFEXITED(stat_val)
#define WEXITSTATUS(stat_val)
const int MAX_OUTPUT_LINE_LENGTH
maximum length of an output line saved from popen() output in runShellCommandAndGetOutput()
#define UNKNOWN_FUNCTION
#define assert(condition)
static MachInfoCmdLineOptions options
Definition MachInfo.cc:46
virtual void execute(int data, siginfo_t *info)=0
static void setCmdLineOptions(CmdLineOptions *options_)
static CmdLineOptions * cmdLineOptions()
static std::ostream & warningStream()
static std::map< int, UnixSignalHandler * > signalHandlers_
Signal handlers in a map associated by their signal numbers.
static char ** argv()
static bool shellCommandsExists(const std::string &commands)
static bool isInstalled()
static void exitProgram(const int status=EXIT_SUCCESS)
static int runShellCommandAndGetOutput(const std::string &command, std::vector< std::string > &outputLines, std::size_t maxOutputLines=DEFAULT_MAX_OUTPUT_LINES, bool includeStdErr=false)
static std::string installationDir()
static void finalize()
static void unexpectedExceptionHandler()
static std::string installationRoot_
Path to the TCE installation root.
static const int VERBOSE_LEVEL_INCREASED
Increased verbose level - print information about modules etc.
static UnixSignalHandler * getSignalHandler(int signalNum)
static const int VERBOSE_LEVEL_SPAM
More Increased verbose level - spam about ddg heights of loops.
static void setSignalHandler(int signalNum, UnixSignalHandler &handler)
static std::ostream * logStream_
The stream for debug logging.
static void abortProgram() __attribute__((noreturn))
static CmdLineOptions * cmdLineOptions_
Holds command line options passed to program.
static void writeToErrorLog(const std::string fileName, const int lineNumber, const std::string functionName, const std::string message, const int neededVerbosity=0)
static int runShellCommandSilently(const std::string &command)
static void setVerboseLevel(const int level=VERBOSE_LEVEL_DEFAULT)
static bool initialized_
True when initialize() is called. Ensures that initialization is done only once.
static std::ostream * errorStream_
The stream for user error notifications.
static const int VERBOSE_LEVEL_DEFAULT
Default verbose level - do not print anything unnecessary.
static std::string TCEVersionString()
static char ** argv_
static int argc()
static std::ostream & errorStream()
static int verboseLevel_
Verbose level directs how much output will be printed to console.
static int argc_
The original argc and argv given to the main program, if applicable.
static std::ostream * warningStream_
The stream for user error notifications.
static std::ostream & logStream()
static void restoreSignalHandler(int signalNum)
static void initialize()
static void signalRedirector(int data, siginfo_t *info, void *context)
virtual bool isVerboseSwitchDefined() const
virtual bool isVerboseSpamSwitchDefined() const
static std::string environmentVariable(const std::string &variable)
static std::string errorLogFilePath()
static bool developerMode()
static std::string lastExceptionInfo()
Returns information of the last thrown exception.
Definition Exception.cc:108
static bool fileExists(const std::string fileName)