My Project
cntrlc.cc
Go to the documentation of this file.
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 /* undef, if you don't want GDB to come up on error */
27 
28 #define CALL_GDB
29 
30 #if defined(__OPTIMIZE__) && defined(CALL_GDB)
31 #undef CALL_GDB
32 #endif
33 
34  #ifdef TIME_WITH_SYS_TIME
35  #include <time.h>
36  #ifdef HAVE_SYS_TIME_H
37  #include <sys/time.h>
38  #endif
39  #else
40  #ifdef HAVE_SYS_TIME_H
41  #include <sys/time.h>
42  #else
43  #include <time.h>
44  #endif
45  #endif
46  #ifdef HAVE_SYS_TIMES_H
47  #include <sys/times.h>
48  #endif
49 
50  #define INTERACTIVE 0
51  #define STACK_TRACE 1
52 
53  #ifdef CALL_GDB
54  static void debug (int);
55  static void debug_stop (char *const*args);
56  #endif
57  #ifndef __OPTIMIZE__
58  static void stack_trace (char *const*args);
59  #endif
60 
63 
64 void sig_pipe_hdl(int /*sig*/)
65 {
66  if (pipeLastLink!=NULL)
67  {
70  WerrorS("pipe failed");
71  }
72 }
73 
75 VAR volatile int defer_shutdown = 0;
76 
77 void sig_term_hdl(int /*sig*/)
78 {
79  do_shutdown = TRUE;
80  if (!defer_shutdown)
81  {
82  m2_end(1);
83  }
84 }
85 
86 /*---------------------------------------------------------------------*
87  * File scope Variables (Variables shared by several functions in
88  * the same file )
89  *
90  *---------------------------------------------------------------------*/
91 /* data */
94 VAR short si_restart=0;
95 
96 typedef void (*si_hdl_typ)(int);
97 
98 
99 /*0 implementation*/
100 /*---------------------------------------------------------------------*
101  * Functions declarations
102  *
103  *---------------------------------------------------------------------*/
104 void sigint_handler(int /*sig*/);
105 
106 si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler);
107 
108 /*---------------------------------------------------------------------*/
109 /**
110  * @brief meta function for binding a signal to an handler
111 
112  @param[in] sig Signal number
113  @param[in] signal_handler Pointer to signal handler
114 
115  @return value of signal()
116 **/
117 /*---------------------------------------------------------------------*/
118 si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler)
119 {
120 #if 0
121  si_hdl_typ retval=signal (sig, (si_hdl_typ)signal_handler);
122  if (retval == SIG_ERR)
123  {
124  fprintf(stderr, "Unable to init signal %d ... exiting...\n", sig);
125  }
126  si_siginterrupt(sig, 0);
127  /*system calls will be restarted if interrupted by the specified
128  * signal sig. This is the default behavior in Linux.
129  */
130 #else
131  struct sigaction new_action,old_action;
132  memset(&new_action, 0, sizeof(struct sigaction));
133 
134  /* Set up the structure to specify the new action. */
135  new_action.sa_handler = signal_handler;
136  if (sig==SIGINT)
137  sigemptyset (&new_action.sa_mask);
138  else
139  new_action.sa_flags = SA_RESTART;
140 
141  int r=si_sigaction (sig, &new_action, &old_action);
142  si_hdl_typ retval=(si_hdl_typ)old_action.sa_handler;
143  if (r == -1)
144  {
145  fprintf(stderr, "Unable to init signal %d ... exiting...\n", sig);
146  retval=SIG_ERR;
147  }
148 #endif
149  return retval;
150 } /* si_set_signal */
151 
152 
153 /*---------------------------------------------------------------------*/
154 #if defined(__linux__) && (defined(__i386) || defined(__amd64))
155 /*2---------------------------------------------------------------------*/
156 /**
157  * @brief signal handler for run time errors, linux/i386, x86_64 version
158 
159  @param[in] sig
160  @param[in] s
161 **/
162 /*---------------------------------------------------------------------*/
163 void sigsegv_handler(int sig, sigcontext s)
164 {
165  fprintf(stderr,"Singular : signal %d (v: %d):\n",sig,SINGULAR_VERSION);
166  if (sig!=SIGINT)
167  {
168  fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
169  fprintf(stderr,"Segment fault/Bus error occurred at %lx because of %lx (r:%d)\n"
170  "please inform the authors\n",
171  #ifdef __i386__
172  (long)s.eip,
173  #else /* x86_64*/
174  (long)s.rip,
175  #endif
176  (long)s.cr2,siRandomStart);
177  }
178 #ifdef __OPTIMIZE__
179  if(si_restart<3)
180  {
181  si_restart++;
182  fputs("trying to restart...\n",stderr);
183  init_signals();
184  longjmp(si_start_jmpbuf,1);
185  }
186 #endif /* __OPTIMIZE__ */
187 #ifdef CALL_GDB
188  if (sig!=SIGINT)
189  {
191  else debug(INTERACTIVE);
192  }
193 #endif /* CALL_GDB */
194  exit(0);
195 }
196 
197 /*---------------------------------------------------------------------*/
198 #elif defined(SunOS) /*SPARC_SUNOS*/
199 /*2
200 * signal handler for run time errors, sparc sunos 4 version
201 */
202 void sigsegv_handler(int sig, int code, struct sigcontext *scp, char *addr)
203 {
204  fprintf(stderr,"Singular : signal %d, code %d (v: %d):\n",
205  sig,code,SINGULAR_VERSION);
206  if ((sig!=SIGINT)&&(sig!=SIGABRT))
207  {
208  fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
209  fprintf(stderr,"Segment fault/Bus error occurred at %x (r:%d)\n"
210  "please inform the authors\n",
211  (int)addr,siRandomStart);
212  }
213 #ifdef __OPTIMIZE__
214  if(si_restart<3)
215  {
216  si_restart++;
217  fputs("trying to restart...\n",stderr);
218  init_signals();
219  longjmp(si_start_jmpbuf,1);
220  }
221 #endif /* __OPTIMIZE__ */
222 #ifdef CALL_GDB
223  if (sig!=SIGINT) debug(STACK_TRACE);
224 #endif /* CALL_GDB */
225  exit(0);
226 }
227 
228 #else
229 
230 /*---------------------------------------------------------------------*/
231 /*2
232 * signal handler for run time errors, general version
233 */
234 void sigsegv_handler(int sig)
235 {
236  fprintf(stderr,"Singular : signal %d (v: %d):\n",
237  sig,SINGULAR_VERSION);
238  if (sig!=SIGINT)
239  {
240  fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
241  fprintf(stderr,"Segment fault/Bus error occurred (r:%d)\n"
242  "please inform the authors\n",
243  siRandomStart);
244  }
245  #ifdef __OPTIMIZE__
246  if(si_restart<3)
247  {
248  si_restart++;
249  fputs("trying to restart...\n",stderr);
250  init_signals();
251  longjmp(si_start_jmpbuf,1);
252  }
253  #endif /* __OPTIMIZE__ */
254  #ifdef CALL_GDB
255  if (sig!=SIGINT) debug(STACK_TRACE);
256  #endif /* CALL_GDB */
257  exit(0);
258 }
259 #endif
260 
261 
262 /*2
263 * signal handler for SIGINT
264 */
266 void sigint_handler(int /*sig*/)
267 {
268  mflush();
269  #ifdef HAVE_FEREAD
271  #endif /* HAVE_FEREAD */
272  char default_opt=' ';
273  if ((feOptSpec[FE_OPT_CNTRLC].value!=NULL)
274  && ((char*)(feOptSpec[FE_OPT_CNTRLC].value))[0])
275  { default_opt=((char*)(feOptSpec[FE_OPT_CNTRLC].value))[0]; }
276  loop
277  {
278  int cnt=0;
279  int c;
280 
282  {
283  c = 'q';
284  }
285  else if (default_opt!=' ')
286  {
287  c = default_opt;
288  }
289  else
290  {
291  fprintf(stderr,"// ** Interrupt at cmd:`%s` in line:'%s'\n",
293  if (feOptValue(FE_OPT_EMACS) == NULL)
294  {
295  fputs("abort after this command(a), abort immediately(r), print backtrace(b), continue(c) or quit Singular(q) ?",stderr);
296  fflush(stderr);fflush(stdin);
297  c = fgetc(stdin);
298  }
299  else
300  {
301  c = 'a';
302  }
303  }
304 
305  switch(c)
306  {
307  case 'q': case EOF:
308  m2_end(2);
309  case 'r':
310  if (sigint_handler_cnt<3)
311  {
313  fputs("** Warning: Singular should be restarted as soon as possible **\n",stderr);
314  fflush(stderr);
315  extern void my_yy_flush();
316  my_yy_flush();
318  longjmp(si_start_jmpbuf,1);
319  }
320  else
321  {
322  fputs("** tried too often, try another possibility **\n",stderr);
323  fflush(stderr);
324  }
325  break;
326  case 'b':
327  VoiceBackTrack();
328  break;
329  case 'a':
330  siCntrlc++;
331  case 'c':
332  if ((feOptValue(FE_OPT_EMACS) == NULL) && (default_opt!=' '))
333  {
334  /* Read until a newline or EOF */
335  while (c != EOF && c != '\n') c = fgetc(stdin);
336  }
338  return;
339  //siCntrlc ++;
340  //if (siCntrlc>2) si_set_signal(SIGINT,(si_hdl_typ) sigsegv_handler);
341  //else si_set_signal(SIGINT,(si_hdl_typ) sigint_handler);
342  }
343  cnt++;
344  if(cnt>5) m2_end(2);
345  }
346 }
347 
348 //void test_int()
349 //{
350 // if (siCntrlc!=0)
351 // {
352 // int saveecho = si_echo;
353 // siCntrlc = FALSE;
354 // si_set_signal(SIGINT ,sigint_handler);
355 // iiDebug();
356 // si_echo = saveecho;
357 // }
358 //}
359 
360 # ifndef __OPTIMIZE__
362 # ifdef CALL_GDB
363 static void debug (int method)
364 {
365  if (feOptValue(FE_OPT_NO_TTY))
366  {
367  dReportError("Caught Signal 11");
368  return;
369  }
370  /* REMARK FOR NEWER LINUX SYSTEMS:
371 Attaching to a process on Linux with GDB as a normal user may fail with "ptrace:Operation not permitted". By default Linux does not allow attaching to a process which wasn't launched by the debugger (see the Yama security documentation for more details). (https://www.kernel.org/doc/Documentation/security/Yama.txt)
372 
373 There are ways to workaround this:
374 
375  Run the following command as super user: echo 0| sudo tee /proc/sys/kernel/yama/ptrace_scope
376 
377  This will set the ptrace level to 0, after this just with user permissions you can attach to processes which are not launched by the debugger.
378 
379  On distributions without Yama (such as Raspbian) you can use libcap2-bin to assign ptrace permissions to specific executables: sudo setcap cap_sys_ptrace=eip /usr/bin/gdb
380 */
381  int pid;
382  char buf[16];
383  char * args[4] = { (char*)"gdb", (char*)"Singular", NULL, NULL };
384 
385  #ifdef HAVE_FEREAD
387  #endif /* HAVE_FEREAD */
388 
389  sprintf (buf, "%d", getpid ());
390 
391  args[2] = buf;
392 
393  pid = fork ();
394  if (pid == 0)
395  {
396  switch (method)
397  {
398  case INTERACTIVE:
399  fputs ("\n\nquit with \"p si_stop_stack_trace_x=0\"\n\n\n",stderr);
400  debug_stop (args);
401  break;
402  case STACK_TRACE:
403  fputs ("stack_trace\n",stderr);
404  stack_trace (args);
405  break;
406  default:
407  // should not be reached:
408  exit(1);
409  }
410  }
411  else if (pid == -1)
412  {
413  perror ("could not fork");
414  return;
415  }
416 
418  while (si_stop_stack_trace_x) ;
419 }
420 
421 static void debug_stop (char *const*args)
422 {
423  execvp (args[0], args);
424  perror ("exec failed");
425  _exit (0);
426 }
427 # endif /* CALL_GDB */
428 
429 static void stack_trace (char *const*args)
430 {
431  int pid;
432  int in_fd[2];
433  int out_fd[2];
434  fd_set fdset;
435  fd_set readset;
436  struct timeval tv;
437  int sel, index, state;
438  char buffer[256];
439  char c;
440 
441  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
442  {
443  perror ("could open pipe");
444  m2_end(999);
445  }
446 
447  pid = fork ();
448  if (pid == 0)
449  {
450  si_close (0); si_dup2 (in_fd[0],0); /* set the stdin to the in pipe */
451  si_close (1); si_dup2 (out_fd[1],1); /* set the stdout to the out pipe */
452  si_close (2); si_dup2 (out_fd[1],2); /* set the stderr to the out pipe */
453 
454  execvp (args[0], args); /* exec gdb */
455  perror ("exec failed");
456  m2_end(999);
457  }
458  else if (pid == -1)
459  {
460  perror ("could not fork");
461  m2_end(999);
462  }
463 
464  FD_ZERO (&fdset);
465  FD_SET (out_fd[0], &fdset);
466 
467  si_write (in_fd[1], "backtrace\n", 10);
468  si_write (in_fd[1], "p si_stop_stack_trace_x = 0\n", 28);
469  si_write (in_fd[1], "quit\n", 5);
470 
471  index = 0;
472  state = 0;
473 
474  loop
475  {
476  readset = fdset;
477  tv.tv_sec = 1;
478  tv.tv_usec = 0;
479 
480  sel = si_select (FD_SETSIZE, &readset, NULL, NULL, &tv);
481  if (sel == -1)
482  break;
483 
484  if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
485  {
486  if (si_read (out_fd[0], &c, 1))
487  {
488  switch (state)
489  {
490  case 0:
491  if (c == '#')
492  {
493  state = 1;
494  index = 0;
495  buffer[index++] = c;
496  }
497  break;
498  case 1:
499  buffer[index++] = c;
500  if ((c == '\n') || (c == '\r'))
501  {
502  buffer[index] = 0;
503  fputs (buffer,stderr);
504  state = 0;
505  index = 0;
506  }
507  break;
508  default:
509  break;
510  }
511  }
512  }
513  else if (si_stop_stack_trace_x==0)
514  break;
515  }
516 
517  si_close (in_fd[0]);
518  si_close (in_fd[1]);
519  si_close (out_fd[0]);
520  si_close (out_fd[1]);
521  m2_end(0);
522 }
523 
524 # endif /* !__OPTIMIZE__ */
525 
526 /// init signal handlers and error handling for libraries: NTL, factory
528 {
529 // signal handler -------------------------------------------------------
530  #ifdef SIGSEGV
532  #endif
533  #ifdef SIGBUS
535  #endif
536  #ifdef SIGFPE
538  #endif
539  #ifdef SIGILL
541  #endif
542  #ifdef SIGIOT
544  #endif
549 }
550 
int BOOLEAN
Definition: auxiliary.h:87
#define TRUE
Definition: auxiliary.h:100
#define FALSE
Definition: auxiliary.h:96
VAR si_link pipeLastLink
Definition: cntrlc.cc:61
void sig_pipe_hdl(int)
Definition: cntrlc.cc:64
VAR jmp_buf si_start_jmpbuf
Definition: cntrlc.cc:92
static void stack_trace(char *const *args)
Definition: cntrlc.cc:429
VAR BOOLEAN singular_in_batchmode
Definition: cntrlc.cc:62
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:118
VAR volatile int si_stop_stack_trace_x
Definition: cntrlc.cc:361
static void debug(int)
Definition: cntrlc.cc:363
VAR volatile BOOLEAN do_shutdown
Definition: cntrlc.cc:74
VAR short si_restart
Definition: cntrlc.cc:94
#define INTERACTIVE
Definition: cntrlc.cc:50
void sig_term_hdl(int)
Definition: cntrlc.cc:77
#define STACK_TRACE
Definition: cntrlc.cc:51
VAR volatile int defer_shutdown
Definition: cntrlc.cc:75
VAR int sigint_handler_cnt
Definition: cntrlc.cc:265
void sigint_handler(int)
Definition: cntrlc.cc:266
void(* si_hdl_typ)(int)
Definition: cntrlc.cc:96
void sigsegv_handler(int sig)
Definition: cntrlc.cc:234
VAR int siRandomStart
Definition: cntrlc.cc:93
static void debug_stop(char *const *args)
Definition: cntrlc.cc:421
void init_signals()
init signal handlers and error handling for libraries: NTL, factory
Definition: cntrlc.cc:527
const CanonicalForm int s
Definition: facAbsFact.cc:51
void WerrorS(const char *s)
Definition: feFopen.cc:24
static void * feOptValue(feOptIndex opt)
Definition: feOpt.h:40
EXTERN_VAR struct fe_option feOptSpec[]
Definition: feOpt.h:17
VAR char my_yylinebuf[80]
Definition: febase.cc:44
if(!FE_OPT_NO_SHELL_FLAG)(void) system(sys)
VAR BOOLEAN fe_is_raw_tty
Definition: fereadl.c:72
void fe_temp_reset(void)
Definition: fereadl.c:110
VAR Voice * currentVoice
Definition: fevoices.cc:49
void VoiceBackTrack()
Definition: fevoices.cc:77
Voice * feInitStdin(Voice *pp)
Definition: fevoices.cc:677
const char * Tok2Cmdname(int tok)
Definition: gentable.cc:140
#define VAR
Definition: globaldefs.h:5
VAR int iiOp
Definition: iparith.cc:222
This file provides miscellaneous functionality.
#define SINGULAR_VERSION
Definition: mod2.h:87
int dReportError(const char *fmt,...)
Definition: dError.cc:44
void m2_end(int i)
Definition: misc_ip.cc:1097
#define NULL
Definition: omList.c:12
VAR BOOLEAN siCntrlc
Definition: options.c:14
static int index(p_Length length, p_Ord ord)
Definition: p_Procs_Impl.h:592
#define mflush()
Definition: reporter.h:58
void my_yy_flush()
Definition: scanner.cc:2318
int status int void * buf
Definition: si_signals.h:59
#define si_siginterrupt(arg1, arg2)
#define loop
Definition: structs.h:75