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