source: git/Singular/cntrlc.cc @ bc0078

spielwiese
Last change on this file since bc0078 was 9803fb, checked in by Hans Schoenemann <hannes@…>, 13 years ago
crash handling in childs git-svn-id: file:///usr/local/Singular/svn/trunk@13942 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 14.9 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT - interupt handling
7*/
8
9/* includes */
10#ifdef DecAlpha_OSF1
11#define _XOPEN_SOURCE_EXTENDED
12#endif /* MP3-Y2 0.022UF */
13#include <stdio.h>
14#include <stddef.h>
15#include <stdlib.h>
16#include <strings.h>
17#include <signal.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20#include <kernel/mod2.h>
21#include <omalloc/omalloc.h>
22#include <Singular/tok.h>
23#include <Singular/ipshell.h>
24#include <kernel/febase.h>
25#include <Singular/cntrlc.h>
26#include <kernel/polys.h>
27#include <Singular/feOpt.h>
28#include <Singular/version.h>
29#include <Singular/silink.h>
30
31/* undef, if you don't want GDB to come up on error */
32
33#if !defined(__alpha)
34#define CALL_GDB
35#endif
36
37#if defined(__OPTIMIZE__) && defined(CALL_GDB)
38#undef CALL_GDB
39#endif
40
41#if defined(unix) && !defined(hpux)
42 #include <unistd.h>
43 #include <sys/types.h>
44
45 #ifdef TIME_WITH_SYS_TIME
46   #include <time.h>
47   #ifdef HAVE_SYS_TIME_H
48     #include <sys/time.h>
49   #endif
50 #else
51   #ifdef HAVE_SYS_TIME_H
52     #include <sys/time.h>
53   #else
54     #include <time.h>
55   #endif
56 #endif
57 #ifdef HAVE_SYS_TIMES_H
58   #include <sys/times.h>
59 #endif
60
61 #define INTERACTIVE 0
62 #define STACK_TRACE 1
63
64 #ifdef CALL_GDB
65   static void debug (int);
66   static void debug_stop (char *const*args);
67 #endif
68 #ifndef __OPTIMIZE__
69   static void stack_trace_sigchld (int);
70   static void stack_trace (char *const*args);
71 #endif
72#endif
73
74si_link pipeLastLink=NULL;
75BOOLEAN singular_in_batchmode=FALSE;
76
77void sig_pipe_hdl(int sig)
78{
79 if (pipeLastLink!=NULL)
80 {
81   slClose(pipeLastLink);
82   pipeLastLink=NULL;
83   WerrorS("pipe failed");
84 }
85}
86
87/*---------------------------------------------------------------------*
88 * File scope Variables (Variables share by several functions in
89 *                       the same file )
90 *
91 *---------------------------------------------------------------------*/
92/* data */
93jmp_buf si_start_jmpbuf;
94int siRandomStart;
95short si_restart=0;
96BOOLEAN siCntrlc = FALSE;
97
98typedef void (*si_hdl_typ)(int);
99
100
101/*0 implementation*/
102/*---------------------------------------------------------------------*
103 * Functions declarations
104 *
105 *---------------------------------------------------------------------*/
106void sigint_handler(int sig);
107
108si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler);
109
110/*---------------------------------------------------------------------*/
111/**
112 * @brief meta function for binding a signal to an handler
113
114 @param[in] sig             Signal number
115 @param[in] signal_handler  Pointer to signal handler
116
117 @return value of signal()
118**/
119/*---------------------------------------------------------------------*/
120si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler)
121{
122  si_hdl_typ retval=signal (sig, (si_hdl_typ)signal_handler);
123  if (retval == SIG_ERR)
124  {
125     fprintf(stderr, "Unable to init signal %d ... exiting...\n", sig);
126  }
127#ifdef HAVE_SIGINTERRUPT
128  siginterrupt(sig, 1);
129#endif
130  return retval;
131}                               /* si_set_signal */
132
133
134/*---------------------------------------------------------------------*/
135#if defined(ix86_Linux)
136  #if !defined(HAVE_SIGCONTEXT) && !defined(HAVE_ASM_SIGCONTEXT_H)
137// we need the following structure sigcontext_struct.
138// if configure finds asm/singcontext.h we assume
139// that this file contains the structure and is included
140// via signal.h
141struct sigcontext_struct {
142        unsigned short gs, __gsh;
143        unsigned short fs, __fsh;
144        unsigned short es, __esh;
145        unsigned short ds, __dsh;
146        unsigned long edi;
147        unsigned long esi;
148        unsigned long ebp;
149        unsigned long esp;
150        unsigned long ebx;
151        unsigned long edx;
152        unsigned long ecx;
153        unsigned long eax;
154        unsigned long trapno;
155        unsigned long err;
156        unsigned long eip;
157        unsigned short cs, __csh;
158        unsigned long eflags;
159        unsigned long esp_at_signal;
160        unsigned short ss, __ssh;
161        unsigned long i387;
162        unsigned long oldmask;
163        unsigned long cr2;
164};
165#endif
166#define HAVE_SIGSTRUCT
167typedef struct sigcontext_struct sigcontext;
168#endif
169
170#if defined(x86_64_Linux)
171#define HAVE_SIGSTRUCT
172#endif
173
174
175#if defined(HAVE_SIGSTRUCT)
176/*2---------------------------------------------------------------------*/
177/**
178 * @brief signal handler for run time errors, linux/i386, x86_64 version
179
180 @param[in] sig
181 @param[in] s
182**/
183/*---------------------------------------------------------------------*/
184void sigsegv_handler(int sig, sigcontext s)
185{
186  fprintf(stderr,"Singular : signal %d (v: %d/%s):\n",sig,SINGULAR_VERSION,feVersionId);
187  if (sig!=SIGINT)
188  {
189    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
190    fprintf(stderr,"Segment fault/Bus error occurred at %lx because of %lx (r:%d)\n"
191                   "please inform the authors\n",
192                   #ifdef __i386__
193                   (long)s.eip,
194                   #else /* x86_64*/
195                   (long)s.rip,
196                   #endif
197                   (long)s.cr2,siRandomStart);
198  }
199#ifdef __OPTIMIZE__
200  if(si_restart<3)
201  {
202    si_restart++;
203    fprintf(stderr,"trying to restart...\n");
204    init_signals();
205    longjmp(si_start_jmpbuf,1);
206  }
207#endif /* __OPTIMIZE__ */
208#ifdef CALL_GDB
209  if (sig!=SIGINT) 
210  {
211    if (singular_in_batchmode) debug(STACK_TRACE);
212    else                       debug(INTERACTIVE);
213  }
214#endif /* CALL_GDB */
215  exit(0);
216}
217
218/*---------------------------------------------------------------------*/
219/**
220 * @brief additional default signal handler
221
222  // some newer Linux version cannot have SIG_IGN for SIGCHLD,
223  // so use this nice routine here:
224  //  SuSe 9.x reports -1 always
225  //  Redhat 9.x/FC x reports sometimes -1
226  // see also: hpux_system
227  // also needed by getrusage (timer etc.)
228
229 @param[in] sig
230**/
231/*---------------------------------------------------------------------*/
232void sig_ign_hdl(int sig)
233{
234 waitpid(-1,NULL,WNOHANG); 
235}
236
237/*2
238* init signal handlers, linux/i386 version
239*/
240void init_signals()
241{
242/*4 signal handler: linux*/
243  if (SIG_ERR==si_set_signal(SIGSEGV,(si_hdl_typ)sigsegv_handler))
244  {
245    PrintS("cannot set signal handler for SEGV\n");
246  }
247  if (SIG_ERR==si_set_signal(SIGFPE, (si_hdl_typ)sigsegv_handler))
248  {
249    PrintS("cannot set signal handler for FPE\n");
250  }
251  if (SIG_ERR==si_set_signal(SIGILL, (si_hdl_typ)sigsegv_handler))
252  {
253    PrintS("cannot set signal handler for ILL\n");
254  }
255  if (SIG_ERR==si_set_signal(SIGIOT, (si_hdl_typ)sigsegv_handler))
256  {
257    PrintS("cannot set signal handler for IOT\n");
258  }
259  if (SIG_ERR==si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler))
260  {
261    PrintS("cannot set signal handler for INT\n");
262  }
263  si_set_signal(SIGCHLD, (si_hdl_typ)sig_ign_hdl);
264  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
265}
266
267/*---------------------------------------------------------------------*/
268#elif defined(SunOS) /*SPARC_SUNOS*/
269/*2
270* signal handler for run time errors, sparc sunos 4 version
271*/
272void sigsegv_handler(int sig, int code, struct sigcontext *scp, char *addr)
273{
274  fprintf(stderr,"Singular : signal %d, code %d (v: %d/%s):\n",
275    sig,code,SINGULAR_VERSION,feVersionId);
276  if ((sig!=SIGINT)&&(sig!=SIGABRT))
277  {
278    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
279    fprintf(stderr,"Segment fault/Bus error occurred at %x (r:%d)\n"
280                   "please inform the authors\n",
281                   (int)addr,siRandomStart);
282  }
283#ifdef __OPTIMIZE__
284  if(si_restart<3)
285  {
286    si_restart++;
287    fprintf(stderr,"trying to restart...\n");
288    init_signals();
289    longjmp(si_start_jmpbuf,1);
290  }
291#endif /* __OPTIMIZE__ */
292#ifdef CALL_GDB
293  if (sig!=SIGINT) debug(STACK_TRACE);
294#endif /* CALL_GDB */
295  exit(0);
296}
297
298/*2
299* init signal handlers, sparc sunos 4 version
300*/
301void init_signals()
302{
303/*4 signal handler:*/
304  si_set_signal(SIGSEGV,sigsegv_handler);
305  si_set_signal(SIGBUS, sigsegv_handler);
306  si_set_signal(SIGFPE, sigsegv_handler);
307  si_set_signal(SIGILL, sigsegv_handler);
308  si_set_signal(SIGIOT, sigsegv_handler);
309  si_set_signal(SIGINT ,sigint_handler);
310  si_set_signal(SIGCHLD, (void (*)(int))SIG_IGN);
311  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
312}
313#else
314
315/*---------------------------------------------------------------------*/
316/*2
317* signal handler for run time errors, general version
318*/
319void sigsegv_handler(int sig)
320{
321  fprintf(stderr,"Singular : signal %d (v: %d/%s):\n",
322    sig,SINGULAR_VERSION,feVersionId);
323  if (sig!=SIGINT)
324  {
325    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
326    fprintf(stderr,"Segment fault/Bus error occurred (r:%d)\n"
327                   "please inform the authors\n",
328                   siRandomStart);
329  }
330  #ifdef __OPTIMIZE__
331  if(si_restart<3)
332  {
333    si_restart++;
334    fprintf(stderr,"trying to restart...\n");
335    init_signals();
336    longjmp(si_start_jmpbuf,1);
337  }
338  #endif /* __OPTIMIZE__ */
339  #if defined(unix) && !defined(hpux)
340  /* debug(..) does not work under HPUX (because ptrace does not work..) */
341  #ifdef CALL_GDB
342  if (sig!=SIGINT) debug(STACK_TRACE);
343  #endif /* CALL_GDB */
344  #endif /* unix */
345  exit(0);
346}
347
348/*2
349* init signal handlers, general version
350*/
351void init_signals()
352{
353/*4 signal handler:*/
354  si_set_signal(SIGSEGV,(void (*) (int))sigsegv_handler);
355  #ifdef SIGBUS
356  si_set_signal(SIGBUS, sigsegv_handler);
357  #endif /* SIGBUS */
358  #ifdef SIGFPE
359  si_set_signal(SIGFPE, sigsegv_handler);
360  #endif /* SIGFPE */
361  #ifdef SIGILL
362  si_set_signal(SIGILL, sigsegv_handler);
363  #endif /* SIGILL */
364  #ifdef SIGIOT
365  si_set_signal(SIGIOT, sigsegv_handler);
366  #endif /* SIGIOT */
367  #ifdef SIGXCPU
368  si_set_signal(SIGXCPU, (void (*)(int))SIG_IGN);
369  #endif /* SIGIOT */
370  si_set_signal(SIGINT ,sigint_handler);
371  #if defined(HPUX_9) || defined(HPUX_10)
372  si_set_signal(SIGCHLD, (void (*)(int))SIG_IGN);
373  #endif
374  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
375}
376#endif
377
378
379/*2
380* signal handler for SIGINT
381*/
382void sigint_handler(int sig)
383{
384  mflush();
385  #ifdef HAVE_FEREAD
386  if (fe_is_raw_tty) fe_temp_reset();
387  #endif /* HAVE_FEREAD */
388  loop
389  {
390    int cnt=0;
391    int c;
392    if(singular_in_batchmode)
393    {
394      c = 'q';
395    }
396    else
397    {
398      fprintf(stderr,"// ** Interrupt at cmd:`%s` in line:'%s'\n",
399        Tok2Cmdname(iiOp),my_yylinebuf);
400      if (feGetOptValue(FE_OPT_EMACS) == NULL)
401      {
402        fputs("abort command(a), continue(c) or quit Singular(q) ?",stderr);fflush(stderr);
403        c = fgetc(stdin);
404      }
405      else
406      {
407        c = 'a';
408      }
409    }
410
411    switch(c)
412    {
413      case 'q':
414                m2_end(2);
415      case 'r':
416                longjmp(si_start_jmpbuf,1);
417      case 'b':
418                VoiceBackTrack();
419                break;
420      case 'a':
421                siCntrlc++;
422      case 'c':
423                if (feGetOptValue(FE_OPT_EMACS) == NULL) fgetc(stdin);
424                si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler);
425                return;
426                //siCntrlc ++;
427                //if (siCntrlc>2) si_set_signal(SIGINT,(si_hdl_typ) sigsegv_handler);
428                //else            si_set_signal(SIGINT,(si_hdl_typ) sigint_handler);
429    }
430    cnt++;
431    if(cnt>5) m2_end(2);
432  }
433}
434
435//void test_int()
436//{
437//  if (siCntrlc!=0)
438//  {
439//    int saveecho = si_echo;
440//    siCntrlc = FALSE;
441//    si_set_signal(SIGINT ,sigint_handler);
442//    iiDebug();
443//    si_echo = saveecho;
444//  }
445//}
446
447#ifdef unix
448# ifndef hpux
449#  ifndef __OPTIMIZE__
450int si_stop_stack_trace_x;
451#    ifdef CALL_GDB
452static void debug (int method)
453{
454  if (feOptValue(FE_OPT_NO_TTY))
455  {
456    dReportError("Caught Signal 11");
457    return;
458  }
459  int pid;
460  char buf[16];
461  char * args[4] = { (char*)"gdb", (char*)"Singularg", NULL, NULL };
462
463  #ifdef HAVE_FEREAD
464  if (fe_is_raw_tty) fe_temp_reset();
465  #endif /* HAVE_FEREAD */
466
467  sprintf (buf, "%d", getpid ());
468
469  args[2] = buf;
470
471  pid = fork ();
472  if (pid == 0)
473  {
474    switch (method)
475    {
476      case INTERACTIVE:
477        fprintf (stderr, "debug_stop\n");
478        debug_stop (args);
479        break;
480      #ifndef __OPTIMIZE__
481      case STACK_TRACE:
482        fprintf (stderr, "stack_trace\n");
483        stack_trace (args);
484        break;
485      #endif
486      default:
487        // should not be reached:
488        exit(1);
489    }
490  }
491  else if (pid == -1)
492  {
493    perror ("could not fork");
494    return;
495  }
496
497  si_stop_stack_trace_x = 1;
498  while (si_stop_stack_trace_x) ;
499}
500
501static void debug_stop (char *const*args)
502{
503  execvp (args[0], args);
504  perror ("exec failed");
505  _exit (0);
506}
507#    endif /* CALL_GDB */
508
509static int stack_trace_done;
510
511static void stack_trace (char *const*args)
512{
513  int pid;
514  int in_fd[2];
515  int out_fd[2];
516  fd_set fdset;
517  fd_set readset;
518  struct timeval tv;
519  int sel, index, state;
520  char buffer[256];
521  char c;
522
523  stack_trace_done = 0;
524
525  signal (SIGCHLD, stack_trace_sigchld);
526
527  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
528  {
529    perror ("could open pipe");
530    m2_end(999);
531  }
532
533  pid = fork ();
534  if (pid == 0)
535  {
536    close (0); dup2 (in_fd[0],0);   /* set the stdin to the in pipe */
537    close (1); dup2 (out_fd[1],1);  /* set the stdout to the out pipe */
538    close (2); dup2 (out_fd[1],2);  /* set the stderr to the out pipe */
539
540    execvp (args[0], args);      /* exec gdb */
541    perror ("exec failed");
542    m2_end(999);
543  }
544  else if (pid == -1)
545  {
546    perror ("could not fork");
547    m2_end(999);
548  }
549
550  FD_ZERO (&fdset);
551  FD_SET (out_fd[0], &fdset);
552
553  write (in_fd[1], "backtrace\n", 10);
554  write (in_fd[1], "p si_stop_stack_trace_x = 0\n", 28);
555  write (in_fd[1], "quit\n", 5);
556
557  index = 0;
558  state = 0;
559
560  loop
561  {
562    readset = fdset;
563    tv.tv_sec = 1;
564    tv.tv_usec = 0;
565
566#    ifdef hpux
567    sel = select (FD_SETSIZE, (int *)readset.fds_bits, NULL, NULL, &tv);
568#    else /* hpux */
569    sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
570#    endif /* hpux */
571    if (sel == -1)
572      break;
573
574    if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
575    {
576      if (read (out_fd[0], &c, 1))
577      {
578        switch (state)
579        {
580          case 0:
581            if (c == '#')
582            {
583              state = 1;
584              index = 0;
585              buffer[index++] = c;
586            }
587            break;
588          case 1:
589            buffer[index++] = c;
590            if ((c == '\n') || (c == '\r'))
591            {
592              buffer[index] = 0;
593              fprintf (stderr, "%s", buffer);
594              state = 0;
595              index = 0;
596            }
597            break;
598          default:
599            break;
600        }
601      }
602    }
603    else if (stack_trace_done)
604      break;
605  }
606
607  close (in_fd[0]);
608  close (in_fd[1]);
609  close (out_fd[0]);
610  close (out_fd[1]);
611  m2_end(0);
612}
613
614static void stack_trace_sigchld (int signum)
615{
616  stack_trace_done = 1;
617}
618
619#  endif /* !__OPTIMIZE__ */
620# endif /* !hpux */
621#endif /* unix */
622
623/* Under HPUX 9, system(...) returns -1 if SIGCHLD does not equal
624   SIG_DFL. However, if it stays at SIG_DFL we get zombie processes
625   for terminated childs generated by fork. Therefors some special treatment
626   is necessary */
627#ifdef HPUX_9
628# undef system
629extern "C" {
630  int  hpux9_system(const char* call)
631  {
632    int ret;
633    si_set_signal(SIGCHLD, (void (*)(int))SIG_DFL);
634    ret = system(call);
635    si_set_signal(SIGCHLD, (void (*)(int))SIG_IGN);
636    return ret;
637  }
638}
639#endif /* HPUX_9 */
Note: See TracBrowser for help on using the repository browser.