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