Branch data Line data Source code
1 : : //-------------------------------------------------------------------------
2 : : // Filename : AppUtil.cc
3 : : //
4 : : // Purpose : This file represents the Cubit application itself.
5 : : //
6 : : // Special Notes :
7 : : //
8 : : // Creator : Darryl Melander
9 : : //
10 : : // Date : 06/08/98
11 : : //
12 : : // Owner : Darryl Melander
13 : : //-------------------------------------------------------------------------
14 : :
15 : : #include <cstdio>
16 : : #include <cstdlib>
17 : : #include <signal.h>
18 : : #ifndef _WIN32
19 : : # include <unistd.h>
20 : : # include <termios.h>
21 : : # include <sys/ioctl.h>
22 : : #endif
23 : : #include <ctype.h>
24 : : #include <time.h>
25 : :
26 : : #include "AppUtil.hpp"
27 : : #include "CubitMessage.hpp"
28 : : #include "CubitString.hpp"
29 : : #include "CubitObserver.hpp"
30 : : #include "SettingHandler.hpp"
31 : : #include "StubProgressTool.hpp"
32 : :
33 : : #ifdef BUILD_WITH_CONCURRENT_SUPPORT
34 : : #include "CubitQtConcurrentApi.h"
35 : : #endif
36 : :
37 : : #ifdef CUBIT_USE_THREADS
38 : : #include "CubitThreadPool.hpp"
39 : : #endif
40 : :
41 : : // Different platforms follow different conventions
42 : : #ifndef _WIN32
43 : : #include <sys/resource.h>
44 : : #include <sys/types.h>
45 : : #include <sys/stat.h>
46 : : #include <fcntl.h>
47 : : #endif
48 : : #ifdef SOLARIS
49 : : #include <procfs.h>
50 : : #include <sys/syscall.h>
51 : : extern "C" int getrusage(int, struct rusage *);
52 : : #ifndef RUSAGE_SELF
53 : : #include </usr/ucbinclude/sys/rusage.h>
54 : : #endif
55 : : #endif
56 : :
57 : : #ifdef HP
58 : : #include <sys/syscall.h>
59 : : #if 0
60 : : #if OS_VERSION != 1020
61 : : #define getrusage(a, b) syscall(SYS_GETRUSAGE, a, b)
62 : : #endif
63 : : #endif
64 : : #endif
65 : :
66 : : #ifndef PATH_MAX
67 : : #define PATH_MAX _MAX_PATH
68 : : #endif
69 : :
70 : : #ifdef _WIN32
71 : : #include <windows.h>
72 : : extern "C" IMAGE_DOS_HEADER __ImageBase;
73 : : #else
74 : : #include <dlfcn.h>
75 : : #endif
76 : :
77 : : AppUtil* AppUtil::instance_ = NULL;
78 : :
79 : : #ifdef HP
80 : : #ifndef UNIX_PORT
81 : : extern "C" int Error;
82 : : #else
83 : : int Error = 0;
84 : : #endif //unix_port
85 : : #endif
86 : : #ifdef _WIN32
87 : : # include <direct.h>
88 : : # include <windows.h>
89 : : //# define strdup _strdup
90 : : #endif
91 : : #include "CubitUtil.hpp"
92 : :
93 : : // Interrupt handling defintions.
94 : : /* Setting this flag (asynchronously) to CUBIT_TRUE
95 : : * will cause Cubit/CGM to attempt to abort any current
96 : : * operations and return.
97 : : *
98 : : * NOTE: IT IS THE RESPONSIBILITY OF THE APPLICATION
99 : : * USING CGM TO RESET THIS FLAG TO CUBIT_FALSE!!!
100 : : * For Cubit, this flag is reset in UserInterface.
101 : : *
102 : : * CubitApp provides a default signal hander that will
103 : : * set this flag to CUBIT_TRUE whenever a SIGINT (^C)
104 : : * is detected. It is still the responsibility of the
105 : : * application using CGM to reset the flag to false!
106 : : * The signal hander provided by CubitApp may be set by
107 : : * calling CubitApp::instance()->catch_interrupt(CUBIT_TRUE).
108 : : *
109 : : * The storage space for this flag is defined in CubitApp.cpp
110 : : * and initialized in CubitApp::initialize().
111 : : */
112 : : static volatile CubitBoolean cubit_intr = CUBIT_FALSE;
113 : :
114 : 874 : extern "C" void cubit_update_terminal_size(int)
115 : : {
116 : : #if defined(_WIN32)
117 : :
118 : : // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getconsolescreenbufferinfo.asp
119 : : // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/scrolling_a_screen_buffer_s_window.asp
120 : : HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
121 : : CONSOLE_SCREEN_BUFFER_INFO scr_info;
122 : : if (GetConsoleScreenBufferInfo(h_stdout, &scr_info))
123 : : {
124 : : AppUtil::instance()->set_terminal_size(
125 : : // dwSize.Y is will return the height of the scroll-back buffer.
126 : : // srWindow contains the position of the visible rect of the
127 : : // window in the buffer. That is the height of the window.
128 : : scr_info.srWindow.Bottom - scr_info.srWindow.Top,
129 : : // use width of scroll buffer rather than size of window
130 : : // for number of columns. The window size is useless as
131 : : // caller would need to know the offset in the X direction
132 : : // to make use of it and we aren't returning that. Besides,
133 : : // the user presumably set the scroll buffer to this width
134 : : // because that's the line length (s)he wants.
135 : : scr_info.dwSize.X
136 : : );
137 : : }
138 : :
139 : : #elif defined(TIOCGWINSZ)
140 : :
141 : : // On UNIX platforms, register this function as a handler for
142 : : // SIGWINCH. The system will then call this function any time
143 : : // the user changes the size of the terminal window.
144 : : #ifdef SIGWINCH
145 : 874 : signal( SIGWINCH, &cubit_update_terminal_size );
146 : : #endif
147 : :
148 : 874 : const int file = fileno(stdout);
149 : : struct winsize size;
150 [ - + ]: 874 : if( ioctl( file, TIOCGWINSZ, (char*)&size ) == 0 )
151 : : {
152 [ # # ][ # # ]: 0 : AppUtil::instance()->set_terminal_size( size.ws_row, size.ws_col );
153 : : }
154 : :
155 : : #endif
156 : 874 : }
157 : :
158 : :
159 : : CubitBoolean AppUtil::catching_sigint_ = CUBIT_FALSE;
160 : :
161 : 0 : AppUtil* AppUtil::instance_no_create()
162 : : {
163 : 0 : return instance_;
164 : : }
165 : :
166 : : // Returns the singleton instance of the app object.
167 : : // If it is being created for the first time, it
168 : : // does application initialization.
169 : 277542 : AppUtil* AppUtil::instance()
170 : : {
171 [ + + ]: 277542 : if (instance_ == NULL)
172 : : {
173 [ + - ]: 874 : instance_ = new AppUtil();
174 : :
175 [ - + ]: 874 : if ( !instance_ )
176 : : {
177 [ # # ][ # # ]: 0 : PRINT_ERROR(" *** Unable to initialize application ***\n");
178 : 0 : exit(1);
179 : : }
180 : :
181 : : // Initialize interrupted flag to false.
182 : 874 : cubit_intr = CUBIT_FALSE;
183 : :
184 : 874 : cubit_update_terminal_size(0);
185 : :
186 : 874 : initialize_settings();
187 : : }
188 : 277542 : return instance_;
189 : : }
190 : :
191 [ + - ]: 1748 : AppUtil::AppUtil()
192 : : {
193 : 874 : term_width = 0;
194 : 874 : term_height = 0;
195 : 874 : mAppStarted = CUBIT_FALSE;
196 : :
197 : : // reset catching_sigint_ here, even though it's static, 'cuz it used
198 : : // to be reset to false on construction before going static
199 : :
200 : 874 : catching_sigint_ = CUBIT_FALSE;
201 : :
202 : : // create a default progress tool that does nothing
203 : : // an app can replace this with an app specific progress tool
204 [ + - ][ + - ]: 874 : mProgressTool = new StubProgressTool();
205 : :
206 : 874 : concurrentSupport = false;
207 : :
208 : 874 : this->mInterruptThrottle = clock();
209 : :
210 : : #ifdef CUBIT_USE_THREADS
211 : : mThreadPool = new CubitThreadPool;
212 : : #else
213 : 874 : mThreadPool = NULL;
214 : : #endif
215 : 874 : }
216 : :
217 [ # # ]: 0 : AppUtil::~AppUtil()
218 : : {
219 : 0 : instance_ = NULL;
220 [ # # ]: 0 : catch_interrupt( CUBIT_FALSE );
221 [ # # ]: 0 : if (mProgressTool)
222 [ # # ][ # # ]: 0 : delete mProgressTool;
223 : 0 : mProgressTool = NULL;
224 : : #ifdef CUBIT_USE_THREADS
225 : : delete mThreadPool;
226 : : #endif
227 : 0 : }
228 : :
229 : 0 : void AppUtil::delete_instance()
230 : : {
231 [ # # ]: 0 : if( NULL != instance_ )
232 : : {
233 [ # # ]: 0 : delete instance_;
234 : 0 : instance_ = NULL;
235 : : }
236 : 0 : }
237 : :
238 : : #ifdef CAT
239 : : // Returns how many days until the app expires. A negative
240 : : // number inicates it is already expired. If there is
241 : : // an extension, has_extension is set to CUBIT_TRUE.
242 : : int AppUtil::days_to_expire(int year, int month, int day ) const
243 : : {
244 : : // Setup variables and constants
245 : : struct tm expiration_time;
246 : : time_t raw_expire;
247 : : time_t raw_current;
248 : : int days;
249 : : const int SECONDS_PER_DAY = 24 * 60 * 60;
250 : :
251 : : // Get the current time, raw
252 : : time(&raw_current);
253 : :
254 : : // Setup a dissected expiration date
255 : : expiration_time.tm_year = year - 1900;
256 : : expiration_time.tm_mon = month - 1;
257 : : expiration_time.tm_mday = day;
258 : : expiration_time.tm_hour = 0;
259 : : expiration_time.tm_min = 0;
260 : : expiration_time.tm_sec = 0;
261 : : expiration_time.tm_isdst = 0;
262 : :
263 : : // Convert expiration date from dissected to raw
264 : : raw_expire = mktime(&expiration_time);
265 : : // Get difference between dates
266 : : days = (int)difftime(raw_expire, raw_current) / SECONDS_PER_DAY;
267 : : //days = INT_MAX;//(int)difftime(raw_expire, raw_current) / SECONDS_PER_DAY;
268 : : //changed back by aga@cat|11/2/04
269 : :
270 : : // Return days left
271 : : return days;
272 : : }
273 : : #endif
274 : :
275 : : // Prints out information about the session, like
276 : : // execution time and memory problems.
277 : 0 : void AppUtil::report_resource_usage() const
278 : : {
279 : :
280 : : #ifndef JANUS
281 : : #ifndef _WIN32
282 : : struct rusage r_usage;
283 : : float utime, stime;
284 [ # # ]: 0 : apputil_getrusage(r_usage);
285 : 0 : utime = (float)r_usage.ru_utime.tv_sec +
286 : 0 : ((float)r_usage.ru_utime.tv_usec/1.e6);
287 : 0 : stime = (float)r_usage.ru_stime.tv_sec +
288 : 0 : ((float)r_usage.ru_stime.tv_usec/1.e6);
289 [ # # ][ # # ]: 0 : static int pagesize = getpagesize();
290 [ # # ][ # # ]: 0 : PRINT_INFO("\nEnd of Execution\n");
[ # # ][ # # ]
291 [ # # ][ # # ]: 0 : PRINT_INFO("User time = %f\n", utime);
[ # # ][ # # ]
292 [ # # ][ # # ]: 0 : PRINT_INFO("System time = %f\n", stime);
[ # # ][ # # ]
293 [ # # ][ # # ]: 0 : PRINT_INFO("Total time = %f\n", utime+stime);
[ # # ][ # # ]
294 [ # # ][ # # ]: 0 : PRINT_INFO("Max resident set size = %ld bytes\n", r_usage.ru_maxrss*pagesize);
[ # # ][ # # ]
295 [ # # ][ # # ]: 0 : PRINT_INFO("Int resident set size = %ld\n", r_usage.ru_idrss);
[ # # ][ # # ]
296 [ # # ][ # # ]: 0 : PRINT_INFO("Minor Page Faults = %ld\n", r_usage.ru_minflt);
[ # # ][ # # ]
297 [ # # ][ # # ]: 0 : PRINT_INFO("Major Page Faults = %ld\n", r_usage.ru_majflt);
[ # # ][ # # ]
298 [ # # ][ # # ]: 0 : PRINT_INFO("Swaps = %ld\n", r_usage.ru_nswap);
[ # # ][ # # ]
299 : : #endif// _WIN32
300 : : #endif//JANUS
301 : 0 : }
302 : :
303 : :
304 : :
305 : : // Default handler for SIGINT provided by AppUtil.
306 : 0 : extern "C" void sigint_handler(int)
307 : : {
308 : : #ifndef CUBIT_NO_SIGNAL
309 [ # # ]: 0 : if( signal( SIGINT, sigint_handler ) == SIG_ERR )
310 [ # # ][ # # ]: 0 : PRINT_ERROR("Cannot continue to catch SIGINT!\n");
311 : 0 : cubit_intr = CUBIT_TRUE;
312 : : #endif
313 : 0 : }
314 : :
315 : : // Set signal handler for SIGINT.
316 : 0 : void AppUtil::catch_interrupt( CubitBoolean yesno )
317 : : {
318 : : #ifndef CUBIT_NO_SIGNAL
319 [ # # ]: 0 : if( yesno )
320 : : {
321 [ # # ]: 0 : if( signal( SIGINT, sigint_handler ) == SIG_ERR )
322 [ # # ][ # # ]: 0 : PRINT_ERROR("Can't catch SIGINT!\n");
323 : : else
324 : 0 : catching_sigint_ = CUBIT_TRUE;
325 : : }
326 : : else
327 : : {
328 [ # # ]: 0 : if( signal( SIGINT, SIG_DFL ) == SIG_ERR )
329 [ # # ][ # # ]: 0 : PRINT_ERROR("Can't reset SIGINT handler!\n");
330 : : else
331 : 0 : catching_sigint_ = CUBIT_FALSE;
332 : : }
333 : : #endif
334 : 0 : }
335 : :
336 : :
337 : 841 : void AppUtil::startup()
338 : : {
339 : : #ifndef NOT_AN_APP
340 [ - + ]: 841 : if (mAppStarted)
341 : 0 : return;
342 : :
343 : : // get paths to binaries that AppUtil is compiled into
344 : : // we'll make this our "cubitDir" and can be used a reference for
345 : : // where Cubit is installed
346 : : #ifdef _WIN32
347 : : wchar_t path_buffer[PATH_MAX];
348 : : if(GetModuleFileNameW((HINSTANCE)&__ImageBase, path_buffer, PATH_MAX))
349 : : {
350 : : *wcsrchr(path_buffer, '\\') = '\0';
351 : : cubitDir = CubitString::toUtf8(path_buffer);
352 : : }
353 : : #else
354 : : Dl_info dl_info;
355 : :
356 : : // Note: this is a nasty hack to avoid the warning:
357 : : // ISO C++ forbids casting between pointer-to-function and pointer-to-object
358 : : // Even with reinterpret_cast, this warning is still generated
359 : : // GCC accepts reinterpret_cast for purposes like in dlsym calls as an extension,
360 : : // but that might not work for other compilers
361 : : // This union-trick has been applied to some open source code, like:
362 : : // https://mail.gnome.org/archives/commits-list/2011-February/msg06409.html
363 : : // http://sourceforge.net/p/scstudio/mailman/message/29083334/
364 : : union {
365 : : void* ptr;
366 : : AppUtil* (*func)();
367 : : } cast_u;
368 : 841 : cast_u.func = AppUtil::instance;
369 : :
370 : 841 : dladdr(cast_u.ptr, &dl_info);
371 [ + - ]: 841 : CubitString path_buffer = dl_info.dli_fname;
372 [ + - ]: 841 : size_t idx = path_buffer.find_last('/');
373 [ + - ]: 841 : if(idx != CubitString::npos)
374 : : {
375 [ + - ][ + - ]: 841 : path_buffer = path_buffer.substr(0, idx);
[ + - ]
376 : : }
377 [ + - ]: 841 : cubitDir = path_buffer;
378 : : #endif
379 : :
380 : : #ifdef BUILD_WITH_CONCURRENT_SUPPORT
381 : : mConcurrentInstance = new CubitQtConcurrent;
382 : : this->concurrentSupport = true;
383 : : #endif
384 : :
385 : 841 : mAppStarted = CUBIT_TRUE;
386 : : // add startup code here
387 : : // nothing to do for now
388 : : #endif /*NOT_AN_APP*/
389 [ + - ]: 841 : return;
390 : : }
391 : :
392 : 0 : int AppUtil::shutdown()
393 : : {
394 : : // When the user is done, print out additional info if requested
395 [ # # ]: 0 : if (DEBUG_FLAG(3))
396 : 0 : report_resource_usage();
397 : :
398 : : // Return the number of errors in the session
399 : 0 : int ret_val = ( CubitMessage::instance()->error_count() );
400 [ # # ]: 0 : if ( ret_val > 0 )
401 : : {
402 [ # # ][ # # ]: 0 : PRINT_ERROR("Errors found during CUBIT session.\n");
403 : : }
404 : :
405 : : // Delete the singletons
406 : 0 : CubitMessage::delete_instance();
407 : :
408 : 0 : SettingHandler::delete_instance();
409 : :
410 : : #ifdef BUILD_WITH_CONCURRENT_SUPPORT
411 : : delete mConcurrentInstance;
412 : : #endif
413 : :
414 : 0 : mAppStarted = CUBIT_FALSE;
415 : :
416 : 0 : return ret_val;
417 : : }
418 : 0 : void AppUtil::apputil_getrusage(struct rusage &r_usage) const
419 : : {
420 : : // get the resource usage as defined by getrusage
421 : : #ifndef JANUS
422 : : #ifndef _WIN32
423 : 0 : getrusage(RUSAGE_SELF, &r_usage);
424 : :
425 [ # # ]: 0 : if (r_usage.ru_maxrss == 0) {
426 : : // this machine doesn't return rss - try going to /proc
427 : : // print the file name to open
428 : : #ifdef SOLARIS
429 : : char buffer[120];
430 : : strcpy(buffer, "/proc/self/psinfo");
431 : : int file_ptr = -1;
432 : : file_ptr = open(buffer, O_RDONLY);
433 : : if (file_ptr < 0) return;
434 : : struct psinfo myps_info;
435 : : read(file_ptr, &myps_info, sizeof(myps_info));
436 : : static int page_size = getpagesize();
437 : : r_usage.ru_maxrss = myps_info.pr_rssize*1024/page_size;
438 : : r_usage.ru_idrss = myps_info.pr_size*1024/page_size;
439 : : close (file_ptr);
440 : : #endif // SOLARIS
441 : : #ifdef CUBIT_LINUX
442 : : char file_str[4096], dum_str[4096];
443 : 0 : int file_ptr = -1, file_len;
444 [ # # ]: 0 : file_ptr = open("/proc/self/stat", O_RDONLY);
445 [ # # ]: 0 : file_len = read(file_ptr, file_str, sizeof(file_str)-1);
446 [ # # ]: 0 : if (file_len == 0) return;
447 [ # # ]: 0 : close(file_ptr);
448 : 0 : file_str[file_len] = '\0';
449 : : // read the preceeding fields and the ones we really want...
450 : : int dum_int;
451 : : unsigned int dum_uint, vm_size, rss;
452 [ # # ][ # # ]: 0 : static int page_size = getpagesize();
453 : : int num_fields = sscanf(file_str,
454 : : "%d " // pid
455 : : "%s " // comm
456 : : "%c " // state
457 : : "%d %d %d %d %d " // ppid, pgrp, session, tty, tpgid
458 : : "%u %u %u %u %u " // flags, minflt, cminflt, majflt, cmajflt
459 : : "%d %d %d %d %d %d " // utime, stime, cutime, cstime, counter, priority
460 : : "%u %u " // timeout, itrealvalue
461 : : "%d " // starttime
462 : : "%u %u", // vsize, rss
463 : : &dum_int,
464 : : dum_str,
465 : : dum_str,
466 : : &dum_int, &dum_int, &dum_int, &dum_int, &dum_int,
467 : : &dum_uint, &dum_uint, &dum_uint, &dum_uint, &dum_uint,
468 : : &dum_int, &dum_int, &dum_int, &dum_int, &dum_int, &dum_int,
469 : : &dum_uint, &dum_uint,
470 : : &dum_int,
471 : 0 : &vm_size, &rss);
472 [ # # ]: 0 : if (num_fields == 24) {
473 : 0 : r_usage.ru_maxrss = rss/page_size;
474 : 0 : r_usage.ru_idrss = vm_size/page_size;
475 : : }
476 : : #endif // CUBIT_LINUX
477 : : }
478 : : #endif // _WIN32
479 : : #endif // JANUS
480 : : }
481 : :
482 : 0 : bool AppUtil::get_terminal_size( int& rows, int& cols )
483 : : {
484 : 0 : cols = term_width;
485 : 0 : rows = term_height;
486 [ # # ][ # # ]: 0 : return rows || cols;
487 : : }
488 : :
489 : 0 : void AppUtil::set_terminal_size( int rows, int cols )
490 : : {
491 : 0 : term_width = cols;
492 : 0 : term_height = rows;
493 : 0 : }
494 : :
495 : 1157 : ProgressTool *AppUtil::progress_tool()
496 : : {
497 [ - + ]: 1157 : assert(mProgressTool != NULL);
498 : :
499 : 1157 : return mProgressTool;
500 : : }
501 : :
502 : 0 : void AppUtil::progress_tool(ProgressTool* pTool)
503 : : {
504 [ # # ]: 0 : assert(pTool != NULL); // existence is assumed elsewhere in the code
505 [ # # ]: 0 : if (pTool)
506 : : {
507 [ # # ]: 0 : if (mProgressTool)
508 : : {
509 [ # # ]: 0 : delete mProgressTool;
510 : : }
511 : 0 : mProgressTool = pTool;
512 : : }
513 : 0 : }
514 : :
515 : 0 : CubitThreadPool* AppUtil::thread_pool()
516 : : {
517 : 0 : return mThreadPool;
518 : : }
519 : :
520 : 874 : void AppUtil::initialize_settings()
521 : : {
522 : 874 : CubitMessage::initialize_settings();
523 : 874 : }
524 : :
525 : 29373 : CubitBoolean AppUtil::interrupt()
526 : : {
527 [ + - ]: 29373 : if(this->mProgressTool)
528 : : {
529 : 29373 : clock_t new_clock = clock();
530 : 29373 : clock_t diff = new_clock - this->mInterruptThrottle;
531 [ + + ]: 29373 : if((diff / static_cast<double>(CLOCKS_PER_SEC)) > 0.1)
532 : : {
533 : 800 : this->mInterruptThrottle = new_clock;
534 : 29373 : mProgressTool->check_interrupt();
535 : : }
536 : : }
537 : :
538 : 29373 : return cubit_intr;
539 : : }
540 : :
541 : 0 : void AppUtil::set_interrupt(CubitBoolean f)
542 : : {
543 [ # # ]: 0 : if(f)
544 : : {
545 : : // call raise so it works regardless of the current signal handler
546 : 0 : raise(SIGINT);
547 : : }
548 : 0 : cubit_intr = f;
549 : 0 : }
550 : :
551 : 0 : void AppUtil::clear_interrupt()
552 : : {
553 : 0 : cubit_intr = CUBIT_FALSE;
554 : 0 : }
555 : :
556 : 241275 : void AppUtil::send_event(CubitObservable* observable, const CubitEvent& event)
557 : : {
558 : 241275 : this->mEventDispatcher.send_event(observable, event);
559 : 241275 : }
|