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