source: git/Singular/cntrlc.cc @ c90500

spielwiese
Last change on this file since c90500 was 32cb7a, checked in by Hans Schoenemann <hannes@…>, 12 years ago
chg: handling of cntrl-c (from master: --cntrlc=?)
  • Property mode set to 100644
File size: 15.6 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT - interupt handling
6*/
7
8/* includes */
9#ifdef DecAlpha_OSF1
10#define _XOPEN_SOURCE_EXTENDED
11#endif /* MP3-Y2 0.022UF */
12
13#include <stdio.h>
14#include <stddef.h>
15#include <stdlib.h>
16#include <strings.h>
17#include <signal.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20
21#include "config.h"
22#include <kernel/mod2.h>
23#include <omalloc/omalloc.h>
24
25#include <kernel/polys.h>
26#include <kernel/febase.h>
27
28#include "tok.h"
29#include "ipshell.h"
30#include "cntrlc.h"
31#include "feOpt.h"
32#include "version.h"
33#include "silink.h"
34
35/* undef, if you don't want GDB to come up on error */
36
37#if !defined(__alpha)
38#define CALL_GDB
39#endif
40
41#if defined(__OPTIMIZE__) && defined(CALL_GDB)
42#undef CALL_GDB
43#endif
44
45#if defined(unix) && !defined(hpux)
46 #include <unistd.h>
47 #include <sys/types.h>
48
49 #ifdef TIME_WITH_SYS_TIME
50   #include <time.h>
51   #ifdef HAVE_SYS_TIME_H
52     #include <sys/time.h>
53   #endif
54 #else
55   #ifdef HAVE_SYS_TIME_H
56     #include <sys/time.h>
57   #else
58     #include <time.h>
59   #endif
60 #endif
61 #ifdef HAVE_SYS_TIMES_H
62   #include <sys/times.h>
63 #endif
64
65 #define INTERACTIVE 0
66 #define STACK_TRACE 1
67
68 #ifdef CALL_GDB
69   static void debug (int);
70   static void debug_stop (char *const*args);
71 #endif
72 #ifndef __OPTIMIZE__
73   static void stack_trace_sigchld (int);
74   static void stack_trace (char *const*args);
75 #endif
76#endif
77
78si_link pipeLastLink=NULL;
79BOOLEAN singular_in_batchmode=FALSE;
80
81void sig_pipe_hdl(int sig)
82{
83 if (pipeLastLink!=NULL)
84 {
85   slClose(pipeLastLink);
86   pipeLastLink=NULL;
87   WerrorS("pipe failed");
88 }
89}
90
91void sig_term_hdl(int sig)
92{
93 while (ssiToBeClosed!=NULL)
94 {
95   slClose(ssiToBeClosed->l);
96   if (ssiToBeClosed==NULL) break;
97   ssiToBeClosed=(link_list)ssiToBeClosed->next;
98 }
99 exit(1);
100}
101
102/*---------------------------------------------------------------------*
103 * File scope Variables (Variables share by several functions in
104 *                       the same file )
105 *
106 *---------------------------------------------------------------------*/
107/* data */
108jmp_buf si_start_jmpbuf;
109int siRandomStart;
110short si_restart=0;
111BOOLEAN siCntrlc = FALSE;
112
113typedef void (*si_hdl_typ)(int);
114
115
116/*0 implementation*/
117/*---------------------------------------------------------------------*
118 * Functions declarations
119 *
120 *---------------------------------------------------------------------*/
121void sigint_handler(int sig);
122
123si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler);
124
125/*---------------------------------------------------------------------*/
126/**
127 * @brief meta function for binding a signal to an handler
128
129 @param[in] sig             Signal number
130 @param[in] signal_handler  Pointer to signal handler
131
132 @return value of signal()
133**/
134/*---------------------------------------------------------------------*/
135si_hdl_typ si_set_signal ( int sig, si_hdl_typ signal_handler)
136{
137  si_hdl_typ retval=signal (sig, (si_hdl_typ)signal_handler);
138  if (retval == SIG_ERR)
139  {
140     fprintf(stderr, "Unable to init signal %d ... exiting...\n", sig);
141  }
142#ifdef HAVE_SIGINTERRUPT
143  siginterrupt(sig, 1);
144#endif
145  return retval;
146}                               /* si_set_signal */
147
148
149/*---------------------------------------------------------------------*/
150#if defined(ix86_Linux)
151  #if !defined(HAVE_SIGCONTEXT) && !defined(HAVE_ASM_SIGCONTEXT_H)
152// we need the following structure sigcontext_struct.
153// if configure finds asm/singcontext.h we assume
154// that this file contains the structure and is included
155// via signal.h
156struct sigcontext_struct {
157        unsigned short gs, __gsh;
158        unsigned short fs, __fsh;
159        unsigned short es, __esh;
160        unsigned short ds, __dsh;
161        unsigned long edi;
162        unsigned long esi;
163        unsigned long ebp;
164        unsigned long esp;
165        unsigned long ebx;
166        unsigned long edx;
167        unsigned long ecx;
168        unsigned long eax;
169        unsigned long trapno;
170        unsigned long err;
171        unsigned long eip;
172        unsigned short cs, __csh;
173        unsigned long eflags;
174        unsigned long esp_at_signal;
175        unsigned short ss, __ssh;
176        unsigned long i387;
177        unsigned long oldmask;
178        unsigned long cr2;
179};
180#endif
181#define HAVE_SIGSTRUCT
182typedef struct sigcontext_struct sigcontext;
183#endif
184
185#if defined(x86_64_Linux)
186#define HAVE_SIGSTRUCT
187#endif
188
189
190#if defined(HAVE_SIGSTRUCT)
191/*2---------------------------------------------------------------------*/
192/**
193 * @brief signal handler for run time errors, linux/i386, x86_64 version
194
195 @param[in] sig
196 @param[in] s
197**/
198/*---------------------------------------------------------------------*/
199void sigsegv_handler(int sig, sigcontext s)
200{
201  fprintf(stderr,"Singular : signal %d (v: %d/%s):\n",sig,SINGULAR_VERSION,feVersionId);
202  if (sig!=SIGINT)
203  {
204    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
205    fprintf(stderr,"Segment fault/Bus error occurred at %lx because of %lx (r:%d)\n"
206                   "please inform the authors\n",
207                   #ifdef __i386__
208                   (long)s.eip,
209                   #else /* x86_64*/
210                   (long)s.rip,
211                   #endif
212                   (long)s.cr2,siRandomStart);
213  }
214#ifdef __OPTIMIZE__
215  if(si_restart<3)
216  {
217    si_restart++;
218    fprintf(stderr,"trying to restart...\n");
219    init_signals();
220    longjmp(si_start_jmpbuf,1);
221  }
222#endif /* __OPTIMIZE__ */
223#ifdef CALL_GDB
224  if (sig!=SIGINT)
225  {
226    if (singular_in_batchmode) debug(STACK_TRACE);
227    else                       debug(INTERACTIVE);
228  }
229#endif /* CALL_GDB */
230  exit(0);
231}
232
233/*2
234* init signal handlers, linux/i386 version
235*/
236void init_signals()
237{
238/*4 signal handler: linux*/
239  if (SIG_ERR==si_set_signal(SIGSEGV,(si_hdl_typ)sigsegv_handler))
240  {
241    PrintS("cannot set signal handler for SEGV\n");
242  }
243  if (SIG_ERR==si_set_signal(SIGFPE, (si_hdl_typ)sigsegv_handler))
244  {
245    PrintS("cannot set signal handler for FPE\n");
246  }
247  if (SIG_ERR==si_set_signal(SIGILL, (si_hdl_typ)sigsegv_handler))
248  {
249    PrintS("cannot set signal handler for ILL\n");
250  }
251  if (SIG_ERR==si_set_signal(SIGIOT, (si_hdl_typ)sigsegv_handler))
252  {
253    PrintS("cannot set signal handler for IOT\n");
254  }
255  if (SIG_ERR==si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler))
256  {
257    PrintS("cannot set signal handler for INT\n");
258  }
259  si_set_signal(SIGCHLD, (si_hdl_typ)sig_chld_hdl);
260  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
261  si_set_signal(SIGTERM, (si_hdl_typ)sig_term_hdl);
262}
263
264/*---------------------------------------------------------------------*/
265#elif defined(SunOS) /*SPARC_SUNOS*/
266/*2
267* signal handler for run time errors, sparc sunos 4 version
268*/
269void sigsegv_handler(int sig, int code, struct sigcontext *scp, char *addr)
270{
271  fprintf(stderr,"Singular : signal %d, code %d (v: %d/%s):\n",
272    sig,code,SINGULAR_VERSION,feVersionId);
273  if ((sig!=SIGINT)&&(sig!=SIGABRT))
274  {
275    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
276    fprintf(stderr,"Segment fault/Bus error occurred at %x (r:%d)\n"
277                   "please inform the authors\n",
278                   (int)addr,siRandomStart);
279  }
280#ifdef __OPTIMIZE__
281  if(si_restart<3)
282  {
283    si_restart++;
284    fprintf(stderr,"trying to restart...\n");
285    init_signals();
286    longjmp(si_start_jmpbuf,1);
287  }
288#endif /* __OPTIMIZE__ */
289#ifdef CALL_GDB
290  if (sig!=SIGINT) debug(STACK_TRACE);
291#endif /* CALL_GDB */
292  exit(0);
293}
294
295/*2
296* init signal handlers, sparc sunos 4 version
297*/
298void init_signals()
299{
300/*4 signal handler:*/
301  si_set_signal(SIGSEGV,sigsegv_handler);
302  si_set_signal(SIGBUS, sigsegv_handler);
303  si_set_signal(SIGFPE, sigsegv_handler);
304  si_set_signal(SIGILL, sigsegv_handler);
305  si_set_signal(SIGIOT, sigsegv_handler);
306  si_set_signal(SIGINT ,sigint_handler);
307  si_set_signal(SIGCHLD, (void (*)(int))SIG_IGN);
308  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
309}
310#else
311
312/*---------------------------------------------------------------------*/
313/*2
314* signal handler for run time errors, general version
315*/
316void sigsegv_handler(int sig)
317{
318  fprintf(stderr,"Singular : signal %d (v: %d/%s):\n",
319    sig,SINGULAR_VERSION,feVersionId);
320  if (sig!=SIGINT)
321  {
322    fprintf(stderr,"current line:>>%s<<\n",my_yylinebuf);
323    fprintf(stderr,"Segment fault/Bus error occurred (r:%d)\n"
324                   "please inform the authors\n",
325                   siRandomStart);
326  }
327  #ifdef __OPTIMIZE__
328  if(si_restart<3)
329  {
330    si_restart++;
331    fprintf(stderr,"trying to restart...\n");
332    init_signals();
333    longjmp(si_start_jmpbuf,1);
334  }
335  #endif /* __OPTIMIZE__ */
336  #if defined(unix) && !defined(hpux)
337  /* debug(..) does not work under HPUX (because ptrace does not work..) */
338  #ifdef CALL_GDB
339  if (sig!=SIGINT) debug(STACK_TRACE);
340  #endif /* CALL_GDB */
341  #endif /* unix */
342  exit(0);
343}
344
345/*2
346* init signal handlers, general version
347*/
348void init_signals()
349{
350/*4 signal handler:*/
351  si_set_signal(SIGSEGV,(void (*) (int))sigsegv_handler);
352  #ifdef SIGBUS
353  si_set_signal(SIGBUS, sigsegv_handler);
354  #endif /* SIGBUS */
355  #ifdef SIGFPE
356  si_set_signal(SIGFPE, sigsegv_handler);
357  #endif /* SIGFPE */
358  #ifdef SIGILL
359  si_set_signal(SIGILL, sigsegv_handler);
360  #endif /* SIGILL */
361  #ifdef SIGIOT
362  si_set_signal(SIGIOT, sigsegv_handler);
363  #endif /* SIGIOT */
364  #ifdef SIGXCPU
365  si_set_signal(SIGXCPU, (void (*)(int))SIG_IGN);
366  #endif /* SIGIOT */
367  si_set_signal(SIGINT ,sigint_handler);
368  #if defined(HPUX_9) || defined(HPUX_10)
369  si_set_signal(SIGCHLD, (void (*)(int))SIG_IGN);
370  #endif
371  si_set_signal(SIGPIPE, (si_hdl_typ)sig_pipe_hdl);
372}
373#endif
374
375/*2
376* signal handler for SIGINT
377*/
378int sigint_handler_cnt=0;
379void sigint_handler(int sig)
380{
381  mflush();
382  #ifdef HAVE_FEREAD
383  if (fe_is_raw_tty) fe_temp_reset();
384  #endif /* HAVE_FEREAD */
385  char default_opt=' ';
386  if ((feOptSpec[FE_OPT_CNTRLC].value!=NULL)
387      && ((char*)(feOptSpec[FE_OPT_CNTRLC].value))[0])
388  { default_opt=((char*)(feOptSpec[FE_OPT_CNTRLC].value))[0]; }
389  loop
390  {
391    int cnt=0;
392    int c;
393
394    if (singular_in_batchmode)
395    {
396      c = 'q';
397    }
398    else if (default_opt!=' ')
399    {
400      c = default_opt;
401    }
402    else
403    {
404      fprintf(stderr,"// ** Interrupt at cmd:`%s` in line:'%s'\n",
405        Tok2Cmdname(iiOp),my_yylinebuf);
406      if (feGetOptValue(FE_OPT_EMACS) == NULL)
407      {
408        fputs("abort after this command(a), abort immediately(r), print backtrace(b), continue(c) or quit Singular(q) ?",stderr);fflush(stderr);
409        c = fgetc(stdin);
410      }
411      else
412      {
413        c = 'a';
414      }
415    }
416
417    switch(c)
418    {
419      case 'q': case EOF:
420                m2_end(2);
421      case 'r':
422                if (sigint_handler_cnt<3)
423                {
424                  sigint_handler_cnt++;
425                  fputs("** Warning: Singular should be restarted as soon as possible **\n",stderr);
426                  fflush(stderr);
427                  longjmp(si_start_jmpbuf,1);
428                }
429                else
430                {
431                  fputs("** tried too often, try another possibility **\n",stderr);
432                  fflush(stderr);
433                }
434                break;
435      case 'b':
436                VoiceBackTrack();
437                break;
438      case 'a':
439                siCntrlc++;
440      case 'c':
441                if ((feGetOptValue(FE_OPT_EMACS) == NULL) && (default_opt!=' '))
442                {
443                  /* Read until a newline or EOF */
444                  while (c != EOF && c != '\n') c = fgetc(stdin);
445                }
446                si_set_signal(SIGINT ,(si_hdl_typ)sigint_handler);
447                return;
448                //siCntrlc ++;
449                //if (siCntrlc>2) si_set_signal(SIGINT,(si_hdl_typ) sigsegv_handler);
450                //else            si_set_signal(SIGINT,(si_hdl_typ) sigint_handler);
451    }
452    cnt++;
453    if(cnt>5) m2_end(2);
454  }
455}
456
457//void test_int()
458//{
459//  if (siCntrlc!=0)
460//  {
461//    int saveecho = si_echo;
462//    siCntrlc = FALSE;
463//    si_set_signal(SIGINT ,sigint_handler);
464//    iiDebug();
465//    si_echo = saveecho;
466//  }
467//}
468
469#ifdef unix
470# ifndef hpux
471#  ifndef __OPTIMIZE__
472int si_stop_stack_trace_x;
473#    ifdef CALL_GDB
474static void debug (int method)
475{
476  if (feOptValue(FE_OPT_NO_TTY))
477  {
478    dReportError("Caught Signal 11");
479    return;
480  }
481  int pid;
482  char buf[16];
483  char * args[4] = { (char*)"gdb", (char*)"Singularg", NULL, NULL };
484
485  #ifdef HAVE_FEREAD
486  if (fe_is_raw_tty) fe_temp_reset();
487  #endif /* HAVE_FEREAD */
488
489  sprintf (buf, "%d", getpid ());
490
491  args[2] = buf;
492
493  pid = fork ();
494  if (pid == 0)
495  {
496    switch (method)
497    {
498      case INTERACTIVE:
499        fprintf (stderr, "debug_stop\n");
500        debug_stop (args);
501        break;
502      #ifndef __OPTIMIZE__
503      case STACK_TRACE:
504        fprintf (stderr, "stack_trace\n");
505        stack_trace (args);
506        break;
507      #endif
508      default:
509        // should not be reached:
510        exit(1);
511    }
512  }
513  else if (pid == -1)
514  {
515    perror ("could not fork");
516    return;
517  }
518
519  si_stop_stack_trace_x = 1;
520  while (si_stop_stack_trace_x) ;
521}
522
523static void debug_stop (char *const*args)
524{
525  execvp (args[0], args);
526  perror ("exec failed");
527  _exit (0);
528}
529#    endif /* CALL_GDB */
530
531static int stack_trace_done;
532
533static void stack_trace (char *const*args)
534{
535  int pid;
536  int in_fd[2];
537  int out_fd[2];
538  fd_set fdset;
539  fd_set readset;
540  struct timeval tv;
541  int sel, index, state;
542  char buffer[256];
543  char c;
544
545  stack_trace_done = 0;
546
547  signal (SIGCHLD, stack_trace_sigchld);
548
549  if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
550  {
551    perror ("could open pipe");
552    m2_end(999);
553  }
554
555  pid = fork ();
556  if (pid == 0)
557  {
558    close (0); dup2 (in_fd[0],0);   /* set the stdin to the in pipe */
559    close (1); dup2 (out_fd[1],1);  /* set the stdout to the out pipe */
560    close (2); dup2 (out_fd[1],2);  /* set the stderr to the out pipe */
561
562    execvp (args[0], args);      /* exec gdb */
563    perror ("exec failed");
564    m2_end(999);
565  }
566  else if (pid == -1)
567  {
568    perror ("could not fork");
569    m2_end(999);
570  }
571
572  FD_ZERO (&fdset);
573  FD_SET (out_fd[0], &fdset);
574
575  write (in_fd[1], "backtrace\n", 10);
576  write (in_fd[1], "p si_stop_stack_trace_x = 0\n", 28);
577  write (in_fd[1], "quit\n", 5);
578
579  index = 0;
580  state = 0;
581
582  loop
583  {
584    readset = fdset;
585    tv.tv_sec = 1;
586    tv.tv_usec = 0;
587
588#    ifdef hpux
589    sel = select (FD_SETSIZE, (int *)readset.fds_bits, NULL, NULL, &tv);
590#    else /* hpux */
591    sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
592#    endif /* hpux */
593    if (sel == -1)
594      break;
595
596    if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
597    {
598      if (read (out_fd[0], &c, 1))
599      {
600        switch (state)
601        {
602          case 0:
603            if (c == '#')
604            {
605              state = 1;
606              index = 0;
607              buffer[index++] = c;
608            }
609            break;
610          case 1:
611            buffer[index++] = c;
612            if ((c == '\n') || (c == '\r'))
613            {
614              buffer[index] = 0;
615              fprintf (stderr, "%s", buffer);
616              state = 0;
617              index = 0;
618            }
619            break;
620          default:
621            break;
622        }
623      }
624    }
625    else if (stack_trace_done)
626      break;
627  }
628
629  close (in_fd[0]);
630  close (in_fd[1]);
631  close (out_fd[0]);
632  close (out_fd[1]);
633  m2_end(0);
634}
635
636static void stack_trace_sigchld (int signum)
637{
638  stack_trace_done = 1;
639}
640
641#  endif /* !__OPTIMIZE__ */
642# endif /* !hpux */
643#endif /* unix */
644
645/* Under HPUX 9, system(...) returns -1 if SIGCHLD does not equal
646   SIG_DFL. However, if it stays at SIG_DFL we get zombie processes
647   for terminated childs generated by fork. Therefors some special treatment
648   is necessary */
649#ifdef HPUX_9
650# undef system
651extern "C" {
652  int  hpux9_system(const char* call)
653  {
654    int ret;
655    si_set_signal(SIGCHLD, (void (*)(int))SIG_DFL);
656    ret = system(call);
657    si_set_signal(SIGCHLD, (void (*)(int))SIG_IGN);
658    return ret;
659  }
660}
661#endif /* HPUX_9 */
Note: See TracBrowser for help on using the repository browser.