From 8a262fa13d48f432224f367eabb710fa192c25e8 Mon Sep 17 00:00:00 2001 From: abv Date: Fri, 7 Dec 2012 16:12:01 +0400 Subject: [PATCH] 0023586: The test execution process should correctly stop on user demand Possibility to break DRAW commands by user break (Control-C) is implemented as follows: - Treatment of Control-C (SIGINT signal) on UNIX in OSD::SetSignal() is made coherent with Windows implementation: instead of attempt to raise exception (simulated by longjump, does not work anyway), signal handler just sets a flag which can be later checked by OSD::ControlBreak() - Call to OSD::ControlBreak() is added to common entry point for OCCT DRAW commands; this causes command interruption if Control-C has been pressed before its start. - Command "dbreak" added allowing to check Control-Break status from Tcl script (raises Tcl exception if break was signaled) - Command "dversion" added printing information on OCCT version, used build options, compiler, etc. - Test system modified to properly handle and report user breaks and add version info in the summary log Fix compiler error on Linux --- src/Draw/Draw_BasicCommands.cxx | 116 ++++++++++++++++++++++++++++- src/Draw/Draw_Interpretor.cxx | 4 + src/DrawResources/TestCommands.tcl | 26 ++++++- src/OSD/OSD_signal.cxx | 23 +++++- 4 files changed, 163 insertions(+), 6 deletions(-) diff --git a/src/Draw/Draw_BasicCommands.cxx b/src/Draw/Draw_BasicCommands.cxx index bd39550b9b..01794fe165 100755 --- a/src/Draw/Draw_BasicCommands.cxx +++ b/src/Draw/Draw_BasicCommands.cxx @@ -18,10 +18,10 @@ // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. - #include #include #include +#include #include #include @@ -30,6 +30,8 @@ #include #include #include +#include +#include #ifdef HAVE_CONFIG_H # include @@ -272,6 +274,113 @@ static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const ch return 0; } +static Standard_Integer dbreak(Draw_Interpretor& di, Standard_Integer, const char**) +{ + try { + OSD::ControlBreak(); + } + catch (OSD_Exception_CTRL_BREAK) { + di << "User pressed Control-Break"; + return 1; // Tcl exception + } + + return 0; +} + +static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const char**) +{ + // print OCCT version and OCCTY-specific macros used + di << "Open CASCADE Technology " << OCC_VERSION_STRING_EXT << "\n"; +#if defined(DEB) || defined(_DEBUG) + di << "Debug mode\n"; +#endif +#ifdef HAVE_TBB + di << "TBB enabled (HAVE_TBB)\n"; +#else + di << "TBB disabled\n"; +#endif +#ifdef HAVE_GL2PS + di << "GL2PS enabled (HAVE_GL2PS)\n"; +#else + di << "GL2PS disabled\n"; +#endif +#ifdef HAVE_FREEIMAGE + di << "FreeImage enabled (HAVE_FREEIMAGE)\n"; +#else + di << "FreeImage disabled\n"; +#endif +#ifdef No_Exception + di << "Exceptions disabled (No_Exception)\n"; +#else + di << "Exceptions enabled\n"; +#endif + + // check compiler, OS, etc. using pre-processor macros provided by compiler + // see "Pre-defined C/C++ Compiler Macros" http://sourceforge.net/p/predef/wiki/ + // note that only modern compilers that are known to be used for OCCT are recognized + + // compiler; note that GCC and MSVC are last as other compilers (e.g. Intel) can also define __GNUC__ and _MSC_VER +#if defined(__INTEL_COMPILER) + di << "Compiler: Intel " << __INTEL_COMPILER << "\n"; +#elif defined(__BORLANDC__) + di << "Compiler: Borland C++ (__BORLANDC__ = " << __BORLANDC__ << ")\n"; +#elif defined(__clang__) + di << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__ << "\n"; +#elif defined(__SUNPRO_C) + di << "Compiler: Sun Studio (__SUNPRO_C = " << __SUNPROC_C << ")\n"; +#elif defined(_MSC_VER) + di << "Compiler: MS Visual C++ " << (int)(_MSC_VER/100-6) << "." << (int)((_MSC_VER/10)-60-10*(int)(_MSC_VER/100-6)) << " (_MSC_FULL_VER = " << _MSC_FULL_VER << ")\n"; +#elif defined(__GNUC__) + di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n"; +#else + di << "Compiler: unrecognized\n"; +#endif + + // Cygwin and MinGW specifics +#if defined(__CYGWIN__) + di << "Cygwin\n"; +#endif +#if defined(__MINGW64__) + di << "MinGW 64 " << __MINGW64_MAJOR_VERSION << "." << __MINGW64_MINOR_VERSION << "\n"; +#elif defined(__MINGW32__) + di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n"; +#endif + + // architecture +#if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64) + di << "Architecture: AMD64\n"; +#elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_) + di << "Architecture: Intel x86\n"; +#elif defined(_M_IA64) || defined(__ia64__) + di << "Architecture: Intel Itanium (IA 64)\n"; +#elif defined(__sparc__) || defined(__sparc) + di << "Architecture: SPARC\n"; +#else + di << "Architecture: unrecognized\n"; +#endif + + // OS +#if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) + di << "OS: Windows\n"; +#elif defined(__APPLE__) || defined(__MACH__) + di << "OS: Mac OS X\n"; +#elif defined(__sun) + di << "OS: SUN Solaris\n"; +#elif defined(__ANDROID__) /* must be before Linux */ + #include + di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n"; +#elif defined(__linux__) + di << "OS: Linux\n"; +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + #include + di << "OS: BSD (BSD = " << BSD << ")\n"; +#else + di << "OS: unrecognized\n"; +#endif + + return 0; +} + //======================================================================= //function : wait //purpose : @@ -570,4 +679,9 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands) __FILE__,dlog,g); theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help", __FILE__,decho,g); + + theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key", + __FILE__,dbreak,g); + theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)", + __FILE__,dversion,g); } diff --git a/src/Draw/Draw_Interpretor.cxx b/src/Draw/Draw_Interpretor.cxx index 84381735c6..7a9aac764e 100755 --- a/src/Draw/Draw_Interpretor.cxx +++ b/src/Draw/Draw_Interpretor.cxx @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -206,6 +207,9 @@ static Standard_Integer CommandCmd try { OCC_CATCH_SIGNALS + // get exception if control-break has been pressed + OSD::ControlBreak(); + // OCC63: Convert strings from UTF-8 to local encoding, normally expected by OCC commands TclUTFToLocalStringSentry anArgs ( argc, (const char**)argv ); diff --git a/src/DrawResources/TestCommands.tcl b/src/DrawResources/TestCommands.tcl index f75c88d7a5..c20687dcd7 100644 --- a/src/DrawResources/TestCommands.tcl +++ b/src/DrawResources/TestCommands.tcl @@ -296,8 +296,9 @@ proc testgrid {args} { # log command arguments and environment set log "Command: testgrid $args\nHost: [info hostname]\nStarted on: [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S}]\n" + catch {set log "$log\nDRAW build:\n[dversion]\n" } set log "$log\nEnvironment:\n" - foreach envar [array names env] { + foreach envar [lsort [array names env]] { set log "$log$envar=\"$env($envar)\"\n" } set log "$log\n" @@ -321,7 +322,14 @@ proc testgrid {args} { } # start test cases + set userbreak 0 foreach test_def $tests_list { + # check for user break + if { "[info commands dbreak]" == "dbreak" && [catch dbreak] } { + set userbreak 1 + break + } + set dir [lindex $test_def 0] set group [lindex $test_def 1] set grid [lindex $test_def 2] @@ -387,12 +395,17 @@ proc testgrid {args} { # get results of started threads if { $parallel > 0 } { catch {tpool::resume $worker} - while { [llength [array names job_def]] > 0 } { + while { ! $userbreak && [llength [array names job_def]] > 0 } { foreach job [tpool::wait $worker [array names job_def]] { eval _log_test_case \[tpool::get $worker $job\] $job_def($job) log unset job_def($job) } + # check for user break + if { "[info commands dbreak]" == "dbreak" && [catch dbreak] } { + set userbreak 1 + } + # update summary log with requested period if { $logdir != "" && $refresh > 0 && [clock seconds] > $refresh_timer + $refresh } { _log_summarize $logdir $log @@ -400,12 +413,18 @@ proc testgrid {args} { } } # release thread pool + tpool::cancel $worker [array names job_def] tpool::release $worker } uplevel dchrono _timer stop set time [lindex [split [uplevel dchrono _timer show] "\n"] 0] + if { $userbreak } { + puts "*********** Stopped by user break ***********" + set time "${time} \nNote: the process is not finished, stopped by user break!" + } + ###################################################### # output summary logs and exit ###################################################### @@ -1243,7 +1262,8 @@ proc _log_html_summary {logdir log totals regressions improvements total_time} { # time stamp and elapsed time info if { $total_time != "" } { - puts $fd "

