source: git/Singular/cntrlc.cc @ a3f0fea

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