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

spielwiese
Last change on this file since 8af20e was 8af20e, checked in by Hans Schoenemann <hannes@…>, 9 years ago
cntrlc handling: flush input
  • Property mode set to 100644
File size: 13.9 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                  longjmp(si_start_jmpbuf,1);
369                }
370                else
371                {
372                  fputs("** tried too often, try another possibility **\n",stderr);
373                  fflush(stderr);
374                }
375                break;
376      case 'b':
377                VoiceBackTrack();
378                break;
379      case 'a':
380                siCntrlc++;
381      case 'c':
382                if ((feOptValue(FE_OPT_EMACS) == NULL) && (default_opt!=' '))
383                {
384                  /* Read until a newline or EOF */
385                  while (c != EOF && c != '\n') c = fgetc(stdin);
386                }
387                si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler);
388                return;
389                //siCntrlc ++;
390                //if (siCntrlc>2) si_set_signal(SIGINT,(si_hdl_typ) sigsegv_handler);
391                //else            si_set_signal(SIGINT,(si_hdl_typ) sigint_handler);
392    }
393    cnt++;
394    if(cnt>5) m2_end(2);
395  }
396}
397
398//void test_int()
399//{
400//  if (siCntrlc!=0)
401//  {
402//    int saveecho = si_echo;
403//    siCntrlc = FALSE;
404//    si_set_signal(SIGINT ,sigint_handler);
405//    iiDebug();
406//    si_echo = saveecho;
407//  }
408//}
409
410#ifdef unix
411#  ifndef __OPTIMIZE__
412volatile int si_stop_stack_trace_x;
413#    ifdef CALL_GDB
414static void debug (int method)
415{
416  if (feOptValue(FE_OPT_NO_TTY))
417  {
418    dReportError("Caught Signal 11");
419    return;
420  }
421  int pid;
422  char buf[16];
423  char * args[4] = { (char*)"gdb", (char*)"Singular", NULL, NULL };
424
425  #ifdef HAVE_FEREAD
426  if (fe_is_raw_tty) fe_temp_reset();
427  #endif /* HAVE_FEREAD */
428
429  sprintf (buf, "%d", getpid ());
430
431  args[2] = buf;
432
433  pid = fork ();
434  if (pid == 0)
435  {
436    switch (method)
437    {
438      case INTERACTIVE:
439        fprintf (stderr, "\n\nquit with \"p si_stop_stack_trace_x=0\"\n\n\n");
440        debug_stop (args);
441        break;
442      case STACK_TRACE:
443        fprintf (stderr, "stack_trace\n");
444        stack_trace (args);
445        break;
446      default:
447        // should not be reached:
448        exit(1);
449    }
450  }
451  else if (pid == -1)
452  {
453    perror ("could not fork");
454    return;
455  }
456
457  si_stop_stack_trace_x = 1;
458  while (si_stop_stack_trace_x) ;
459}
460
461static void debug_stop (char *const*args)
462{
463  execvp (args[0], args);
464  perror ("exec failed");
465  _exit (0);
466}
467#    endif /* CALL_GDB */
468
469static void stack_trace (char *const*args)
470{
471  int pid;
472  int in_fd[2];
473  int out_fd[2];
474  fd_set fdset;
475  fd_set readset;
476  struct timeval tv;
477  int sel, index, state;
478  char buffer[256];
479  char c;
480
481  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
482  {
483    perror ("could open pipe");
484    m2_end(999);
485  }
486
487  pid = fork ();
488  if (pid == 0)
489  {
490    si_close (0); si_dup2 (in_fd[0],0);   /* set the stdin to the in pipe */
491    si_close (1); si_dup2 (out_fd[1],1);  /* set the stdout to the out pipe */
492    si_close (2); si_dup2 (out_fd[1],2);  /* set the stderr to the out pipe */
493
494    execvp (args[0], args);      /* exec gdb */
495    perror ("exec failed");
496    m2_end(999);
497  }
498  else if (pid == -1)
499  {
500    perror ("could not fork");
501    m2_end(999);
502  }
503
504  FD_ZERO (&fdset);
505  FD_SET (out_fd[0], &fdset);
506
507  si_write (in_fd[1], "backtrace\n", 10);
508  si_write (in_fd[1], "p si_stop_stack_trace_x = 0\n", 28);
509  si_write (in_fd[1], "quit\n", 5);
510
511  index = 0;
512  state = 0;
513
514  loop
515  {
516    readset = fdset;
517    tv.tv_sec = 1;
518    tv.tv_usec = 0;
519
520    sel = si_select (FD_SETSIZE, &readset, NULL, NULL, &tv);
521    if (sel == -1)
522      break;
523
524    if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
525    {
526      if (si_read (out_fd[0], &c, 1))
527      {
528        switch (state)
529        {
530          case 0:
531            if (c == '#')
532            {
533              state = 1;
534              index = 0;
535              buffer[index++] = c;
536            }
537            break;
538          case 1:
539            buffer[index++] = c;
540            if ((c == '\n') || (c == '\r'))
541            {
542              buffer[index] = 0;
543              fprintf (stderr, "%s", buffer);
544              state = 0;
545              index = 0;
546            }
547            break;
548          default:
549            break;
550        }
551      }
552    }
553    else if (si_stop_stack_trace_x==0)
554      break;
555  }
556
557  si_close (in_fd[0]);
558  si_close (in_fd[1]);
559  si_close (out_fd[0]);
560  si_close (out_fd[1]);
561  m2_end(0);
562}
563
564#  endif /* !__OPTIMIZE__ */
565#endif /* unix */
566
567/*2
568* init signal handlers
569*/
570void init_signals()
571{
572  #ifdef SIGSEGV
573  si_set_signal(SIGSEGV,(si_hdl_typ)sigsegv_handler);
574  #endif
575  #ifdef SIGBUS
576  si_set_signal(SIGBUS, (si_hdl_typ)sigsegv_handler);
577  #endif
578  #ifdef SIGFPE
579  si_set_signal(SIGFPE, (si_hdl_typ)sigsegv_handler);
580  #endif
581  #ifdef SIGILL
582  si_set_signal(SIGILL, (si_hdl_typ)sigsegv_handler);
583  #endif
584  #ifdef SIGIOT
585  si_set_signal(SIGIOT, (si_hdl_typ)sigsegv_handler);
586  #endif
587  si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler);
588  si_set_signal(SIGCHLD, (si_hdl_typ)sig_chld_hdl);
589  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
590  si_set_signal(SIGTERM, (si_hdl_typ)sig_term_hdl);
591}
592
Note: See TracBrowser for help on using the repository browser.