Generated on [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S}] on [info hostname]

$total_time" + puts $fd "

Generated on [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S}] on [info hostname]\n

" + puts $fd [join [split $total_time "\n"] "

"] } else { puts $fd "

NOTE: This is intermediate summary; the tests are still running! This page will refresh automatically until tests are finished." } diff --git a/src/OSD/OSD_signal.cxx b/src/OSD/OSD_signal.cxx index 6d292a47ae..73d3a8866d 100755 --- a/src/OSD/OSD_signal.cxx +++ b/src/OSD/OSD_signal.cxx @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,9 @@ static pthread_t getOCCThread () { static Standard_Boolean fFltExceptions = Standard_False; #endif +// variable signalling that Control-C has been pressed (SIGINT signal) +static Standard_Boolean fCtrlBrk; + //const OSD_WhoAmI Iam = OSD_WPackage; typedef void (ACT_SIGIO_HANDLER)(void) ; @@ -486,8 +490,11 @@ void OSD::Handler(const OSD_Signals theSignal, break; case SIGINT: - OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump(); - exit(SIGINT); + // For safe handling of Control-C as stop event, arm a variable but do not + // generate longjump (we are out of context anyway) + fCtrlBrk = Standard_True; +// OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump(); +// exit(SIGINT); break; case SIGQUIT: @@ -578,6 +585,18 @@ void OSD::Handler(const OSD_Signals theSignal, } } +//============================================================================ +//==== ControlBreak +//============================================================================ + +void OSD :: ControlBreak () +{ + if ( fCtrlBrk ) { + fCtrlBrk = Standard_False; + OSD_Exception_CTRL_BREAK::Raise ("*** INTERRUPT ***"); + } +} + //============================================================================ //==== SegvHandler //============================================================================