OpenASIP  2.0
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 
68 using std::fgets; // cstdio
69 using std::exit;
70 using std::abort;
71 using std::atexit;
72 using std::string;
73 using std::cerr;
74 using std::cout;
75 using std::endl;
76 using std::ofstream;
77 using std::ios;
78 using std::set_unexpected;
79 
80 
81 // static member variable initializations
82 bool Application::initialized_ = false;
83 std::ostream* Application::logStream_ = NULL;
84 std::ostream* Application::errorStream_ = NULL;
85 std::ostream* Application::warningStream_ = NULL;
86 std::map<int, Application::UnixSignalHandler*> Application::signalHandlers_;
87 
90 
92 char** Application::argv_;
94 
95 /**
96  * Initializes the state data needed by the application services.
97  */
98 void
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 
140 void
141 Application::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  */
154 std::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  */
170 std::ostream&
172  initialize();
173  return *errorStream_;
174 }
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  */
187 std::ostream&
189  initialize();
190  return *warningStream_;
191 }
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  */
198 void
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  */
223 void
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  */
257 void
258 Application::exitProgram(const int status) {
259  exit(status);
260 }
261 
262 /**
263  * Exit the program in an abnormal situation.
264  */
265 void
267  abort();
268 }
269 
270 /**
271  * Default callback for unexpected exceptions.
272  */
273 void
275  *logStream_
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  */
289 bool
290 Application::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  */
300 int
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  */
337 int
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  */
380 void
382 
383  // delete the possible old instance first
384  delete cmdLineOptions_;
386 
389  }
390 
393  }
394 }
395 
398  return cmdLineOptions_;
399 }
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__
411 void
412 Application::setSignalHandler(int, UnixSignalHandler&) {
413  return;
414 }
415 #else
416 void
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__
465 void
467  return;
468 }
469 #else
470 void
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__
488 void
489 Application::signalRedirector(int, siginfo_t*, void*) {
490  return;
491 }
492 #else
493 void
494 Application::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  */
509 std::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  */
521 bool
523  return !Environment::developerMode();
524 }
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  */
536 string
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 }
Application::installationRoot_
static std::string installationRoot_
Path to the TCE installation root.
Definition: Application.hh:261
FileSystem.hh
Application::finalize
static void finalize()
Definition: Application.cc:199
Application::errorStream_
static std::ostream * errorStream_
The stream for user error notifications.
Definition: Application.hh:242
Application::getSignalHandler
static UnixSignalHandler * getSignalHandler(int signalNum)
Definition: Application.cc:445
Exception.hh
Application::restoreSignalHandler
static void restoreSignalHandler(int signalNum)
Definition: Application.cc:471
Application::runShellCommandAndGetOutput
static int runShellCommandAndGetOutput(const std::string &command, std::vector< std::string > &outputLines, std::size_t maxOutputLines=DEFAULT_MAX_OUTPUT_LINES, bool includeStdErr=false)
Definition: Application.cc:338
Application::writeToErrorLog
static void writeToErrorLog(const std::string fileName, const int lineNumber, const std::string functionName, const std::string message, const int neededVerbosity=0)
Definition: Application.cc:224
Application::exitProgram
static void exitProgram(const int status=EXIT_SUCCESS)
Definition: Application.cc:258
Application::VERBOSE_LEVEL_DEFAULT
static const int VERBOSE_LEVEL_DEFAULT
Default verbose level - do not print anything unnecessary.
Definition: Application.hh:222
Application::setVerboseLevel
static void setVerboseLevel(const int level=VERBOSE_LEVEL_DEFAULT)
Definition: Application.hh:186
CmdLineOptions.hh
Exception::lastExceptionInfo
static std::string lastExceptionInfo()
Returns information of the last thrown exception.
Definition: Exception.cc:108
Application::setCmdLineOptions
static void setCmdLineOptions(CmdLineOptions *options_)
Definition: Application.cc:381
Application::logStream
static std::ostream & logStream()
Definition: Application.cc:155
Application::setSignalHandler
static void setSignalHandler(int signalNum, UnixSignalHandler &handler)
Definition: Application.cc:417
WIFEXITED
#define WIFEXITED(stat_val)
Definition: Application.cc:57
Environment::errorLogFilePath
static std::string errorLogFilePath()
Definition: Environment.cc:323
Application::logStream_
static std::ostream * logStream_
The stream for debug logging.
Definition: Application.hh:239
assert
#define assert(condition)
Definition: Application.hh:86
WEXITSTATUS
#define WEXITSTATUS(stat_val)
Definition: Application.cc:54
Application::UnixSignalHandler
Definition: Application.hh:203
Application::argc
static int argc()
Definition: Application.hh:192
CmdLineOptions
Definition: CmdLineOptions.hh:54
Application::initialized_
static bool initialized_
True when initialize() is called. Ensures that initialization is done only once.
Definition: Application.hh:236
Application.hh
Application::cmdLineOptions
static CmdLineOptions * cmdLineOptions()
Definition: Application.cc:397
MAX_OUTPUT_LINE_LENGTH
const int MAX_OUTPUT_LINE_LENGTH
maximum length of an output line saved from popen() output in runShellCommandAndGetOutput()
Definition: Application.hh:128
Application::warningStream_
static std::ostream * warningStream_
The stream for user error notifications.
Definition: Application.hh:245
Environment.hh
CmdLineOptions::isVerboseSwitchDefined
virtual bool isVerboseSwitchDefined() const
Definition: CmdLineOptions.cc:300
Application::VERBOSE_LEVEL_INCREASED
static const int VERBOSE_LEVEL_INCREASED
Increased verbose level - print information about modules etc.
Definition: Application.hh:224
Application::runShellCommandSilently
static int runShellCommandSilently(const std::string &command)
Definition: Application.cc:301
Application::cmdLineOptions_
static CmdLineOptions * cmdLineOptions_
Holds command line options passed to program.
Definition: Application.hh:254
UNKNOWN_FUNCTION
#define UNKNOWN_FUNCTION
Definition: Application.hh:58
options
static MachInfoCmdLineOptions options
Definition: MachInfo.cc:46
Application::signalHandlers_
static std::map< int, UnixSignalHandler * > signalHandlers_
Signal handlers in a map associated by their signal numbers.
Definition: Application.hh:248
Application::isInstalled
static bool isInstalled()
Definition: Application.cc:522
Application::argv
static char ** argv()
Definition: Application.hh:193
Application::errorStream
static std::ostream & errorStream()
Definition: Application.cc:171
FileSystem::fileExists
static bool fileExists(const std::string fileName)
Application::argv_
static char ** argv_
Definition: Application.hh:258
Application::installationDir
static std::string installationDir()
Definition: Application.cc:537
Application::initialize
static void initialize()
Definition: Application.cc:99
Application::argc_
static int argc_
The original argc and argv given to the main program, if applicable.
Definition: Application.hh:257
Application::VERBOSE_LEVEL_SPAM
static const int VERBOSE_LEVEL_SPAM
More Increased verbose level - spam about ddg heights of loops.
Definition: Application.hh:226
Application::warningStream
static std::ostream & warningStream()
Definition: Application.cc:188
Application::unexpectedExceptionHandler
static void unexpectedExceptionHandler()
Definition: Application.cc:274
Environment::developerMode
static bool developerMode()
Definition: Environment.cc:1166
Environment::environmentVariable
static std::string environmentVariable(const std::string &variable)
Definition: Environment.cc:406
Application::UnixSignalHandler::execute
virtual void execute(int data, siginfo_t *info)=0
Application::verboseLevel_
static int verboseLevel_
Verbose level directs how much output will be printed to console.
Definition: Application.hh:251
Application::abortProgram
static void abortProgram() __attribute__((noreturn))
Definition: Application.cc:266
Application::TCEVersionString
static std::string TCEVersionString()
Definition: Application.cc:510
InstanceNotFound
Definition: Exception.hh:304
Application::signalRedirector
static void signalRedirector(int data, siginfo_t *info, void *context)
Definition: Application.cc:494
CmdLineOptions::isVerboseSpamSwitchDefined
virtual bool isVerboseSpamSwitchDefined() const
Definition: CmdLineOptions.cc:310
Application::shellCommandsExists
static bool shellCommandsExists(const std::string &commands)
Definition: Application.cc:290