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