0024023: Revamp the OCCT Handle -- ambiguity
[occt.git] / src / OSD / OSD_signal.cxx
CommitLineData
973c2be1 1// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 2//
973c2be1 3// This file is part of Open CASCADE Technology software library.
b311480e 4//
d5f74e42 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
973c2be1 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.
b311480e 10//
973c2be1 11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
7fd59977 13
14#include <OSD.ixx>
15
9bf6baed 16#ifndef _WIN32
7fd59977 17
18//---------- All Systems except Windows NT : ----------------------------------
19
7fd59977 20# include <stdio.h>
21
22#include <OSD_WhoAmI.hxx>
23#include <OSD_SIGHUP.hxx>
24#include <OSD_SIGINT.hxx>
25#include <OSD_SIGQUIT.hxx>
26#include <OSD_SIGILL.hxx>
27#include <OSD_SIGKILL.hxx>
28#include <OSD_SIGBUS.hxx>
29#include <OSD_SIGSEGV.hxx>
30#include <OSD_SIGSYS.hxx>
8a262fa1 31#include <OSD_Exception_CTRL_BREAK.hxx>
7fd59977 32#include <Standard_NumericError.hxx>
7fd59977 33#include <Standard_DivideByZero.hxx>
34#include <Standard_Overflow.hxx>
35
36#include <Standard_ErrorHandler.hxx>
37
38// POSIX threads
03155c18 39#include <pthread.h>
7fd59977 40
41#ifdef linux
42#include <fenv.h>
7fd59977 43static Standard_Boolean fFltExceptions = Standard_False;
44#endif
45
8a262fa1 46// variable signalling that Control-C has been pressed (SIGINT signal)
47static Standard_Boolean fCtrlBrk;
48
7fd59977 49//const OSD_WhoAmI Iam = OSD_WPackage;
50
51typedef void (ACT_SIGIO_HANDLER)(void) ;
52ACT_SIGIO_HANDLER *ADR_ACT_SIGIO_HANDLER = NULL ;
53
7fd59977 54#ifdef DECOSF1
55typedef void (* SIG_PFV) (int);
56#endif
57
7fd59977 58#ifdef __GNUC__
59# include <stdlib.h>
60# include <stdio.h>
61#else
62# ifdef SA_SIGINFO
63# ifndef _AIX
64# include <sys/siginfo.h>
65# endif
66# endif
67#endif
68typedef void (* SIG_PFV) (int);
69
03155c18 70#include <signal.h>
7fd59977 71
9bf6baed 72#if !defined(__ANDROID__)
73 #include <sys/signal.h>
74#endif
75
76#if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION)
7fd59977 77//============================================================================
78//==== GetOldSigAction
79//==== get previous
80//============================================================================
81
82static struct sigaction *GetOldSigAction()
83{
84 static struct sigaction oldSignals[NSIG];
85 return oldSignals;
86}
87
88#ifdef SOLARIS
89static sigfpe_handler_type *GetOldFPE()
90{
91 static sigfpe_handler_type aIEEEHandler[5] = { NULL, NULL, NULL, NULL, NULL } ;
92 return aIEEEHandler;
93}
94#endif
95#endif
96
7fd59977 97//============================================================================
89c4bca8 98//==== Handler
7fd59977 99//==== Catche the differents signals:
100//==== 1- The Fatal signals, which cause the end of process:
101//==== 2- The exceptions which are "signaled" by Raise.
102//==== The Fatal Signals:
103//==== SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGKILL, SIGBUS, SIGSYS
104//==== The Exceptions:
105//==== SIGFPE
106//==== (SUN versions)
107//==== FPE_INTOVF_TRAP // ..... integer overflow
108//==== FPE_INTDIV_TRAP // ..... integer divide by zero
109//==== FPE_FLTINEX_TRAP // ..... [floating inexact result]
110//==== FPE_FLTDIV_TRAP // ..... [floating divide by zero]
111//==== FPE_FLTUND_TRAP // ..... [floating underflow]
112//==== FPE_FLTOPER_TRAP // ..... [floating inexact result]
113//==== FPE_FLTOVF_TRAP // ..... [floating overflow]
114//==== SIGSEGV is handled by "SegvHandler()"
115//============================================================================
7fd59977 116#ifdef SA_SIGINFO
89c4bca8 117static void Handler (const int theSignal, siginfo_t *theSigInfo, const Standard_Address theContext)
118#else
119static void Handler (const int theSignal)
7fd59977 120#endif
7fd59977 121{
122 struct sigaction oldact, act;
7fd59977 123 // re-install the signal
7fd59977 124 if ( ! sigaction (theSignal, NULL, &oldact) ) {
89c4bca8 125 // cout << " signal is " << theSignal << " handler is " << oldact.sa_handler << endl;
126 if (sigaction (theSignal, &oldact, &act)) perror ("sigaction");
127 }
128 else {
129 perror ("sigaction");
7fd59977 130 }
7fd59977 131
89c4bca8 132#if defined(HAVE_PTHREAD_H) && defined(NO_CXX_EXCEPTION)
7fd59977 133 if (pthread_self() != getOCCThread() || !Standard_ErrorHandler::IsInTryBlock()) {
134 // use the previous signal handler
89c4bca8 135 // cout << "OSD::Handler: signal " << (int) theSignal << " occured outside a try block " << endl ;
7fd59977 136 struct sigaction *oldSignals = GetOldSigAction();
89c4bca8 137 struct sigaction asigacthandler = oldSignals[theSignal >= 0 && theSignal < NSIG ? theSignal : 0];
138
7fd59977 139 if (asigacthandler.sa_flags & SA_SIGINFO) {
140 void (*aCurInfoHandle)(int, siginfo_t *, void *) = asigacthandler.sa_sigaction;
7d679df3 141
142 siginfo_t * aSigInfo = NULL;
143#ifdef SA_SIGINFO
144 aSigInfo = theSigInfo;
145#endif
146
7fd59977 147 if (aSigInfo) {
89c4bca8 148 switch (aSigInfo->si_signo) {
149 case SIGFPE:
150 {
7fd59977 151#ifdef SOLARIS
89c4bca8 152 sigfpe_handler_type *aIEEEHandlerTab = GetOldFPE();
153 sigfpe_handler_type aIEEEHandler = NULL;
154 switch (aSigInfo->si_code) {
155 case FPE_INTDIV_TRAP :
156 case FPE_FLTDIV_TRAP :
157 aIEEEHandler = aIEEEHandlerTab[1];
158 break;
159 case FPE_INTOVF_TRAP :
160 case FPE_FLTOVF_TRAP :
161 aIEEEHandler = aIEEEHandlerTab[2];
162 break;
163 case FPE_FLTUND_TRAP :
164 aIEEEHandler = aIEEEHandlerTab[4];
165 break;
166 case FPE_FLTRES_TRAP :
167 aIEEEHandler = aIEEEHandlerTab[3];
168 break;
169 case FPE_FLTINV_TRAP :
170 aIEEEHandler = aIEEEHandlerTab[0];
171 break;
172 case FPE_FLTSUB_TRAP :
173 default:
174 break;
175 }
176 if (aIEEEHandler) {
177 // cout << "OSD::Handler: calling previous IEEE signal handler with info" << endl ;
178 (*aIEEEHandler) (theSignal, aSigInfo, theContext);
179 return;
180 }
181#endif
182 break;
183 }
184 default:
185 break;
186 }
7fd59977 187 }
188 if (aCurInfoHandle) {
89c4bca8 189 // cout << "OSD::Handler: calling previous signal handler with info " << aCurInfoHandle << endl ;
190 (*aCurInfoHandle) (theSignal, aSigInfo, theContext);
0797d9d3 191#ifdef OCCT_DEBUG
89c4bca8 192 cerr << " previous signal handler return" << endl ;
63c629aa 193#endif
89c4bca8 194 return;
7fd59977 195 }
196 else {
197 // cout << "OSD::Handler: no handler with info for the signal" << endl;
198 }
89c4bca8 199 }
200 else {
201 // no siginfo needed for the signal
7fd59977 202 void (*aCurHandler) (int) = asigacthandler.sa_handler;
203 if(aCurHandler) {
89c4bca8 204 // cout << "OSD::Handler: calling previous signal handler" << endl ;
205 (*aCurHandler) (theSignal);
0797d9d3 206#ifdef OCCT_DEBUG
89c4bca8 207 cerr << " previous signal handler return" << endl ;
63c629aa 208#endif
89c4bca8 209 return;
210 }
7fd59977 211 }
212 // cout << " Signal occured outside a try block, but no handler for it" <<endl;
213 return;
214 }
215#endif
216
7fd59977 217 // cout << "OSD::Handler: signal " << (int) theSignal << " occured inside a try block " << endl ;
89c4bca8 218 if ( ADR_ACT_SIGIO_HANDLER != NULL )
219 (*ADR_ACT_SIGIO_HANDLER)() ;
7fd59977 220#ifdef linux
221 if (fFltExceptions)
222 feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
223 //feenableexcept (FE_INVALID | FE_DIVBYZERO);
224#endif
7fd59977 225 sigset_t set;
226 sigemptyset(&set);
89c4bca8 227 switch (theSignal) {
7fd59977 228 case SIGHUP:
229 OSD_SIGHUP::NewInstance("SIGHUP 'hangup' detected.")->Jump();
230 exit(SIGHUP);
231 break;
7fd59977 232 case SIGINT:
8a262fa1 233 // For safe handling of Control-C as stop event, arm a variable but do not
234 // generate longjump (we are out of context anyway)
235 fCtrlBrk = Standard_True;
89c4bca8 236 // OSD_SIGINT::NewInstance("SIGINT 'interrupt' detected.")->Jump();
237 // exit(SIGINT);
7fd59977 238 break;
7fd59977 239 case SIGQUIT:
240 OSD_SIGQUIT::NewInstance("SIGQUIT 'quit' detected.")->Jump();
241 exit(SIGQUIT);
242 break;
7fd59977 243 case SIGILL:
244 OSD_SIGILL::NewInstance("SIGILL 'illegal instruction' detected.")->Jump();
245 exit(SIGILL);
246 break;
7fd59977 247 case SIGKILL:
248 OSD_SIGKILL::NewInstance("SIGKILL 'kill' detected.")->Jump();
249 exit(SIGKILL);
250 break;
7fd59977 251 case SIGBUS:
252 sigaddset(&set, SIGBUS);
253 sigprocmask(SIG_UNBLOCK, &set, NULL) ;
254 OSD_SIGBUS::NewInstance("SIGBUS 'bus error' detected.")->Jump();
255 exit(SIGBUS);
256 break;
7fd59977 257 case SIGSEGV:
258 OSD_SIGSEGV::NewInstance("SIGSEGV 'segmentation violation' detected.")->Jump();
259 exit(SIGSEGV);
260 break;
7fd59977 261#ifdef SIGSYS
262 case SIGSYS:
263 OSD_SIGSYS::NewInstance("SIGSYS 'bad argument to system call' detected.")->Jump();
264 exit(SIGSYS);
265 break;
266#endif
89c4bca8 267 case SIGFPE:
7fd59977 268 sigaddset(&set, SIGFPE);
269 sigprocmask(SIG_UNBLOCK, &set, NULL) ;
270#ifdef DECOSF1
89c4bca8 271 // Pour DEC/OSF1 SIGFPE = Division par zero.
7fd59977 272 Standard_DivideByZero::NewInstance('')->Jump;
7fd59977 273 break;
89c4bca8 274#endif
7fd59977 275#if (!defined (__sun)) && (!defined(SOLARIS))
276 Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
277 break;
278#else
279 // Reste SOLARIS
89c4bca8 280 if (aSigInfo) {
7fd59977 281 switch(aSigInfo->si_code) {
282 case FPE_FLTDIV_TRAP :
89c4bca8 283 Standard_DivideByZero::NewInstance("Floating Divide By Zero")->Jump();
284 break;
7fd59977 285 case FPE_INTDIV_TRAP :
89c4bca8 286 Standard_DivideByZero::NewInstance("Integer Divide By Zero")->Jump();
287 break;
7fd59977 288 case FPE_FLTOVF_TRAP :
89c4bca8 289 Standard_Overflow::NewInstance("Floating Overflow")->Jump();
290 break;
7fd59977 291 case FPE_INTOVF_TRAP :
89c4bca8 292 Standard_Overflow::NewInstance("Integer Overflow")->Jump();
293 break;
7fd59977 294 case FPE_FLTUND_TRAP :
89c4bca8 295 Standard_NumericError::NewInstance("Floating Underflow")->Jump();
296 break;
7fd59977 297 case FPE_FLTRES_TRAP:
89c4bca8 298 Standard_NumericError::NewInstance("Floating Point Inexact Result")->Jump();
299 break;
7fd59977 300 case FPE_FLTINV_TRAP :
89c4bca8 301 Standard_NumericError::NewInstance("Invalid Floating Point Operation")->Jump();
302 break;
7fd59977 303 default:
89c4bca8 304 Standard_NumericError::NewInstance("Numeric Error")->Jump();
305 break;
7fd59977 306 }
89c4bca8 307 } else {
7fd59977 308 Standard_NumericError::NewInstance("SIGFPE Arithmetic exception detected")->Jump();
309 }
310#endif
311 break;
7fd59977 312#if defined (__sgi) || defined(IRIX)
89c4bca8 313 case SIGTRAP:
7fd59977 314 sigaddset(&set, SIGTRAP);
315 sigprocmask(SIG_UNBLOCK, &set, NULL) ;
316 Standard_DivideByZero::NewInstance("SIGTRAP IntegerDivideByZero")->Jump(); break;
317#endif
318 default:
0797d9d3 319#ifdef OCCT_DEBUG
89c4bca8 320 cout << "Unexpected signal " << theSignal << endl ;
63c629aa 321#endif
89c4bca8 322 break;
8a262fa1 323 }
324}
325
7fd59977 326//============================================================================
89c4bca8 327//==== SegvHandler
7fd59977 328//============================================================================
7fd59977 329#ifdef SA_SIGINFO
330
89c4bca8 331static void SegvHandler(const int theSignal,
332 siginfo_t *ip,
333 const Standard_Address theContext)
7fd59977 334{
89c4bca8 335#ifdef NO_CXX_EXCEPTION
7fd59977 336 if (!Standard_ErrorHandler::IsInTryBlock()) {
89c4bca8 337 Handler(theSignal, ip, theContext);
7fd59977 338 return;
339 }
7fd59977 340#endif
7fd59977 341#ifdef linux
342 if (fFltExceptions)
343 feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
344 //feenableexcept (FE_INVALID | FE_DIVBYZERO);
345#endif
7fd59977 346// cout << "OSD::SegvHandler activated(SA_SIGINFO)" << endl ;
347 if ( ip != NULL ) {
348 sigset_t set;
349 sigemptyset(&set);
350 sigaddset(&set, SIGSEGV);
351 sigprocmask (SIG_UNBLOCK, &set, NULL) ;
89c4bca8 352 void *address = ip->si_addr ;
4d9421a9 353 {
7fd59977 354 char Msg[100];
355 sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",
89c4bca8 356 (long ) address ) ;
7fd59977 357 OSD_SIGSEGV::NewInstance(Msg)->Jump();
358 }
89c4bca8 359 }
0797d9d3 360#ifdef OCCT_DEBUG
89c4bca8 361 else {
7fd59977 362 cout << "Wrong undefined address." << endl ;
89c4bca8 363 }
63c629aa 364#endif
7fd59977 365 exit(SIGSEGV);
366}
367
89c4bca8 368#elif defined (_hpux) || defined(HPUX)
7fd59977 369// Not ACTIVE ? SA_SIGINFO is defined on SUN, OSF, SGI and HP (and Linux) !
370// pour version 09.07
89c4bca8 371
372static void SegvHandler(const int theSignal,
373 siginfo_t *ip,
374 const Standard_Address theContext)
7fd59977 375{
376 unsigned long Space ;
377 unsigned long Offset ;
378 char Msg[100] ;
379
89c4bca8 380 if ( theContext != NULL ) {
381 Space = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr20 ;
382 Offset = ((struct sigcontext *)theContext)->sc_sl.sl_ss.ss_cr21 ;
7fd59977 383// cout << "Wrong address = " << hex(Offset) << endl ;
4d9421a9 384 {
89c4bca8 385 sprintf(Msg,"SIGSEGV 'segmentation violation' detected. Address %lx",Offset) ;
386 OSD_SIGSEGV::Jump(Msg);
7fd59977 387// scp->sc_pcoq_head = scp->sc_pcoq_tail ; Permettrait de continuer a
388// scp->sc_pcoq_tail = scp->sc_pcoq_tail + 0x4 ; l'intruction suivant le segv.
389 }
390 }
0797d9d3 391#ifdef OCCT_DEBUG
89c4bca8 392 else {
7fd59977 393 cout << "Wrong undefined address." << endl ;
89c4bca8 394 }
63c629aa 395#endif
7fd59977 396 exit(SIGSEGV);
89c4bca8 397}
398
399#endif
400
401//============================================================================
402//==== SetSignal
403//==== Set the differents signals:
404//============================================================================
405
406void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
407{
408 static int first_time = 3 ;
409 struct sigaction act, oact;
410 int stat = 0;
411
412 if( aFloatingSignal ) {
413 //==== Enable the floating point exceptions ===============
414#if defined (__sun) || defined (SOLARIS)
415 sigfpe_handler_type PHandler = (sigfpe_handler_type) Handler ;
416 stat = ieee_handler("set", "invalid", PHandler);
417 stat = ieee_handler("set", "division", PHandler) || stat;
418 stat = ieee_handler("set", "overflow", PHandler) || stat;
419
420 //stat = ieee_handler("set", "underflow", PHandler) || stat;
421 //stat = ieee_handler("set", "inexact", PHandler) || stat;
422
423 if (stat) {
0797d9d3 424#ifdef OCCT_DEBUG
89c4bca8 425 cerr << "ieee_handler does not work !!! KO " << endl;
63c629aa 426#endif
89c4bca8 427 }
428#elif defined (linux)
429 feenableexcept (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
430 //feenableexcept (FE_INVALID | FE_DIVBYZERO);
431 fFltExceptions = Standard_True;
432#endif
433 }
434 else if ( first_time & 1 ) {
435// cout << "SetSignal( Standard_False ) is not implemented..." << endl ;
436 first_time = first_time & (~ 1) ;
437 }
438
439#if defined (sgi) || defined (IRIX )
440 if ( first_time & 2 ) {
441 char *TRAP_FPE = getenv("TRAP_FPE") ;
442 if ( TRAP_FPE == NULL ) {
0797d9d3 443#ifdef OCCT_DEBUG
89c4bca8 444 cout << "On SGI you must set TRAP_FPE environment variable : " << endl ;
445 cout << "set env(TRAP_FPE) \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\" or" << endl ;
446 cout << "setenv TRAP_FPE \"UNDERFL=FLUSH_ZERO;OVERFL=DEFAULT;DIVZERO=DEFAULT;INT_OVERFL=DEFAULT\"" << endl ;
63c629aa 447#endif
89c4bca8 448// exit(1) ;
449 first_time = first_time & (~ 2) ;
450 }
451 }
452#endif
453
454 //==== Save the old Signal Handler, and set the new one ===================
455
456 sigemptyset(&act.sa_mask) ;
457
458#ifdef SA_RESTART
459 act.sa_flags = SA_RESTART ;
460#else
461 act.sa_flags = 0 ;
462#endif
463#ifdef SA_SIGINFO
464 act.sa_flags = act.sa_flags | SA_SIGINFO ;
465 act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ Handler;
466#else
467 act.sa_handler = /*(SIG_PFV)*/ Handler;
468#endif
7fd59977 469
89c4bca8 470 //==== Always detected the signal "SIGFPE" =================================
471 stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
472 if (stat) {
0797d9d3 473#ifdef OCCT_DEBUG
89c4bca8 474 cerr << "sigaction does not work !!! KO " << endl;
63c629aa 475#endif
89c4bca8 476 perror("sigaction ");
477 }
478
479 //==== Detected the only the "free" signals ================================
480 sigaction(SIGHUP,&act,&oact); // ...... hangup
481
482#ifdef OBJS
483 if(oact.sa_handler)
484 sigaction(SIGHUP,&oact,&oact);
485#endif
486
487 sigaction(SIGINT,&act,&oact); // ...... interrupt
488
489#ifdef OBJS
490 if(oact.sa_handler)
491 sigaction(SIGINT,&oact,&oact);
7fd59977 492#endif
89c4bca8 493
494 sigaction(SIGQUIT,&act,&oact); // ...... quit
495
496#ifdef OBJS
497 if(oact.sa_handler)
498 sigaction(SIGQUIT,&oact,&oact);
499#endif
500
501 sigaction(SIGILL,&act,&oact); // ...... illegal instruction
502
503#ifdef OBJS
504 if(oact.sa_handler)
505 sigaction(SIGILL,&oact,&oact);
506#endif
507
508 sigaction(SIGBUS,&act,&oact); // ...... bus error
509
510#ifdef OBJS
511 if(oact.sa_handler)
512 sigaction(SIGBUS,&oact,&oact);
513#endif
514
515#if (!defined (linux)) && (!defined(LININTEL))
516 sigaction(SIGSYS,&act,&oact); // ...... bad argument to system call
517
518# ifdef OBJS
519 if(oact.sa_handler)
520 sigaction(SIGSYS,&oact,&oact);
521# endif
522#endif
523
524#if defined (__sgi) || defined(IRIX)
525 sigaction(SIGTRAP,&act,&oact); // Integer Divide By Zero (IRIX)
526
527# ifdef OBJS
528 if(oact.sa_handler)
529 sigaction(SIGTRAP,&oact,&oact);
530# endif
531#endif
532
533#ifdef SA_SIGINFO
534 act.sa_sigaction = /*(void(*)(int, siginfo_t *, void*))*/ SegvHandler;
7fd59977 535#else
89c4bca8 536 act.sa_handler = /*(SIG_PFV)*/ SegvHandler;
537#endif
7fd59977 538
89c4bca8 539 if ( sigaction( SIGSEGV , &act , &oact ) ) // ...... segmentation violation
540 perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
7fd59977 541
89c4bca8 542#ifdef OBJS
543 if(oact.sa_handler)
544 sigaction(SIGSEGV,&oact,&oact);
545#endif
546#if defined(__osf__) || defined(DECOSF1)
547 struct sigaction action, prev_action;
548 action.sa_handler = SIG_IGN;
549 action.sa_mask = 0;
550 action.sa_flags = 0;
551
552 if (sigaction (SIGFPE, &action, &prev_action) == -1) {
553 perror ("sigaction");
554 exit (1);
555 }
7fd59977 556#endif
89c4bca8 557
558}
559
560//============================================================================
561//==== ControlBreak
562//============================================================================
563
564void OSD :: ControlBreak ()
565{
566 if ( fCtrlBrk ) {
567 fCtrlBrk = Standard_False;
568 OSD_Exception_CTRL_BREAK::Raise ("*** INTERRUPT ***");
569 }
570}
571
7fd59977 572#endif