cgma
AppUtil.cpp
Go to the documentation of this file.
00001 //-------------------------------------------------------------------------
00002 // Filename      : AppUtil.cc
00003 //
00004 // Purpose       : This file represents the Cubit application itself.
00005 //
00006 // Special Notes :
00007 //
00008 // Creator       : Darryl Melander
00009 //
00010 // Date          : 06/08/98
00011 //
00012 // Owner         : Darryl Melander
00013 //-------------------------------------------------------------------------
00014 
00015 #include <cstdio>
00016 #include <cstdlib>
00017 #include <signal.h>
00018 #ifndef _WIN32
00019 #  include <unistd.h>
00020 #  include <termios.h>
00021 #  include <sys/ioctl.h>
00022 #endif
00023 #include <ctype.h>
00024 #include <time.h>
00025 
00026 #include "AppUtil.hpp"
00027 #include "CubitMessage.hpp"
00028 #include "CubitString.hpp"
00029 #include "CubitObserver.hpp"
00030 #include "SettingHandler.hpp"
00031 #include "StubProgressTool.hpp"
00032 
00033 #ifdef BUILD_WITH_CONCURRENT_SUPPORT
00034 #include "CubitQtConcurrentApi.h"
00035 #endif
00036 
00037 #ifdef CUBIT_USE_THREADS
00038 #include "CubitThreadPool.hpp"
00039 #endif
00040 
00041 // Different platforms follow different conventions
00042 #ifndef _WIN32
00043 #include <sys/resource.h>
00044 #include <sys/types.h>
00045 #include <sys/stat.h>
00046 #include <fcntl.h>
00047 #endif
00048 #ifdef SOLARIS
00049 #include <procfs.h>
00050 #include <sys/syscall.h>
00051 extern "C" int getrusage(int, struct rusage *);
00052 #ifndef RUSAGE_SELF
00053 #include </usr/ucbinclude/sys/rusage.h>
00054 #endif
00055 #endif
00056 
00057 #ifdef HP
00058 #include <sys/syscall.h>
00059 #if 0
00060 #if OS_VERSION != 1020
00061 #define getrusage(a, b)  syscall(SYS_GETRUSAGE, a, b)
00062 #endif
00063 #endif
00064 #endif
00065 
00066 #ifndef PATH_MAX
00067   #define PATH_MAX _MAX_PATH
00068 #endif
00069 
00070 #ifdef _WIN32
00071 #include <windows.h>
00072 extern "C" IMAGE_DOS_HEADER __ImageBase;
00073 #else
00074 #include <dlfcn.h>
00075 #endif
00076 
00077 AppUtil* AppUtil::instance_ = NULL;
00078 
00079 #ifdef HP
00080 #ifndef UNIX_PORT
00081 extern "C" int Error;
00082 #else
00083 int Error = 0;
00084 #endif //unix_port
00085 #endif
00086 #ifdef _WIN32
00087 #  include <direct.h>
00088 #  include <windows.h>
00089 //#  define strdup _strdup
00090 #endif
00091 #include "CubitUtil.hpp"
00092 
00093 // Interrupt handling defintions.
00094 /*  Setting this flag (asynchronously) to CUBIT_TRUE 
00095  *  will cause Cubit/CGM to attempt to abort any current
00096  *  operations and return.  
00097  * 
00098  * NOTE: IT IS THE RESPONSIBILITY OF THE APPLICATION 
00099  *       USING CGM TO RESET THIS FLAG TO CUBIT_FALSE!!!
00100  *       For Cubit, this flag is reset in UserInterface.
00101  *       
00102  *  CubitApp provides a default signal hander that will
00103  *  set this flag to CUBIT_TRUE whenever a SIGINT (^C)
00104  *  is detected.  It is still the responsibility of the
00105  *  application using CGM to reset the flag to false!
00106  *  The signal hander provided by CubitApp may be set by 
00107  *  calling CubitApp::instance()->catch_interrupt(CUBIT_TRUE).
00108  *
00109  *  The storage space for this flag is defined in CubitApp.cpp
00110  *  and initialized in CubitApp::initialize().
00111  */    
00112 static volatile CubitBoolean cubit_intr = CUBIT_FALSE;
00113 
00114 extern "C" void cubit_update_terminal_size(int)
00115 {
00116 #if defined(_WIN32)
00117 
00118   // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getconsolescreenbufferinfo.asp
00119   // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/scrolling_a_screen_buffer_s_window.asp
00120   HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
00121   CONSOLE_SCREEN_BUFFER_INFO scr_info;
00122   if (GetConsoleScreenBufferInfo(h_stdout, &scr_info))
00123   {
00124       AppUtil::instance()->set_terminal_size(
00125         // dwSize.Y is will return the height of the scroll-back buffer.
00126         // srWindow contains the position of the visible rect of the
00127         // window in the buffer.  That is the height of the window.
00128       scr_info.srWindow.Bottom - scr_info.srWindow.Top,
00129         // use width of scroll buffer rather than size of window
00130         // for number of columns.  The window size is useless as
00131         // caller would need to know the offset in the X direction
00132         // to make use of it and we aren't returning that.  Besides,
00133         // the user presumably set the scroll buffer to this width
00134         // because that's the line length (s)he wants.
00135       scr_info.dwSize.X
00136     );
00137   }
00138 
00139 #elif defined(TIOCGWINSZ)
00140 
00141     // On UNIX platforms, register this function as a handler for
00142     // SIGWINCH.  The system will then call this function any time
00143     // the user changes the size of the terminal window.
00144 #ifdef SIGWINCH
00145   signal( SIGWINCH, &cubit_update_terminal_size );
00146 #endif
00147 
00148   const int file = fileno(stdout);
00149   struct winsize size;
00150   if( ioctl( file, TIOCGWINSZ, (char*)&size ) == 0 )
00151   {
00152     AppUtil::instance()->set_terminal_size( size.ws_row, size.ws_col );
00153   }
00154 
00155 #endif
00156 }
00157 
00158 
00159 CubitBoolean AppUtil::catching_sigint_ = CUBIT_FALSE;
00160 
00161 AppUtil* AppUtil::instance_no_create()
00162 {
00163   return instance_;
00164 }
00165 
00166 // Returns the singleton instance of the app object.
00167 // If it is being created for the first time, it
00168 // does application initialization.
00169 AppUtil* AppUtil::instance()
00170 {
00171    if (instance_ == NULL)
00172    {
00173       instance_ = new AppUtil();
00174 
00175       if ( !instance_ )
00176       {
00177          PRINT_ERROR(" *** Unable to initialize application ***\n");
00178          exit(1);
00179       }
00180 
00181         // Initialize interrupted flag to false.
00182       cubit_intr = CUBIT_FALSE;
00183 
00184       cubit_update_terminal_size(0);
00185 
00186       initialize_settings();
00187    }
00188    return instance_;
00189 }
00190 
00191 AppUtil::AppUtil()
00192 {
00193     term_width = 0;
00194     term_height = 0;
00195     mAppStarted = CUBIT_FALSE;
00196 
00197       // reset catching_sigint_ here, even though it's static, 'cuz it used
00198       // to be reset to false on construction before going static
00199 
00200     catching_sigint_ = CUBIT_FALSE;
00201 
00202     // create a default progress tool that does nothing
00203     // an app can replace this with an app specific progress tool
00204     mProgressTool = new StubProgressTool();
00205 
00206     concurrentSupport = false;
00207 
00208     this->mInterruptThrottle = clock();
00209 
00210 #ifdef CUBIT_USE_THREADS
00211     mThreadPool = new CubitThreadPool;
00212 #else
00213     mThreadPool = NULL;
00214 #endif
00215 }
00216 
00217 AppUtil::~AppUtil()
00218 {
00219   instance_ = NULL;
00220   catch_interrupt( CUBIT_FALSE );
00221   if (mProgressTool)
00222       delete mProgressTool;
00223   mProgressTool = NULL;
00224 #ifdef CUBIT_USE_THREADS
00225   delete mThreadPool;
00226 #endif
00227 }
00228 
00229 void AppUtil::delete_instance()
00230 {
00231   if( NULL != instance_ )
00232   {
00233     delete instance_;
00234     instance_ = NULL;
00235   }
00236 }    
00237 
00238 #ifdef CAT
00239 // Returns how many days until the app expires.  A negative
00240 // number inicates it is already expired.  If there is
00241 // an extension, has_extension is set to CUBIT_TRUE.
00242 int AppUtil::days_to_expire(int year, int month, int day ) const
00243 {
00244      // Setup variables and constants
00245    struct tm expiration_time;
00246    time_t raw_expire;
00247    time_t raw_current;
00248    int days;
00249    const int SECONDS_PER_DAY = 24 * 60 * 60;
00250 
00251      // Get the current time, raw
00252    time(&raw_current);
00253 
00254      // Setup a dissected expiration date
00255    expiration_time.tm_year  = year - 1900;
00256    expiration_time.tm_mon   = month - 1;
00257    expiration_time.tm_mday  = day;
00258    expiration_time.tm_hour  = 0;
00259    expiration_time.tm_min   = 0;
00260    expiration_time.tm_sec   = 0;
00261    expiration_time.tm_isdst = 0;
00262 
00263      // Convert expiration date from dissected to raw
00264    raw_expire = mktime(&expiration_time);
00265      // Get difference between dates
00266    days = (int)difftime(raw_expire, raw_current) / SECONDS_PER_DAY;
00267    //days = INT_MAX;//(int)difftime(raw_expire, raw_current) / SECONDS_PER_DAY;
00268 //changed back by aga@cat|11/2/04
00269 
00270      // Return days left
00271    return days;
00272 }
00273 #endif
00274 
00275 // Prints out information about the session, like
00276 // execution time and memory problems.
00277 void AppUtil::report_resource_usage() const
00278 {
00279 
00280 #ifndef JANUS
00281 #ifndef _WIN32
00282    struct rusage r_usage;
00283    float utime, stime;
00284    apputil_getrusage(r_usage);
00285    utime = (float)r_usage.ru_utime.tv_sec +
00286       ((float)r_usage.ru_utime.tv_usec/1.e6);
00287    stime = (float)r_usage.ru_stime.tv_sec +
00288       ((float)r_usage.ru_stime.tv_usec/1.e6);
00289    static int pagesize = getpagesize();
00290    PRINT_INFO("\nEnd of Execution\n");
00291    PRINT_INFO("User time             = %f\n", utime);
00292    PRINT_INFO("System time           = %f\n", stime);
00293    PRINT_INFO("Total time            = %f\n", utime+stime);
00294    PRINT_INFO("Max resident set size = %ld bytes\n", r_usage.ru_maxrss*pagesize);
00295    PRINT_INFO("Int resident set size = %ld\n", r_usage.ru_idrss);
00296    PRINT_INFO("Minor Page Faults     = %ld\n", r_usage.ru_minflt);
00297    PRINT_INFO("Major Page Faults     = %ld\n", r_usage.ru_majflt);
00298    PRINT_INFO("Swaps                 = %ld\n", r_usage.ru_nswap);
00299 #endif// _WIN32
00300 #endif//JANUS
00301 }
00302 
00303 
00304 
00305 // Default handler for SIGINT provided by AppUtil.
00306 extern "C" void sigint_handler(int)
00307 {
00308 #ifndef CUBIT_NO_SIGNAL
00309   if( signal( SIGINT, sigint_handler ) == SIG_ERR )
00310     PRINT_ERROR("Cannot continue to catch SIGINT!\n");
00311   cubit_intr = CUBIT_TRUE;
00312 #endif
00313 }
00314 
00315 // Set signal handler for SIGINT.
00316 void AppUtil::catch_interrupt( CubitBoolean yesno )
00317 {
00318 #ifndef CUBIT_NO_SIGNAL
00319   if( yesno )
00320   {
00321     if( signal( SIGINT, sigint_handler ) == SIG_ERR )
00322       PRINT_ERROR("Can't catch SIGINT!\n");
00323     else
00324       catching_sigint_ = CUBIT_TRUE;
00325   }
00326   else
00327   {
00328     if( signal( SIGINT, SIG_DFL ) == SIG_ERR )
00329       PRINT_ERROR("Can't reset SIGINT handler!\n");
00330     else
00331       catching_sigint_ = CUBIT_FALSE;
00332   }
00333 #endif
00334 }
00335 
00336 
00337 void AppUtil::startup()
00338 {
00339 #ifndef NOT_AN_APP
00340     if (mAppStarted)
00341         return;
00342    
00343     // get paths to binaries that AppUtil is compiled into
00344     // we'll make this our "cubitDir" and can be used a reference for 
00345     // where Cubit is installed
00346 #ifdef _WIN32
00347     wchar_t path_buffer[PATH_MAX];
00348     if(GetModuleFileNameW((HINSTANCE)&__ImageBase, path_buffer, PATH_MAX))
00349     {
00350       *wcsrchr(path_buffer, '\\') = '\0';
00351       cubitDir = CubitString::toUtf8(path_buffer);
00352     }
00353 #else
00354     Dl_info dl_info;
00355 
00356     // Note: this is a nasty hack to avoid the warning:
00357     // ISO C++ forbids casting between pointer-to-function and pointer-to-object
00358     // Even with reinterpret_cast, this warning is still generated
00359     // GCC accepts reinterpret_cast for purposes like in dlsym calls as an extension,
00360     // but that might not work for other compilers
00361     // This union-trick has been applied to some open source code, like:
00362     // https://mail.gnome.org/archives/commits-list/2011-February/msg06409.html
00363     // http://sourceforge.net/p/scstudio/mailman/message/29083334/
00364     union {
00365       void* ptr;
00366       AppUtil* (*func)();
00367     } cast_u;
00368     cast_u.func = AppUtil::instance;
00369 
00370     dladdr(cast_u.ptr, &dl_info);
00371     CubitString path_buffer = dl_info.dli_fname;
00372     size_t idx = path_buffer.find_last('/');
00373     if(idx != CubitString::npos)
00374     {
00375       path_buffer = path_buffer.substr(0, idx);
00376     }
00377     cubitDir = path_buffer;
00378 #endif
00379 
00380 #ifdef BUILD_WITH_CONCURRENT_SUPPORT
00381     mConcurrentInstance = new CubitQtConcurrent;
00382     this->concurrentSupport = true;
00383 #endif
00384 
00385     mAppStarted = CUBIT_TRUE;
00386     // add startup code here
00387     // nothing to do for now
00388 #endif /*NOT_AN_APP*/
00389     return;
00390 }
00391 
00392 int AppUtil::shutdown()
00393 {
00394     // When the user is done, print out additional info if requested
00395    if (DEBUG_FLAG(3))
00396       report_resource_usage();
00397 
00398      // Return the number of errors in the session
00399    int ret_val = ( CubitMessage::instance()->error_count() );
00400    if ( ret_val > 0 )
00401    {
00402      PRINT_ERROR("Errors found during CUBIT session.\n");
00403    }
00404 
00405      // Delete the singletons
00406    CubitMessage::delete_instance();
00407 
00408    SettingHandler::delete_instance();
00409 
00410 #ifdef BUILD_WITH_CONCURRENT_SUPPORT
00411    delete mConcurrentInstance;
00412 #endif
00413 
00414    mAppStarted = CUBIT_FALSE;
00415 
00416    return ret_val;
00417 }
00418 void AppUtil::apputil_getrusage(struct rusage &r_usage) const
00419 {
00420     // get the resource usage as defined by getrusage
00421 #ifndef JANUS
00422 #ifndef _WIN32
00423    getrusage(RUSAGE_SELF, &r_usage);
00424 
00425    if (r_usage.ru_maxrss == 0) {
00426        // this machine doesn't return rss - try going to /proc
00427        // print the file name to open
00428 #ifdef SOLARIS
00429      char buffer[120];
00430      strcpy(buffer, "/proc/self/psinfo");
00431      int file_ptr = -1;
00432      file_ptr = open(buffer, O_RDONLY);
00433      if (file_ptr < 0) return;
00434      struct psinfo myps_info;
00435      read(file_ptr, &myps_info, sizeof(myps_info));
00436      static int page_size = getpagesize();
00437      r_usage.ru_maxrss = myps_info.pr_rssize*1024/page_size;
00438      r_usage.ru_idrss = myps_info.pr_size*1024/page_size;
00439      close (file_ptr);
00440 #endif // SOLARIS
00441 #ifdef CUBIT_LINUX
00442      char file_str[4096], dum_str[4096];
00443      int file_ptr = -1, file_len;
00444      file_ptr = open("/proc/self/stat", O_RDONLY);
00445      file_len = read(file_ptr, file_str, sizeof(file_str)-1);
00446      if (file_len == 0) return;
00447      close(file_ptr);
00448      file_str[file_len] = '\0';
00449        // read the preceeding fields and the ones we really want...
00450      int dum_int;
00451      unsigned int dum_uint, vm_size, rss;
00452      static int page_size = getpagesize();
00453      int num_fields = sscanf(file_str,
00454                              "%d " // pid
00455                              "%s " // comm
00456                              "%c " // state
00457                              "%d %d %d %d %d " // ppid, pgrp, session, tty, tpgid
00458                              "%u %u %u %u %u " // flags, minflt, cminflt, majflt, cmajflt
00459                              "%d %d %d %d %d %d " // utime, stime, cutime, cstime, counter, priority
00460                              "%u %u " // timeout, itrealvalue
00461                              "%d " // starttime
00462                              "%u %u", // vsize, rss
00463                              &dum_int,
00464                              dum_str,
00465                              dum_str,
00466                              &dum_int, &dum_int, &dum_int, &dum_int, &dum_int,
00467                              &dum_uint, &dum_uint, &dum_uint, &dum_uint, &dum_uint,
00468                              &dum_int, &dum_int, &dum_int, &dum_int, &dum_int, &dum_int,
00469                              &dum_uint, &dum_uint,
00470                              &dum_int,
00471                              &vm_size, &rss);
00472      if (num_fields == 24) {
00473        r_usage.ru_maxrss = rss/page_size;
00474        r_usage.ru_idrss = vm_size/page_size;
00475      }
00476 #endif // CUBIT_LINUX
00477    }
00478 #endif // _WIN32
00479 #endif // JANUS
00480 }
00481 
00482 bool AppUtil::get_terminal_size( int& rows, int& cols )
00483 {
00484   cols = term_width;
00485   rows = term_height;
00486   return rows || cols;
00487 }
00488 
00489 void AppUtil::set_terminal_size( int rows, int cols )
00490 {
00491   term_width = cols;
00492   term_height = rows;
00493 }
00494 
00495 ProgressTool *AppUtil::progress_tool()
00496 {
00497   assert(mProgressTool != NULL);
00498 
00499   return mProgressTool;
00500 }
00501 
00502 void AppUtil::progress_tool(ProgressTool* pTool)
00503 {
00504   assert(pTool != NULL);  // existence is assumed elsewhere in the code
00505   if (pTool)
00506   {
00507       if (mProgressTool)
00508       {
00509           delete mProgressTool;
00510       }
00511       mProgressTool = pTool;
00512   }
00513 }
00514 
00515 CubitThreadPool* AppUtil::thread_pool()
00516 {
00517   return mThreadPool;
00518 }
00519 
00520 void AppUtil::initialize_settings()
00521 {
00522   CubitMessage::initialize_settings();
00523 }
00524 
00525 CubitBoolean AppUtil::interrupt()
00526 {
00527   if(this->mProgressTool)
00528   {
00529     clock_t new_clock = clock();
00530     clock_t diff = new_clock - this->mInterruptThrottle;
00531     if((diff / static_cast<double>(CLOCKS_PER_SEC)) > 0.1)
00532     {
00533       this->mInterruptThrottle = new_clock;
00534       mProgressTool->check_interrupt();
00535     }
00536   }
00537 
00538   return cubit_intr;
00539 }
00540 
00541 void AppUtil::set_interrupt(CubitBoolean f)
00542 {
00543   if(f)
00544   {
00545     // call raise so it works regardless of the current signal handler
00546     raise(SIGINT);
00547   }
00548   cubit_intr = f;
00549 }
00550 
00551 void AppUtil::clear_interrupt()
00552 {
00553   cubit_intr = CUBIT_FALSE;
00554 }
00555 
00556 void AppUtil::send_event(CubitObservable* observable, const CubitEvent& event)
00557 {
00558     this->mEventDispatcher.send_event(observable, event);
00559 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines