source: git/Singular/cntrlc.cc @ 8d1432e

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