source: git/Singular/cntrlc.cc @ 206e202

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