source: git/Singular/cntrlc.cc @ 7ffb4b

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