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