diff options
Diffstat (limited to 'signal.c')
-rw-r--r-- | signal.c | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/signal.c b/signal.c new file mode 100644 index 0000000000..0131941a5d --- /dev/null +++ b/signal.c @@ -0,0 +1,444 @@ +/************************************************ + + signal.c - + + $Author: matz $ + $Date: 1994/12/20 05:15:42 $ + created at: Tue Dec 20 10:13:44 JST 1994 + +************************************************/ + +#include "ruby.h" +#include <signal.h> +#include <stdio.h> + +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; +} + +VALUE +Fkill(argc, argv) + int argc; + VALUE *argv; +{ + int sig; + int i; + + if (argc < 2) + Fail("wrong # of arguments -- kill(sig, pid...)"); + switch (TYPE(argv[0])) { + case T_FIXNUM: + sig = FIX2UINT(argv[0]); + break; + + case T_STRING: + { + int negative = 0; + + char *s = RSTRING(argv[0])->ptr; + if (*s == '-') { + negative++; + s++; + } + if (strncmp("SIG", s, 3) == 0) + s += 3; + if((sig = signm2signo(s)) == 0) + Fail("Unrecognized signal name `%s'", s); + + if (negative) + sig = -sig; + } + break; + + default: + Fail("bad signal type %s", rb_class2name(CLASS_OF(argv[0]))); + break; + } + + if (sig < 0) { + sig = -sig; + for (i=1; i<argc; i++) { + int pid = NUM2INT(argv[i]); +#ifdef HAS_KILLPG + if (killpg(pid, sig) < 0) +#else + if (kill(-pid, sig) < 0) +#endif + rb_sys_fail(Qnil); + } + } + else { + for (i=1; i<argc; i++) { + Check_Type(argv[i], T_FIXNUM); + if (kill(FIX2UINT(argv[i]), sig) < 0) + rb_sys_fail(Qnil); + } + } + return INT2FIX(i-1); +} + +static VALUE trap_list[NSIG]; +#ifdef SAFE_SIGHANDLE +static int trap_pending_list[NSIG]; +int trap_pending; +static int trap_immediate; +#endif + +void +gc_mark_trap_list() +{ + int i; + + for (i=0; i<NSIG; i++) { + if (trap_list[i]) + gc_mark(trap_list[i]); + } +} + +static RETSIGTYPE +sighandle(sig) + int sig; +{ + if (sig >= NSIG || trap_list[sig] == Qnil) + Fail("trap_handler: Bad signal %d", sig); + +#ifndef HAVE_BSD_SIGNALS + signal(sig, sighandle); +#endif + +#ifdef SAFE_SIGHANDLE + if (trap_immediate) + rb_trap_eval(trap_list[sig]); + else { + trap_pending++; + trap_pending_list[sig]++; + } +#else + rb_trap_eval(trap_list[sig]); +#endif +} + +void +rb_trap_exit() +{ + if (trap_list[0]) + rb_trap_eval(trap_list[0]); +} + +#if defined(SAFE_SIGHANDLE) +rb_trap_exec() +{ + int i; + + trap_pending = 0; + for (i=0; i<NSIG; i++) { + if (trap_pending_list[i]) { + trap_pending_list[i] = 0; + rb_trap_eval(trap_list[i]); + } + } +} + +#if defined(HAVE_SYSCALL) && defined(HAVE_SYSCALL_H) +#include <syscall.h> + +#ifdef SYS_read +int +read(fd, buf, nbytes) + int fd, nbytes; + char *buf; +{ + int res; + + trap_immediate++; + res = syscall(SYS_read, fd, buf, nbytes); + trap_immediate = 0; + return res; +} +#endif /* SYS_read */ + +#ifdef SYS_wait +int +wait(status) + union wait *status; +{ + int res; + + trap_immediate++; + res = syscall(SYS_wait, status); + trap_immediate =0; + return res; +} +#endif /* SYS_wait */ + +#ifdef SYS_sigpause +int +sigpause(mask) + int mask; +{ + int res; + + trap_immediate++; + res = syscall(SYS_sigpause, mask); + trap_immediate =0; + return res; +} +#endif /* SYS_sigpause */ + +/* linux syscall(select) doesn't work file. */ +#if defined(SYS_select) && !defined(linux) +#include <sys/types.h> + +int +select(nfds, readfds, writefds, exceptfds, timeout) + int nfds; + fd_set *readfds, *writefds, *exceptfds; + struct timeval *timeout; +{ + int res; + + trap_immediate++; + res = syscall(SYS_select, nfds, readfds, writefds, exceptfds, timeout); + trap_immediate =0; + return res; +} +#endif /* SYS_select */ + +#endif /* HAVE_SYSCALL_H */ +#endif /* SAFE_SIGHANDLE */ + +static VALUE +Ftrap(argc, argv) + int argc; + VALUE *argv; +{ + RETSIGTYPE (*func)(); + VALUE command; + int i, sig; +#ifdef HAVE_SIGPROCMASK + sigset_t mask; +#else + int mask; +#endif + + if (argc < 2) + Fail("wrong # of arguments -- kill(cmd, sig...)"); + + /* disable interrupt */ +#ifdef HAVE_SIGPROCMASK + sigfillset(&mask); + sigprocmask(SIG_BLOCK, &mask, &mask); +#else + mask = sigblock(~0); +#endif + + func = sighandle; + + if (argv[0] == Qnil) { + func = SIG_IGN; + command = Qnil; + } + else { + Check_Type(argv[0], T_STRING); + command = argv[0]; + if (RSTRING(argv[0])->len == 0) { + func = SIG_IGN; + } + else if (RSTRING(argv[0])->len == 7) { + if (strncmp(RSTRING(argv[0])->ptr, "SIG_IGN", 7) == 0) { + func = SIG_IGN; + } + else if (strncmp(RSTRING(argv[0])->ptr, "SIG_DFL", 7) == 0) { + func = SIG_DFL; + } + else if (strncmp(RSTRING(argv[0])->ptr, "DEFAULT", 7) == 0) { + func = SIG_DFL; + } + } + else if (RSTRING(argv[0])->len == 6) { + if (strncmp(RSTRING(argv[0])->ptr, "IGNORE", 6) == 0) { + func = SIG_IGN; + } + } + } + if (func == SIG_IGN || func == SIG_DFL) + command = Qnil; + + for (i=1; i<argc; i++) { + if (TYPE(argv[i]) == T_STRING) { + char *s = RSTRING(argv[i])->ptr; + + if (strncmp("SIG", s, 3) == 0) + s += 3; + sig = signm2signo(s); + if (sig == 0 && strcmp(s, "EXIT") != 0) + Fail("Invalid signal SIG%s", s); + } + else { + sig = NUM2INT(argv[i]); + } + if (sig < 0 || sig > NSIG) + Fail("Invalid signal no %d", sig); + + signal(sig, sighandle); + trap_list[sig] = command; + /* enable at least specified signal. */ +#ifdef HAVE_SIGPROCMASK + sigdelset(&mask, sig); +#else + mask &= ~sigmask(sig); +#endif + } + /* disable interrupt */ +#ifdef HAVE_SIGPROCMASK + sigprocmask(SIG_SETMASK, &mask, NULL); +#else + sigsetmask(mask); +#endif + return Qnil; +} |