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