source: git/Singular/cntrlc.cc @ bd4cb06

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