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 #ifdef HAVE_NTL
27 #include <NTL/version.h>
28 #include <NTL/tools.h>
29 #ifdef NTL_CLIENT
30 NTL_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 
71 
72 void sig_pipe_hdl(int /*sig*/)
73 {
74  if (pipeLastLink!=NULL)
75  {
78  WerrorS("pipe failed");
79  }
80 }
81 
83 VAR volatile int defer_shutdown = 0;
84 
85 void 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 */
102 VAR short si_restart=0;
103 
104 typedef void (*si_hdl_typ)(int);
105 
106 
107 /*0 implementation*/
108 /*---------------------------------------------------------------------*
109  * Functions declarations
110  *
111  *---------------------------------------------------------------------*/
112 void sigint_handler(int /*sig*/);
113 
114 si_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 /*---------------------------------------------------------------------*/
126 si_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 /*---------------------------------------------------------------------*/
171 void 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  {
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 */
210 void 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 */
242 void 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 */
274 void sigint_handler(int /*sig*/)
275 {
276  mflush();
277  #ifdef HAVE_FEREAD
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 
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",
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  {
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();
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  }
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__
370 # ifdef CALL_GDB
371 static void debug (int method)
372 {
373  if (feOptValue(FE_OPT_NO_TTY))
374  {
375  dReportError("Caught Signal 11");
376  return;
377  }
378  /* REMARK FOR NEWER LINUX SYSTEMS:
379 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)
380 
381 There are ways to workaround this:
382 
383  Run the following command as super user: echo 0| sudo tee /proc/sys/kernel/yama/ptrace_scope
384 
385  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.
386 
387  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
388 */
389  int pid;
390  char buf[16];
391  char * args[4] = { (char*)"gdb", (char*)"Singular", NULL, NULL };
392 
393  #ifdef HAVE_FEREAD
395  #endif /* HAVE_FEREAD */
396 
397  sprintf (buf, "%d", getpid ());
398 
399  args[2] = buf;
400 
401  pid = fork ();
402  if (pid == 0)
403  {
404  switch (method)
405  {
406  case INTERACTIVE:
407  fputs ("\n\nquit with \"p si_stop_stack_trace_x=0\"\n\n\n",stderr);
408  debug_stop (args);
409  break;
410  case STACK_TRACE:
411  fputs ("stack_trace\n",stderr);
412  stack_trace (args);
413  break;
414  default:
415  // should not be reached:
416  exit(1);
417  }
418  }
419  else if (pid == -1)
420  {
421  perror ("could not fork");
422  return;
423  }
424 
426  while (si_stop_stack_trace_x) ;
427 }
428 
429 static void debug_stop (char *const*args)
430 {
431  execvp (args[0], args);
432  perror ("exec failed");
433  _exit (0);
434 }
435 # endif /* CALL_GDB */
436 
437 static void stack_trace (char *const*args)
438 {
439  int pid;
440  int in_fd[2];
441  int out_fd[2];
442  fd_set fdset;
443  fd_set readset;
444  struct timeval tv;
445  int sel, index, state;
446  char buffer[256];
447  char c;
448 
449  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
450  {
451  perror ("could open pipe");
452  m2_end(999);
453  }
454 
455  pid = fork ();
456  if (pid == 0)
457  {
458  si_close (0); si_dup2 (in_fd[0],0); /* set the stdin to the in pipe */
459  si_close (1); si_dup2 (out_fd[1],1); /* set the stdout to the out pipe */
460  si_close (2); si_dup2 (out_fd[1],2); /* set the stderr to the out pipe */
461 
462  execvp (args[0], args); /* exec gdb */
463  perror ("exec failed");
464  m2_end(999);
465  }
466  else if (pid == -1)
467  {
468  perror ("could not fork");
469  m2_end(999);
470  }
471 
472  FD_ZERO (&fdset);
473  FD_SET (out_fd[0], &fdset);
474 
475  si_write (in_fd[1], "backtrace\n", 10);
476  si_write (in_fd[1], "p si_stop_stack_trace_x = 0\n", 28);
477  si_write (in_fd[1], "quit\n", 5);
478 
479  index = 0;
480  state = 0;
481 
482  loop
483  {
484  readset = fdset;
485  tv.tv_sec = 1;
486  tv.tv_usec = 0;
487 
488  sel = si_select (FD_SETSIZE, &readset, NULL, NULL, &tv);
489  if (sel == -1)
490  break;
491 
492  if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
493  {
494  if (si_read (out_fd[0], &c, 1))
495  {
496  switch (state)
497  {
498  case 0:
499  if (c == '#')
500  {
501  state = 1;
502  index = 0;
503  buffer[index++] = c;
504  }
505  break;
506  case 1:
507  buffer[index++] = c;
508  if ((c == '\n') || (c == '\r'))
509  {
510  buffer[index] = 0;
511  fputs (buffer,stderr);
512  state = 0;
513  index = 0;
514  }
515  break;
516  default:
517  break;
518  }
519  }
520  }
521  else if (si_stop_stack_trace_x==0)
522  break;
523  }
524 
525  si_close (in_fd[0]);
526  si_close (in_fd[1]);
527  si_close (out_fd[0]);
528  si_close (out_fd[1]);
529  m2_end(0);
530 }
531 
532 # endif /* !__OPTIMIZE__ */
533 
534 /// init signal handlers and error handling for libraries: NTL, factory
536 {
537 // NTL error handling (>= 9.3.0) ----------------------------------------
538 #ifdef HAVE_NTL
539 #if (((NTL_MAJOR_VERSION==9)&&(NTL_MINOR_VERSION>=3))||(NTL_MAJOR_VERSION>=10))
540  ErrorMsgCallback=WerrorS;
541  ErrorCallback=HALT;
542 #endif
543 #endif
544 
545 // signal handler -------------------------------------------------------
546  #ifdef SIGSEGV
548  #endif
549  #ifdef SIGBUS
551  #endif
552  #ifdef SIGFPE
554  #endif
555  #ifdef SIGILL
557  #endif
558  #ifdef SIGIOT
560  #endif
565 }
566 
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:69
void sig_pipe_hdl(int)
Definition: cntrlc.cc:72
VAR jmp_buf si_start_jmpbuf
Definition: cntrlc.cc:100
static void stack_trace(char *const *args)
Definition: cntrlc.cc:437
VAR BOOLEAN singular_in_batchmode
Definition: cntrlc.cc:70
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:126
VAR volatile int si_stop_stack_trace_x
Definition: cntrlc.cc:369
static void debug(int)
Definition: cntrlc.cc:371
VAR volatile BOOLEAN do_shutdown
Definition: cntrlc.cc:82
VAR short si_restart
Definition: cntrlc.cc:102
#define INTERACTIVE
Definition: cntrlc.cc:58
void sig_term_hdl(int)
Definition: cntrlc.cc:85
#define STACK_TRACE
Definition: cntrlc.cc:59
VAR volatile int defer_shutdown
Definition: cntrlc.cc:83
VAR int sigint_handler_cnt
Definition: cntrlc.cc:273
void sigint_handler(int)
Definition: cntrlc.cc:274
void(* si_hdl_typ)(int)
Definition: cntrlc.cc:104
void sigsegv_handler(int sig)
Definition: cntrlc.cc:242
VAR int siRandomStart
Definition: cntrlc.cc:101
static void debug_stop(char *const *args)
Definition: cntrlc.cc:429
void init_signals()
init signal handlers and error handling for libraries: NTL, factory
Definition: cntrlc.cc:535
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
VAR BOOLEAN fe_is_raw_tty
Definition: fereadl.c:71
void fe_temp_reset(void)
Definition: fereadl.c:109
VAR Voice * currentVoice
Definition: fevoices.cc:47
void VoiceBackTrack()
Definition: fevoices.cc:75
Voice * feInitStdin(Voice *pp)
Definition: fevoices.cc:669
const char * Tok2Cmdname(int tok)
Definition: gentable.cc:140
#define VAR
Definition: globaldefs.h:5
VAR int iiOp
Definition: iparith.cc:219
if(yy_init)
Definition: libparse.cc:1420
This file provides miscellaneous functionality.
static void HALT()
Definition: mod2.h:124
#define SINGULAR_VERSION
Definition: mod2.h:85
int dReportError(const char *fmt,...)
Definition: dError.cc:43
void m2_end(int i)
Definition: misc_ip.cc:1096
#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:2338
int status int void * buf
Definition: si_signals.h:59
#define si_siginterrupt(arg1, arg2)
#define loop
Definition: structs.h:80