source: git/Singular/cntrlc.cc @ 5476e83

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