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