0027801: Configuration - fix compilation of Standard.cxx when using MinGW-W64
[occt.git] / src / OSD / OSD_signal.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14
15 #include <OSD.hxx>
16 #include <OSD_Exception_CTRL_BREAK.hxx>
17 #include <Standard_DivideByZero.hxx>
18 #include <Standard_Overflow.hxx>
19
20 #ifdef _WIN32
21 //---------------------------- Windows NT System --------------------------------
22
23 #define STRICT
24 #ifdef NOUSER
25 #undef NOUSER
26 #endif
27 #include <windows.h>
28
29 #ifndef STATUS_FLOAT_MULTIPLE_FAULTS
30   // <ntstatus.h>
31   #define STATUS_FLOAT_MULTIPLE_FAULTS     (0xC00002B4L)
32   #define STATUS_FLOAT_MULTIPLE_TRAPS      (0xC00002B5L)
33 #endif
34
35 #include <OSD_Exception_ACCESS_VIOLATION.hxx>
36 #include <OSD_Exception_ARRAY_BOUNDS_EXCEEDED.hxx>
37 #include <OSD_Exception_ILLEGAL_INSTRUCTION.hxx>
38 #include <OSD_Exception_IN_PAGE_ERROR.hxx>
39 #include <OSD_Exception_INT_DIVIDE_BY_ZERO.hxx>
40 #include <OSD_Exception_INT_OVERFLOW.hxx>
41 #include <OSD_Exception_INVALID_DISPOSITION.hxx>
42 #include <OSD_Exception_NONCONTINUABLE_EXCEPTION.hxx>
43 #include <OSD_Exception_PRIV_INSTRUCTION.hxx>
44 #include <OSD_Exception_STACK_OVERFLOW.hxx>
45 #include <OSD_Exception_STATUS_NO_MEMORY.hxx>
46
47 #include <OSD_Environment.hxx>
48 #include <Standard_Underflow.hxx>
49 #include <Standard_ProgramError.hxx>
50 #include <Standard_Mutex.hxx>
51
52 #include <OSD_WNT_1.hxx>
53
54 #ifdef _MSC_VER
55 #include <eh.h>
56 #include <malloc.h>
57 #endif
58
59 #include <process.h>
60 #include <signal.h>
61 #include <float.h>
62
63 static Standard_Boolean fCtrlBrk;
64 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
65 static Standard_Boolean fMsgBox;
66 static Standard_Boolean fFltExceptions;
67 static Standard_Boolean fDbgLoaded;
68
69 // used to forbid simultaneous execution of setting / executing handlers
70 static Standard_Mutex THE_SIGNAL_MUTEX;
71
72 static LONG __fastcall _osd_raise ( DWORD, LPSTR );
73 static BOOL WINAPI     _osd_ctrl_break_handler ( DWORD );
74
75 static LONG _osd_debug   ( void );
76
77 //# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
78 # define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
79
80 //=======================================================================
81 //function : CallHandler
82 //purpose  :
83 //=======================================================================
84 static LONG CallHandler (DWORD dwExceptionCode,
85                          ptrdiff_t ExceptionInformation1,
86                          ptrdiff_t ExceptionInformation0)
87 {
88   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
89   static char          buffer[ 2048 ];
90   int                  flterr = 0;
91
92   buffer[0] = '\0' ;
93
94 // cout << "CallHandler " << dwExceptionCode << endl ;
95   switch ( dwExceptionCode ) {
96     case EXCEPTION_FLT_DENORMAL_OPERAND:
97 //      cout << "CallHandler : EXCEPTION_FLT_DENORMAL_OPERAND:" << endl ;
98       lstrcpyA (  buffer, "FLT DENORMAL OPERAND"  );
99       flterr = 1 ;
100       break ;
101     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
102 //      cout << "CallHandler : EXCEPTION_FLT_DIVIDE_BY_ZERO:" << endl ;
103       lstrcpyA (  buffer, "FLT DIVIDE BY ZERO"  );
104       flterr = 1 ;
105       break ;
106     case EXCEPTION_FLT_INEXACT_RESULT:
107 //      cout << "CallHandler : EXCEPTION_FLT_INEXACT_RESULT:" << endl ;
108       lstrcpyA (  buffer, "FLT INEXACT RESULT"  );
109       flterr = 1 ;
110       break ;
111     case EXCEPTION_FLT_INVALID_OPERATION:
112 //      cout << "CallHandler : EXCEPTION_FLT_INVALID_OPERATION:" << endl ;
113       lstrcpyA (  buffer, "FLT INVALID OPERATION"  );
114       flterr = 1 ;
115       break ;
116     case EXCEPTION_FLT_OVERFLOW:
117 //      cout << "CallHandler : EXCEPTION_FLT_OVERFLOW:" << endl ;
118       lstrcpyA (  buffer, "FLT OVERFLOW"  );
119       flterr = 1 ;
120       break ;
121     case EXCEPTION_FLT_STACK_CHECK:
122 //      cout << "CallHandler : EXCEPTION_FLT_STACK_CHECK:" << endl ;
123       lstrcpyA (  buffer, "FLT STACK CHECK"  );
124       flterr = 1 ;
125       break ;
126     case EXCEPTION_FLT_UNDERFLOW:
127 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
128       lstrcpyA (  buffer, "FLT UNDERFLOW"  );
129       flterr = 1 ;
130       break ;
131     case STATUS_FLOAT_MULTIPLE_TRAPS:
132 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
133       lstrcpyA (  buffer, "FLT MULTIPLE TRAPS (possible overflow in conversion of double to integer)"  );
134       flterr = 1 ;
135       break ;
136     case STATUS_FLOAT_MULTIPLE_FAULTS:
137 //      cout << "CallHandler : EXCEPTION_FLT_UNDERFLOW:" << endl ;
138       lstrcpyA (  buffer, "FLT MULTIPLE FAULTS"  );
139       flterr = 1 ;
140       break ;
141     case STATUS_NO_MEMORY:
142 //      cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
143       OSD_Exception_STATUS_NO_MEMORY ::
144       Raise (  "MEMORY ALLOCATION ERROR ( no room in the process heap )"  );
145     case EXCEPTION_ACCESS_VIOLATION:
146 //      cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
147       wsprintf ( buffer, "%s%s%s0x%.8p%s%s%s", "ACCESS VIOLATION",
148                  fMsgBox ? "\n" : " ", "at address ",
149                  ExceptionInformation1 ,
150                  " during '",
151                  ExceptionInformation0 ? "WRITE" : "READ",
152                  "' operation");
153       break;
154     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
155 //      cout << "CallHandler : EXCEPTION_ARRAY_BOUNDS_EXCEEDED:" << endl ;
156       lstrcpyA (  buffer, "ARRAY BOUNDS EXCEEDED"  );
157       break;
158     case EXCEPTION_DATATYPE_MISALIGNMENT:
159 //      cout << "CallHandler : EXCEPTION_DATATYPE_MISALIGNMENT:" << endl ;
160       lstrcpyA (  buffer, "DATATYPE MISALIGNMENT"  );
161       break;
162
163     case EXCEPTION_ILLEGAL_INSTRUCTION:
164 //      cout << "CallHandler : EXCEPTION_ILLEGAL_INSTRUCTION:" << endl ;
165       lstrcpyA (  buffer, "ILLEGAL INSTRUCTION"  );
166       break;
167
168     case EXCEPTION_IN_PAGE_ERROR:
169 //      cout << "CallHandler : EXCEPTION_IN_PAGE_ERROR:" << endl ;
170       lstrcpyA (  buffer, "IN_PAGE ERROR"  );
171       break;
172
173     case EXCEPTION_INT_DIVIDE_BY_ZERO:
174 //      cout << "CallHandler : EXCEPTION_INT_DIVIDE_BY_ZERO:" << endl ;
175       lstrcpyA (  buffer, "INTEGER DIVISION BY ZERO"  );
176       break;
177
178     case EXCEPTION_INT_OVERFLOW:
179 //      cout << "CallHandler : EXCEPTION_INT_OVERFLOW:" << endl ;
180       lstrcpyA (  buffer, "INTEGER OVERFLOW"  );
181       break;
182
183     case EXCEPTION_INVALID_DISPOSITION:
184 //      cout << "CallHandler : EXCEPTION_INVALID_DISPOSITION:" << endl ;
185       lstrcpyA (  buffer, "INVALID DISPOSITION"  );
186       break;
187
188     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
189 //      cout << "CallHandler : EXCEPTION_NONCONTINUABLE_EXCEPTION:" << endl ;
190       lstrcpyA (  buffer, "NONCONTINUABLE EXCEPTION"  );
191       break;
192
193     case EXCEPTION_PRIV_INSTRUCTION:
194 //      cout << "CallHandler : EXCEPTION_PRIV_INSTRUCTION:" << endl ;
195       lstrcpyA (  buffer, "PRIVELEGED INSTRUCTION ENCOUNTERED"  );
196       break;
197
198     case EXCEPTION_STACK_OVERFLOW:
199 //      cout << "CallHandler : EXCEPTION_STACK_OVERFLOW:" << endl ;
200 #if defined( _MSC_VER ) && ( _MSC_VER >= 1300 )
201     // try recovering from stack overflow: available in MS VC++ 7.0
202       if (!_resetstkoflw())
203         lstrcpyA (  buffer, "Unrecoverable STACK OVERFLOW"  );
204       else
205 #endif
206         lstrcpyA (  buffer, "STACK OVERFLOW"  );
207       break;
208
209     default:
210       wsprintf( buffer, "unknown exception code 0x%x, params 0x%p 0x%p",
211                 dwExceptionCode, ExceptionInformation1, ExceptionInformation0 );
212
213   }  // end switch
214
215  // provide message to the user with possibility to stop
216   int idx = lstrlenA ( buffer );
217   if ( idx && fMsgBox && dwExceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION ) {
218      // reset FP operations before message box, otherwise it may fail to show up
219     _fpreset();
220     _clearfp();
221
222     MessageBeep ( MB_ICONHAND );
223     int aChoice = ::MessageBox (0, buffer, "OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
224     if (aChoice == IDRETRY)
225     {
226       _osd_debug();
227       DebugBreak();
228     } else if (aChoice == IDABORT)
229       exit(0xFFFF);
230   }
231
232   // reset FPE state
233   if ( flterr ) {
234     if ( !fFltExceptions ) return EXCEPTION_EXECUTE_HANDLER;
235    _fpreset () ;
236    _clearfp() ;
237    _controlfp ( 0, _OSD_FPX ) ;          // JR add :
238 //     cout << "OSD::WntHandler _controlfp( 0, _OSD_FPX ) " << hex << _controlfp(0,0) << dec << endl ;
239   }
240   return _osd_raise ( dwExceptionCode, buffer );
241 }
242
243 //=======================================================================
244 //function : SIGWntHandler
245 //purpose  : Will only be used if user calls ::raise() function with
246 //           signal type set in OSD::SetSignal() - SIGSEGV, SIGFPE, SIGILL
247 //           (the latter will likely be removed in the future)
248 //=======================================================================
249 static void SIGWntHandler (int signum, int sub_code)
250 {
251   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
252   switch( signum ) {
253     case SIGFPE :
254       if ( signal( signum , (void(*)(int))SIGWntHandler ) == SIG_ERR )
255         cout << "signal error" << endl ;
256       switch( sub_code ) {
257         case _FPE_INVALID :
258           CallHandler( EXCEPTION_FLT_INVALID_OPERATION ,0,0) ;
259           break ;
260         case _FPE_DENORMAL :
261           CallHandler( EXCEPTION_FLT_DENORMAL_OPERAND ,0,0) ;
262           break ;
263         case _FPE_ZERODIVIDE :
264           CallHandler( EXCEPTION_FLT_DIVIDE_BY_ZERO ,0,0) ;
265           break ;
266         case _FPE_OVERFLOW :
267           CallHandler( EXCEPTION_FLT_OVERFLOW ,0,0) ;
268           break ;
269         case _FPE_UNDERFLOW :
270           CallHandler( EXCEPTION_FLT_UNDERFLOW ,0,0) ;
271           break ;
272         case _FPE_INEXACT :
273           CallHandler( EXCEPTION_FLT_INEXACT_RESULT ,0,0) ;
274           break ;
275         default:
276           cout << "SIGWntHandler(default) -> Standard_NumericError::Raise(\"Floating Point Error\");" << endl;
277           Standard_NumericError::Raise("Floating Point Error");
278           break ;
279       }
280       break ;
281     case SIGSEGV :
282       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
283         cout << "signal error" << endl ;
284       CallHandler( EXCEPTION_ACCESS_VIOLATION ,0,0) ;
285       break ;
286     case SIGILL :
287       if ( signal( signum, (void(*)(int))SIGWntHandler ) == SIG_ERR )
288         cout << "signal error" << endl ;
289       CallHandler( EXCEPTION_ILLEGAL_INSTRUCTION ,0,0) ;
290       break ;
291     default:
292       cout << "SIGWntHandler unexpected signal : " << signum << endl ;
293       break ;
294   }
295   DebugBreak ();
296 }
297 #endif
298
299 //=======================================================================
300 //function : TranslateSE
301 //purpose  : Translate Structural Exceptions into C++ exceptions
302 //           Will be used when user's code is compiled with /EHa option
303 //=======================================================================
304 #ifdef _MSC_VER
305 // If this file compiled with the default MSVC options for exception
306 // handling (/GX or /EHsc) then the following warning is issued:
307 //   warning C4535: calling _set_se_translator() requires /EHa
308 // However it is correctly inserted and used when user's code compiled with /EHa.
309 // So, here we disable the warning.
310 #pragma warning (disable:4535)
311
312 static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
313 {
314   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
315   ptrdiff_t info1 = 0, info0 = 0;
316   if ( theExcPtr ) {
317     info1 = theExcPtr->ExceptionRecord->ExceptionInformation[1];
318     info0 = theExcPtr->ExceptionRecord->ExceptionInformation[0];
319   }
320   CallHandler(theCode, info1, info0);
321 }
322 #endif
323
324 //=======================================================================
325 //function : WntHandler
326 //purpose  : Will be used when user's code is compiled with /EHs
327 //           option and unless user sets his own exception handler with
328 //           ::SetUnhandledExceptionFilter().
329 //=======================================================================
330 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
331 static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
332 {
333   DWORD               dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
334
335   return CallHandler (dwExceptionCode,
336                       lpXP->ExceptionRecord->ExceptionInformation[1],
337                       lpXP->ExceptionRecord->ExceptionInformation[0]);
338 }
339 #endif
340
341 //=======================================================================
342 //function : SetSignal
343 //purpose  :
344 //=======================================================================
345 void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
346 {
347 #if !defined(__CYGWIN32__) && !defined(__MINGW32__)
348   Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
349   LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
350
351   OSD_Environment env (TEXT("CSF_DEBUG_MODE"));
352   TCollection_AsciiString val = env.Value();
353   if (!env.Failed())
354   {
355     cout << "Environment variable CSF_DEBUG_MODE setted.\n";
356     fMsgBox = Standard_True;
357   }
358   else
359   {
360     fMsgBox = Standard_False;
361   }
362
363   // Set exception handler (ignored when running under debugger). It will be used in most cases
364   // when user's code is compiled with /EHs
365   // Replaces the existing top-level exception filter for all existing and all future threads
366   // in the calling process
367   aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
368
369   // Signal handlers will only be used when the method ::raise() will be used
370   // Handlers must be set for every thread
371   if (signal (SIGSEGV, (void(*)(int))SIGWntHandler) == SIG_ERR)
372     cout << "signal(OSD::SetSignal) error\n";
373   if (signal (SIGFPE,  (void(*)(int))SIGWntHandler) == SIG_ERR)
374     cout << "signal(OSD::SetSignal) error\n";
375   if (signal (SIGILL,  (void(*)(int))SIGWntHandler) == SIG_ERR)
376     cout << "signal(OSD::SetSignal) error\n";
377
378   // Set Ctrl-C and Ctrl-Break handler
379   fCtrlBrk = Standard_False;
380   SetConsoleCtrlHandler (&_osd_ctrl_break_handler, TRUE);
381
382 #ifdef _MSC_VER
383 //  _se_translator_function pOldSeFunc =
384   _set_se_translator (TranslateSE);
385 #endif
386
387   fFltExceptions = theFloatingSignal;
388   if (theFloatingSignal)
389   {
390     _controlfp (0, _OSD_FPX);        // JR add :
391   }
392   else {
393     _controlfp (_OSD_FPX, _OSD_FPX); // JR add :
394   }
395 #endif
396 }  // end OSD :: SetSignal
397
398 //============================================================================
399 //==== ControlBreak
400 //============================================================================
401 void OSD::ControlBreak () {
402   if ( fCtrlBrk ) {
403     fCtrlBrk = Standard_False;
404     OSD_Exception_CTRL_BREAK :: Raise (  TEXT( "*** INTERRUPT ***" )  );
405   }
406 }  // end OSD :: ControlBreak
407
408 #if !defined(__MINGW32__) && !defined(__CYGWIN32__)
409 //============================================================================
410 //==== _osd_ctrl_break_handler
411 //============================================================================
412 static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
413   if ( dwCode == CTRL_C_EVENT || dwCode == CTRL_BREAK_EVENT ) {
414     MessageBeep ( MB_ICONEXCLAMATION );
415     fCtrlBrk = Standard_True;
416   } else
417     exit ( 254 );
418
419   return TRUE;
420 }  // end _osd_ctrl_break_handler
421
422 //============================================================================
423 //==== _osd_raise
424 //============================================================================
425 static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
426 {
427   if (msg[0] == '\x03') ++msg;
428
429   switch (dwCode)
430   {
431     case EXCEPTION_ACCESS_VIOLATION:
432       OSD_Exception_ACCESS_VIOLATION::Raise (msg);
433       break;
434     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
435       OSD_Exception_ARRAY_BOUNDS_EXCEEDED::Raise (msg);
436       break;
437     case EXCEPTION_DATATYPE_MISALIGNMENT:
438       Standard_ProgramError::Raise (msg);
439       break;
440     case EXCEPTION_ILLEGAL_INSTRUCTION:
441       OSD_Exception_ILLEGAL_INSTRUCTION::Raise (msg);
442       break;
443     case EXCEPTION_IN_PAGE_ERROR:
444       OSD_Exception_IN_PAGE_ERROR::Raise (msg);
445       break;
446     case EXCEPTION_INT_DIVIDE_BY_ZERO:
447       Standard_DivideByZero::Raise (msg);
448       break;
449     case EXCEPTION_INT_OVERFLOW:
450       OSD_Exception_INT_OVERFLOW::Raise (msg);
451       break;
452     case EXCEPTION_INVALID_DISPOSITION:
453       OSD_Exception_INVALID_DISPOSITION::Raise (msg);
454       break;
455     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
456       OSD_Exception_NONCONTINUABLE_EXCEPTION::Raise (msg);
457       break;
458     case EXCEPTION_PRIV_INSTRUCTION:
459       OSD_Exception_PRIV_INSTRUCTION::Raise (msg);
460       break;
461     case EXCEPTION_STACK_OVERFLOW:
462       OSD_Exception_STACK_OVERFLOW::Raise (msg);
463       break;
464     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
465       Standard_DivideByZero::Raise (msg);
466       break;
467     case EXCEPTION_FLT_STACK_CHECK:
468     case EXCEPTION_FLT_OVERFLOW:
469       Standard_Overflow::Raise (msg);
470       break;
471     case EXCEPTION_FLT_UNDERFLOW:
472       Standard_Underflow::Raise (msg);
473       break;
474     case EXCEPTION_FLT_INVALID_OPERATION:
475     case EXCEPTION_FLT_DENORMAL_OPERAND:
476     case EXCEPTION_FLT_INEXACT_RESULT:
477     case STATUS_FLOAT_MULTIPLE_TRAPS:
478     case STATUS_FLOAT_MULTIPLE_FAULTS:
479       Standard_NumericError::Raise (msg);
480       break;
481     default:
482       break;
483   }  // end switch
484   return EXCEPTION_EXECUTE_HANDLER;
485 }  // end _osd_raise
486
487 //============================================================================
488 //==== _osd_debug
489 //============================================================================
490 LONG _osd_debug ( void ) {
491
492   LONG action ;
493
494   if ( !fDbgLoaded ) {
495
496     HKEY                hKey = NULL;
497     HANDLE              hEvent = INVALID_HANDLE_VALUE;
498     DWORD               dwKeyType;
499     DWORD               dwValueLen;
500     TCHAR               keyValue[ MAX_PATH ];
501     TCHAR               cmdLine[ MAX_PATH ];
502     SECURITY_ATTRIBUTES sa;
503     PROCESS_INFORMATION pi;
504     STARTUPINFO         si;
505
506     __try {
507
508       if (  RegOpenKey (
509               HKEY_LOCAL_MACHINE,
510               TEXT( "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ),
511               &hKey
512             ) != ERROR_SUCCESS
513       ) __leave;
514
515       dwValueLen = sizeof ( keyValue );
516
517       if (  RegQueryValueEx (
518              hKey, TEXT( "Debugger" ), NULL, &dwKeyType, ( unsigned char* )keyValue, &dwValueLen
519             ) != ERROR_SUCCESS
520       ) __leave;
521
522       sa.nLength              = sizeof ( SECURITY_ATTRIBUTES );
523       sa.lpSecurityDescriptor = NULL;
524       sa.bInheritHandle       = TRUE;
525
526       if (   (  hEvent = CreateEvent ( &sa, TRUE, FALSE, NULL )  ) == NULL   ) __leave;
527
528       wsprintf (  cmdLine, keyValue, GetCurrentProcessId (), hEvent  );
529
530       ZeroMemory (  &si, sizeof ( STARTUPINFO )  );
531
532       si.cb      = sizeof ( STARTUPINFO );
533       si.dwFlags = STARTF_FORCEONFEEDBACK;
534
535   //   cout << "_osd_debug -> CreateProcess" << endl ;
536       if (  !CreateProcess (
537               NULL, cmdLine, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE,
538               NULL, NULL, &si, &pi
539              )
540       ) __leave;
541
542   //   cout << "_osd_debug -> WaitForSingleObject " << endl ;
543       WaitForSingleObject ( hEvent, INFINITE );
544   //   cout << "_osd_debug <- WaitForSingleObject -> CloseHandle " << endl ;
545
546       CloseHandle ( pi.hProcess );
547       CloseHandle ( pi.hThread  );
548
549   //   cout << "_osd_debug fDbgLoaded  " << endl ;
550       fDbgLoaded = TRUE;
551
552     }  // end __try
553
554     __finally {
555
556 //   cout << "_osd_debug -> CloseHandle(hKey) " << endl ;
557       if ( hKey   != INVALID_HANDLE_VALUE ) CloseHandle ( hKey   );
558 //   cout << "_osd_debug -> CloseHandle(hEvent) " << endl ;
559       if ( hEvent != INVALID_HANDLE_VALUE ) CloseHandle ( hEvent );
560 //   cout << "_osd_debug end __finally " << endl ;
561
562     }  // end __finally
563
564   }  /* end if */
565
566   action = fDbgLoaded ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
567 // cout << "_osd_debug return " << action << " EXCEPTION_CONTINUE_EXECUTION("
568 //      << EXCEPTION_CONTINUE_EXECUTION << ")" << endl ;
569   return action ;
570
571 }  // end _osd_debug
572 #endif
573
574 #else
575
576 //---------- All Systems except Windows NT : ----------------------------------
577
578 # include <stdio.h>
579
580 #include <OSD_WhoAmI.hxx>
581 #include <OSD_SIGHUP.hxx>
582 #include <OSD_SIGINT.hxx>
583 #include <OSD_SIGQUIT.hxx>
584 #include <OSD_SIGILL.hxx>
585 #include <OSD_SIGKILL.hxx>
586 #include <OSD_SIGBUS.hxx>
587 #include <OSD_SIGSEGV.hxx>
588 #include <OSD_SIGSYS.hxx>
589 #include <Standard_NumericError.hxx>
590
591 #include <Standard_ErrorHandler.hxx>
592
593 // POSIX threads
594 #include <pthread.h>
595
596 #ifdef linux
597 #include <fenv.h>
598 static Standard_Boolean fFltExceptions = Standard_False;
599 #endif
600
601 // variable signalling that Control-C has been pressed (SIGINT signal)
602 static Standard_Boolean fCtrlBrk;
603
604 //const OSD_WhoAmI Iam = OSD_WPackage;
605
606 typedef void (ACT_SIGIO_HANDLER)(void) ;
607 ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
608
609 #ifdef DECOSF1
610 typedef void (* SIG_PFV) (int);
611 #endif
612
613 #ifdef __GNUC__
614 # include <stdlib.h>
615 # include <stdio.h>
616 #else
617 #  ifdef SA_SIGINFO 
618 #    ifndef _AIX
619 #  include <sys/siginfo.h>
620 #     endif
621 #  endif
622 #endif
623 typedef void (* SIG_PFV) (int);
624
625 #include <signal.h>
626
627 #if !defined(__ANDROID__) && !defined(__QNX__)
628   #include <sys/signal.h>
629 #endif
630
631 #if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION)
632 //============================================================================
633 //====  GetOldSigAction
634 //====     get previous 
635 //============================================================================
636
637 static struct sigaction *GetOldSigAction() 
638 {
639   static struct sigaction oldSignals[NSIG];
640   return oldSignals;
641 }
642
643 #ifdef SOLARIS
644 static sigfpe_handler_type *GetOldFPE()
645 {
646   static sigfpe_handler_type aIEEEHandler[5] = { NULL, NULL, NULL, NULL, NULL } ;
647   return aIEEEHandler;
648 }
649 #endif
650 #endif
651
652 //============================================================================
653 //==== Handler
654 //====     Catche the differents signals:
655 //====          1- The Fatal signals, which cause the end of process:
656 //====          2- The exceptions which are "signaled" by Raise.
657 //====     The Fatal Signals:
658 //====        SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGKILL, SIGBUS, SIGSYS
659 //====     The Exceptions:
660 //====        SIGFPE
661 //====         (SUN versions)
662 //====           FPE_INTOVF_TRAP    // ..... integer overflow
663 //====           FPE_INTDIV_TRAP    // ..... integer divide by zero
664 //====           FPE_FLTINEX_TRAP   // ..... [floating inexact result]
665 //====           FPE_FLTDIV_TRAP    // ..... [floating divide by zero]
666 //====           FPE_FLTUND_TRAP    // ..... [floating underflow]
667 //====           FPE_FLTOPER_TRAP   // ..... [floating inexact result]
668 //====           FPE_FLTOVF_TRAP    // ..... [floating overflow]
669 //==== SIGSEGV is handled by "SegvHandler()"
670 //============================================================================
671 #ifdef SA_SIGINFO
672   #if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION)
673 static void Handler (const int theSignal, siginfo_t *theSigInfo, const Standard_Address theContext)
674   #else
675 static void Handler (const int theSignal, siginfo_t */*theSigInfo*/, const Standard_Address /*theContext*/)
676   #endif
677 #else
678 static void Handler (const int theSignal)
679 #endif
680 {
681   struct sigaction oldact, act;
682   // re-install the signal
683   if ( ! sigaction (theSignal, NULL, &oldact) ) {
684     // cout << " signal is " << theSignal << " handler is " <<  oldact.sa_handler << endl;
685     if (sigaction (theSignal, &oldact, &act)) perror ("sigaction");
686   }
687   else {
688     perror ("sigaction");
689   }
690
691 #if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION)
692   if (pthread_self() != getOCCThread()  || !Standard_ErrorHandler::IsInTryBlock()) {
693     // use the previous signal handler
694     // cout << "OSD::Handler: signal " << (int) theSignal << " occured outside a try block " <<  endl ;
695     struct sigaction *oldSignals = GetOldSigAction();
696     struct sigaction  asigacthandler =  oldSignals[theSignal >= 0 && theSignal < NSIG ? theSignal : 0];
697
698     if (asigacthandler.sa_flags & SA_SIGINFO) {
699       void (*aCurInfoHandle)(int, siginfo_t *, void *) = asigacthandler.sa_sigaction;
700
701       siginfo_t * aSigInfo = NULL;
702 #ifdef SA_SIGINFO
703       aSigInfo = theSigInfo;
704 #endif
705
706       if (aSigInfo) {
707         switch (aSigInfo->si_signo) {
708           case SIGFPE:
709           {
710 #ifdef SOLARIS
711             sigfpe_handler_type *aIEEEHandlerTab = GetOldFPE();
712             sigfpe_handler_type  aIEEEHandler = NULL;
713             switch (aSigInfo->si_code) {
714               case FPE_INTDIV_TRAP :
715               case FPE_FLTDIV_TRAP :
716                aIEEEHandler = aIEEEHandlerTab[1];
717                 break;
718               case FPE_INTOVF_TRAP :
719               case FPE_FLTOVF_TRAP :
720                 aIEEEHandler = aIEEEHandlerTab[2];
721                 break;
722               case FPE_FLTUND_TRAP :
723                 aIEEEHandler = aIEEEHandlerTab[4];
724                 break;
725               case FPE_FLTRES_TRAP :
726                 aIEEEHandler = aIEEEHandlerTab[3];
727                 break;
728               case FPE_FLTINV_TRAP :
729                 aIEEEHandler = aIEEEHandlerTab[0];
730                 break;
731               case FPE_FLTSUB_TRAP :
732               default:
733                 break;
734             }
735             if (aIEEEHandler) {
736               // cout << "OSD::Handler: calling previous IEEE signal handler with info" <<  endl ;
737               (*aIEEEHandler) (theSignal, aSigInfo, theContext);
738               return;
739             }
740 #endif
741             break;
742           }
743           default:
744             break;
745         }
746       }
747       if (aCurInfoHandle) {
748         // cout << "OSD::Handler: calling previous signal handler with info " << aCurInfoHandle <<  endl ;
749         (*aCurInfoHandle) (theSignal, aSigInfo, theContext);
750 #ifdef OCCT_DEBUG
751         cerr << " previous signal handler return" <<  endl ;
752 #endif
753         return;
754       }
755       else {
756         // cout << "OSD::Handler: no handler with info for the signal" << endl;
757       }
758     }
759     else {
760       // no siginfo needed for the signal
761       void (*aCurHandler) (int) = asigacthandler.sa_handler;
762       if(aCurHandler) {
763         // cout << "OSD::Handler: calling previous signal handler" <<  endl ;
764         (*aCurHandler) (theSignal);
765 #ifdef OCCT_DEBUG
766         cerr << " previous signal handler return" <<  endl ;
767 #endif
768         return;
769       }
770     }
771     // cout << " Signal occured outside a try block, but no handler for it" <<endl;
772     return;
773   }
774 #endif
775
776   // cout << "OSD::Handler: signal " << (int) theSignal << " occured inside a try block " <<  endl ;
777   if ( ADR_ACT_SIGIO_HANDLER != NULL )
778     (*ADR_ACT_SIGIO_HANDLER)() ;
779 #ifdef linux
780   if (fFltExceptions)
781     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
782     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
783 #endif
784   sigset_t set;
785   sigemptyset(&set);
786   switch (theSignal) {
787   case SIGHUP:
788     OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
789     exit(SIGHUP);
790     break;
791   case SIGINT:
792     // For safe handling of Control-C as stop event, arm a variable but do not
793     // generate longjump (we are out of context anyway)
794     fCtrlBrk = Standard_True;
795     // OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
796     // exit(SIGINT);
797     break;
798   case SIGQUIT:
799     OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
800     exit(SIGQUIT);
801     break;
802   case SIGILL:
803     OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
804     exit(SIGILL);
805     break;
806   case SIGKILL:
807     OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
808     exit(SIGKILL);
809     break;
810   case SIGBUS:
811     sigaddset(&set, SIGBUS);
812     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
813     OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
814     exit(SIGBUS);
815     break;
816   case SIGSEGV:
817     OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
818     exit(SIGSEGV);
819     break;
820 #ifdef SIGSYS
821   case SIGSYS:
822     OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
823     exit(SIGSYS);
824     break;
825 #endif
826   case SIGFPE:
827     sigaddset(&set, SIGFPE);
828     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
829 #ifdef DECOSF1
830     // Pour DEC/OSF1 SIGFPE = Division par zero.
831     Standard_DivideByZero::NewInstance('')->Jump;
832     break;
833 #endif
834 #if (!defined (__sun)) && (!defined(SOLARIS))
835     Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
836     break;
837 #else
838     // Reste SOLARIS
839     if (aSigInfo) {
840       switch(aSigInfo->si_code) {
841       case FPE_FLTDIV_TRAP :
842         Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
843         break;
844       case FPE_INTDIV_TRAP :
845         Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
846         break;
847       case FPE_FLTOVF_TRAP :
848         Standard_Overflow::NewInstance("Floating Overflow")->Jump();
849         break;
850       case FPE_INTOVF_TRAP :
851         Standard_Overflow::NewInstance("Integer Overflow")->Jump();
852         break;
853       case FPE_FLTUND_TRAP :
854         Standard_NumericError::NewInstance("Floating Underflow")->Jump();
855         break;
856       case FPE_FLTRES_TRAP:
857         Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
858         break;
859       case FPE_FLTINV_TRAP :
860         Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
861         break;
862       default:
863         Standard_NumericError::NewInstance("Numeric Error")->Jump();
864         break;
865       }
866     } else {
867       Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
868     }
869 #endif
870     break;
871 #if defined (__sgi) || defined(IRIX)
872   case SIGTRAP:
873     sigaddset(&set, SIGTRAP);
874     sigprocmask(SIG_UNBLOCK, &set, NULL) ;
875     Standard_DivideByZero::NewInstance("SIGTRAP IntegerDivideByZero")->Jump(); break;
876 #endif
877   default:
878 #ifdef OCCT_DEBUG
879     cout << "Unexpected signal " << theSignal << endl ;
880 #endif
881     break;
882   }
883 }
884
885 //============================================================================
886 //==== SegvHandler
887 //============================================================================
888 #ifdef SA_SIGINFO
889
890 static void SegvHandler(const int theSignal,
891                         siginfo_t *ip,
892                         const Standard_Address theContext)
893 {
894 #ifdef NO_CXX_EXCEPTION
895   if (!Standard_ErrorHandler::IsInTryBlock()) {
896     Handler(theSignal, ip, theContext);
897     return;
898   }
899 #else
900   (void)theSignal; // silence GCC warnings
901   (void)theContext;
902 #endif
903 #ifdef linux
904   if (fFltExceptions)
905     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
906     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
907 #endif
908 //  cout << "OSD::SegvHandler activated(SA_SIGINFO)" << endl ;
909   if ( ip != NULL ) {
910      sigset_t set;
911      sigemptyset(&set);
912      sigaddset(&set, SIGSEGV);
913      sigprocmask (SIG_UNBLOCK, &set, NULL) ;
914      void *address = ip->si_addr ;
915      {
916        char Msg[100];
917        sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",
918          (long ) address ) ;
919        OSD_SIGSEGV::NewInstance(Msg)->Jump();
920      }
921   }
922 #ifdef OCCT_DEBUG
923   else {
924     cout << "Wrong undefined address." << endl ;
925   }
926 #endif
927   exit(SIGSEGV);
928 }
929
930 #elif defined (_hpux) || defined(HPUX)
931 // Not ACTIVE ? SA_SIGINFO is defined on SUN, OSF, SGI and HP (and Linux) !
932 // pour version 09.07
933
934 static void SegvHandler(const int theSignal,
935                         siginfo_t *ip,
936                         const Standard_Address theContext)
937 {
938   unsigned long Space  ;
939   unsigned long Offset ;
940   char Msg[100] ;
941
942   if ( theContext != NULL ) {
943     Space = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20 ;
944     Offset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21 ;
945 //    cout << "Wrong address = " << hex(Offset) << endl ;
946     {
947       sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",Offset) ;
948       OSD_SIGSEGV::Jump(Msg);
949 //    scp->sc_pcoq_head = scp->sc_pcoq_tail ;       Permettrait de continuer a
950 //    scp->sc_pcoq_tail = scp->sc_pcoq_tail + 0x4 ; l'intruction suivant le segv.
951     }
952   }
953 #ifdef OCCT_DEBUG
954   else {
955     cout << "Wrong undefined address." << endl ;
956   }
957 #endif
958   exit(SIGSEGV);
959 }
960
961 #endif
962
963 //============================================================================
964 //==== SetSignal 
965 //====     Set the differents signals:
966 //============================================================================
967
968 void OSD::SetSignal(const Standard_Boolean aFloatingSignal) 
969 {
970   static int first_time = 3 ;
971   struct sigaction act, oact;
972   int              stat = 0;
973
974   if( aFloatingSignal ) {
975     //==== Enable the floating point exceptions ===============
976 #if defined (__sun) || defined (SOLARIS)
977     sigfpe_handler_type PHandler = (sigfpe_handler_type) Handler ;
978     stat = ieee_handler("set", "invalid",  PHandler);
979     stat = ieee_handler("set", "division", PHandler) || stat;
980     stat = ieee_handler("set", "overflow", PHandler) || stat;
981
982     //stat = ieee_handler("set", "underflow", PHandler) || stat;
983     //stat = ieee_handler("set", "inexact", PHandler) || stat;
984
985     if (stat) {
986 #ifdef OCCT_DEBUG
987       cerr << "ieee_handler does not work !!! KO " << endl;
988 #endif
989     }
990 #elif defined (linux)
991     feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
992     //feenableexcept (FE_INVALID | FE_DIVBYZERO);
993     fFltExceptions = Standard_True;
994 #endif
995   }
996   else if ( first_time & 1 ) {
997 //    cout << "SetSignal( Standard_False ) is not implemented..." << endl ;
998     first_time = first_time & (~ 1) ;
999   }
1000
1001 #if defined (sgi) || defined (IRIX )
1002  if ( first_time & 2 ) {
1003    char *TRAP_FPE = getenv("TRAP_FPE") ;
1004    if ( TRAP_FPE == NULL ) {
1005 #ifdef OCCT_DEBUG
1006      cout << "On SGI you must set TRAP_FPE environment variable : " << endl ;
1007      cout << "set env(TRAP_FPE) \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\" or" << endl ;
1008      cout << "setenv TRAP_FPE \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\"" << endl ;
1009 #endif
1010 //     exit(1) ;
1011      first_time = first_time & (~ 2) ;
1012    }
1013  }
1014 #endif
1015
1016   //==== Save the old Signal Handler, and set the new one ===================
1017
1018   sigemptyset(&act.sa_mask) ;
1019
1020 #ifdef SA_RESTART
1021   act.sa_flags   = SA_RESTART ;
1022 #else
1023   act.sa_flags   = 0 ;
1024 #endif
1025 #ifdef SA_SIGINFO
1026   act.sa_flags = act.sa_flags | SA_SIGINFO ;
1027   act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ Handler;
1028 #else
1029   act.sa_handler = /*(SIG_PFV)*/ Handler;
1030 #endif
1031
1032   //==== Always detected the signal "SIGFPE" =================================
1033   stat = sigaction(SIGFPE,&act,&oact);   // ...... floating point exception 
1034   if (stat) {
1035 #ifdef OCCT_DEBUG
1036      cerr << "sigaction does not work !!! KO " << endl;
1037 #endif
1038      perror("sigaction ");
1039   }
1040
1041   //==== Detected the only the "free" signals ================================
1042   sigaction(SIGHUP,&act,&oact);    // ...... hangup  
1043
1044 #ifdef OBJS
1045   if(oact.sa_handler) 
1046         sigaction(SIGHUP,&oact,&oact);
1047 #endif
1048
1049   sigaction(SIGINT,&act,&oact);   // ...... interrupt   
1050
1051 #ifdef OBJS
1052   if(oact.sa_handler) 
1053         sigaction(SIGINT,&oact,&oact);
1054 #endif
1055             
1056   sigaction(SIGQUIT,&act,&oact);  // ...... quit
1057
1058 #ifdef OBJS
1059   if(oact.sa_handler) 
1060         sigaction(SIGQUIT,&oact,&oact);
1061 #endif
1062
1063   sigaction(SIGILL,&act,&oact);   // ...... illegal instruction 
1064
1065 #ifdef OBJS
1066   if(oact.sa_handler) 
1067         sigaction(SIGILL,&oact,&oact);
1068 #endif
1069
1070   sigaction(SIGBUS,&act,&oact);   // ...... bus error 
1071
1072 #ifdef OBJS
1073   if(oact.sa_handler) 
1074         sigaction(SIGBUS,&oact,&oact);
1075 #endif
1076
1077 #if (!defined (linux)) && (!defined(__linux__))
1078   sigaction(SIGSYS,&act,&oact);   // ...... bad argument to system call
1079
1080 # ifdef OBJS
1081   if(oact.sa_handler) 
1082         sigaction(SIGSYS,&oact,&oact);
1083 # endif
1084 #endif
1085
1086 #if defined (__sgi) || defined(IRIX)
1087   sigaction(SIGTRAP,&act,&oact);   // Integer Divide By Zero (IRIX)
1088
1089 # ifdef OBJS
1090   if(oact.sa_handler) 
1091         sigaction(SIGTRAP,&oact,&oact);
1092 # endif
1093 #endif
1094
1095 #ifdef SA_SIGINFO
1096   act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
1097 #else
1098   act.sa_handler = /*(SIG_PFV)*/ SegvHandler;
1099 #endif
1100
1101   if ( sigaction( SIGSEGV , &act , &oact ) )  // ...... segmentation violation
1102     perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
1103
1104 #ifdef OBJS
1105   if(oact.sa_handler) 
1106         sigaction(SIGSEGV,&oact,&oact);
1107 #endif
1108 #if defined(__osf__) || defined(DECOSF1)
1109    struct sigaction action, prev_action;
1110    action.sa_handler = SIG_IGN;
1111    action.sa_mask = 0;
1112    action.sa_flags = 0;
1113    
1114    if (sigaction (SIGFPE, &action, &prev_action) == -1) {
1115      perror ("sigaction");
1116      exit (1);
1117    }
1118 #endif
1119
1120 }
1121
1122 //============================================================================
1123 //==== ControlBreak 
1124 //============================================================================
1125
1126 void OSD :: ControlBreak () 
1127 {
1128   if ( fCtrlBrk ) {
1129     fCtrlBrk = Standard_False;
1130     OSD_Exception_CTRL_BREAK::Raise ("*** INTERRUPT ***");
1131   }
1132 }
1133
1134 #endif