/********************************************************************** signal.c - $Author$ $Date$ created at: Tue Dec 20 10:13:44 JST 1994 Copyright (C) 1993-2001 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby.h" #include "rubysig.h" #include #include #ifdef __BEOS__ #undef SIGBUS #endif #ifndef NSIG # ifdef DJGPP # define NSIG SIGMAX # else # define NSIG (_SIGMAX + 1) /* For QNX */ # endif #endif static struct signals { char *signm; int signo; } siglist [] = { #ifdef SIGHUP "HUP", SIGHUP, #endif #ifdef SIGINT "INT", SIGINT, #endif #ifdef SIGQUIT "QUIT", SIGQUIT, #endif #ifdef SIGILL "ILL", SIGILL, #endif #ifdef SIGTRAP "TRAP", SIGTRAP, #endif #ifdef SIGIOT "IOT", SIGIOT, #endif #ifdef SIGABRT "ABRT", SIGABRT, #endif #ifdef SIGEMT "EMT", SIGEMT, #endif #ifdef SIGFPE "FPE", SIGFPE, #endif #ifdef SIGKILL "KILL", SIGKILL, #endif #ifdef SIGBUS "BUS", SIGBUS, #endif #ifdef SIGSEGV "SEGV", SIGSEGV, #endif #ifdef SIGSYS "SYS", SIGSYS, #endif #ifdef SIGPIPE "PIPE", SIGPIPE, #endif #ifdef SIGALRM "ALRM", SIGALRM, #endif #ifdef SIGTERM "TERM", SIGTERM, #endif #ifdef SIGURG "URG", SIGURG, #endif #ifdef SIGSTOP "STOP", SIGSTOP, #endif #ifdef SIGTSTP "TSTP", SIGTSTP, #endif #ifdef SIGCONT "CONT", SIGCONT, #endif #ifdef SIGCHLD "CHLD", SIGCHLD, #endif #ifdef SIGCLD "CLD", SIGCLD, #else # ifdef SIGCHLD "CLD", SIGCHLD, # endif #endif #ifdef SIGTTIN "TTIN", SIGTTIN, #endif #ifdef SIGTTOU "TTOU", SIGTTOU, #endif #ifdef SIGIO "IO", SIGIO, #endif #ifdef SIGXCPU "XCPU", SIGXCPU, #endif #ifdef SIGXFSZ "XFSZ", SIGXFSZ, #endif #ifdef SIGVTALRM "VTALRM", SIGVTALRM, #endif #ifdef SIGPROF "PROF", SIGPROF, #endif #ifdef SIGWINCH "WINCH", SIGWINCH, #endif #ifdef SIGUSR1 "USR1", SIGUSR1, #endif #ifdef SIGUSR2 "USR2", SIGUSR2, #endif #ifdef SIGLOST "LOST", SIGLOST, #endif #ifdef SIGMSG "MSG", SIGMSG, #endif #ifdef SIGPWR "PWR", SIGPWR, #endif #ifdef SIGPOLL "POLL", SIGPOLL, #endif #ifdef SIGDANGER "DANGER", SIGDANGER, #endif #ifdef SIGMIGRATE "MIGRATE", SIGMIGRATE, #endif #ifdef SIGPRE "PRE", SIGPRE, #endif #ifdef SIGGRANT "GRANT", SIGGRANT, #endif #ifdef SIGRETRACT "RETRACT", SIGRETRACT, #endif #ifdef SIGSOUND "SOUND", SIGSOUND, #endif NULL, 0, }; static int signm2signo(nm) char *nm; { struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) if (strcmp(sigs->signm, nm) == 0) return sigs->signo; return 0; } static char* signo2signm(no) int no; { struct signals *sigs; for (sigs = siglist; sigs->signm; sigs++) if (sigs->signo == no) return sigs->signm; return 0; } VALUE rb_f_kill(argc, argv) int argc; VALUE *argv; { int negative = 0; int sig; int i; char *s; rb_secure(2); if (argc < 2) rb_raise(rb_eArgError, "wrong # of arguments -- kill(sig, pid...)"); switch (TYPE(argv[0])) { case T_FIXNUM: sig = FIX2INT(argv[0]); break; case T_SYMBOL: s = rb_id2name(SYM2ID(argv[0])); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; case T_STRING: { s = RSTRING(argv[0])->ptr; if (s[0] == '-') { negative++; s++; } str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; if((sig = signm2signo(s)) == 0) rb_raise(rb_eArgError, "unrecognized signal name `%s'", s); if (negative) sig = -sig; } break; default: rb_raise(rb_eArgError, "bad signal type %s", rb_class2name(CLASS_OF(argv[0]))); break; } if (sig < 0) { sig = -sig; for (i=1; i= NSIG) { rb_bug("trap_handler: Bad signal %d", sig); } #if !defined(BSD_SIGNAL) ruby_signal(sig, sighandle); #endif if (ATOMIC_TEST(rb_trap_immediate)) { IN_MAIN_CONTEXT(signal_exec, sig); ATOMIC_SET(rb_trap_immediate, 1); } else { ATOMIC_INC(rb_trap_pending); ATOMIC_INC(trap_pending_list[sig]); } } #ifdef SIGBUS static RETSIGTYPE sigbus _((int)); static RETSIGTYPE sigbus(sig) int sig; { rb_bug("Bus Error"); } #endif #ifdef SIGSEGV static RETSIGTYPE sigsegv _((int)); static RETSIGTYPE sigsegv(sig) int sig; { rb_bug("Segmentation fault"); } #endif #ifdef SIGPIPE static RETSIGTYPE sigpipe _((int)); static RETSIGTYPE sigpipe(sig) int sig; { /* do nothing */ } #endif void rb_trap_exit() { #ifndef MACOS_UNUSE_SIGNAL if (trap_list[0]) { VALUE trap_exit = trap_list[0]; trap_list[0] = 0; rb_eval_cmd(trap_exit, rb_ary_new3(1, INT2FIX(0))); } #endif } void rb_trap_exec() { #ifndef MACOS_UNUSE_SIGNAL int i; for (i=0; icmd; if (NIL_P(command)) { func = SIG_IGN; } else if (TYPE(command) == T_STRING) { SafeStr(command); /* taint check */ if (RSTRING(command)->len == 0) { func = SIG_IGN; } else if (RSTRING(command)->len == 7) { if (strncmp(RSTRING(command)->ptr, "SIG_IGN", 7) == 0) { func = SIG_IGN; } else if (strncmp(RSTRING(command)->ptr, "SIG_DFL", 7) == 0) { func = SIG_DFL; } else if (strncmp(RSTRING(command)->ptr, "DEFAULT", 7) == 0) { func = SIG_DFL; } } else if (RSTRING(command)->len == 6) { if (strncmp(RSTRING(command)->ptr, "IGNORE", 6) == 0) { func = SIG_IGN; } } else if (RSTRING(command)->len == 4) { if (strncmp(RSTRING(command)->ptr, "EXIT", 4) == 0) { func = sigexit; } } } if (func == SIG_IGN || func == SIG_DFL) { command = 0; } switch (TYPE(arg->sig)) { case T_FIXNUM: sig = NUM2INT(arg->sig); break; case T_SYMBOL: s = rb_id2name(SYM2ID(arg->sig)); if (!s) rb_raise(rb_eArgError, "bad signal"); goto str_signal; case T_STRING: s = RSTRING(arg->sig)->ptr; str_signal: if (strncmp("SIG", s, 3) == 0) s += 3; sig = signm2signo(s); if (sig == 0 && strcmp(s, "EXIT") != 0) rb_raise(rb_eArgError, "invalid signal SIG%s", s); } if (sig < 0 || sig > NSIG) { rb_raise(rb_eArgError, "invalid signal number (%d)", sig); } #if defined(HAVE_SETITIMER) && !defined(__BOW__) if (sig == SIGVTALRM) { rb_raise(rb_eArgError, "SIGVTALRM reserved for Thread; cannot set handler"); } #endif if (func == SIG_DFL) { switch (sig) { case SIGINT: #ifdef SIGHUP case SIGHUP: #endif #ifdef SIGQUIT case SIGQUIT: #endif #ifdef SIGALRM case SIGALRM: #endif #ifdef SIGUSR1 case SIGUSR1: #endif #ifdef SIGUSR2 case SIGUSR2: #endif func = sighandle; break; #ifdef SIGBUS case SIGBUS: func = sigbus; break; #endif #ifdef SIGSEGV case SIGSEGV: func = sigsegv; break; #endif #ifdef SIGPIPE case SIGPIPE: func = sigpipe; break; #endif } } ruby_signal(sig, func); old = trap_list[sig]; if (!old) old = Qnil; trap_list[sig] = command; /* enable at least specified signal. */ #if !defined(NT) #ifdef HAVE_SIGPROCMASK sigdelset(&arg->mask, sig); #else arg->mask &= ~sigmask(sig); #endif #endif return old; } #if !defined(NT) static VALUE trap_ensure(arg) struct trap_arg *arg; { /* enable interrupt */ #ifdef HAVE_SIGPROCMASK sigprocmask(SIG_SETMASK, &arg->mask, NULL); #else sigsetmask(arg->mask); #endif trap_last_mask = arg->mask; return 0; } #endif void rb_trap_restore_mask() { #if !defined(NT) # ifdef HAVE_SIGPROCMASK sigprocmask(SIG_SETMASK, &trap_last_mask, NULL); # else sigsetmask(trap_last_mask); # endif #endif } static VALUE rb_f_trap(argc, argv) int argc; VALUE *argv; { struct trap_arg arg; rb_secure(2); if (argc == 0 || argc > 2) { rb_raise(rb_eArgError, "wrong # of arguments -- trap(sig, cmd)/trap(sig){...}"); } arg.sig = argv[0]; if (argc == 1) { arg.cmd = rb_f_lambda(); } else if (argc == 2) { arg.cmd = argv[1]; } #if !defined(NT) /* disable interrupt */ # ifdef HAVE_SIGPROCMASK sigfillset(&arg.mask); sigprocmask(SIG_BLOCK, &arg.mask, &arg.mask); # else arg.mask = sigblock(~0); # endif return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg); #else return trap(&arg); #endif } void Init_signal() { #ifndef MACOS_UNUSE_SIGNAL rb_define_global_function("trap", rb_f_trap, -1); ruby_signal(SIGINT, sighandle); #ifdef SIGHUP ruby_signal(SIGHUP, sighandle); #endif #ifdef SIGQUIT ruby_signal(SIGQUIT, sighandle); #endif #ifdef SIGALRM ruby_signal(SIGALRM, sighandle); #endif #ifdef SIGUSR1 ruby_signal(SIGUSR1, sighandle); #endif #ifdef SIGUSR2 ruby_signal(SIGUSR2, sighandle); #endif #ifdef SIGBUS ruby_signal(SIGBUS, sigbus); #endif #ifdef SIGSEGV ruby_signal(SIGSEGV, sigsegv); #endif #ifdef SIGPIPE ruby_signal(SIGPIPE, sigpipe); #endif #endif /* MACOS_UNUSE_SIGNAL */ }