/* * Copyright (c) 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #pragma implementation #ifdef PROTOGEN # include "exception.h" # include "logfile.h" #else # include # define ERROS(fmt, args...) { fprintf(stderr, fmt ": " , ## args); \ perror(""); exit(1); } # define LOGDEBUG(fmt, args...) \ { fprintf(stderr, __PRETTY_FUNCTION__ ": " fmt "\n" , ## args); } #endif #include "Signal.h" #include #include class Signal *Signal::_signals[NSIG] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #if NSIG > 16 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #endif #if NSIG > 32 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #endif #if NSIG > 64 # error NSIG exceeds any reasonable value #endif }; void Signal::superhandler(int sig) { for(Signal *s = _signals[sig]; s != NULL; s = s->_next) { if(s->_flags & f_disable) return; else if(s->_handler != NULL) if((*s->_handler)(*s) != 0) return; } return; } Signal::Signal(int sig, handler_t hdl, int flags, int mask) { _signal = sig; _jmp_succ = NULL; _jmp_pred = NULL; _predecessor = NULL; _orig_flags = 0; // BEGIN CRITICAL SECTION // block the signal for we are going to touch the chain of // Signal objects // prepare for setting the signal mask sigset_t ss, bs; sigemptyset(&bs); sigaddset(&bs, _signal); sigprocmask(SIG_BLOCK, &bs, &ss); // get the current sigaction struct sigaction sa; sigaction(_signal, NULL, &sa); // Save the current state of the signal in _orig_flags _orig_handler = (handler_t)sa.sa_handler; if(_orig_handler == (handler_t)SIG_IGN) _orig_flags |= f_ignore; if(sa.sa_flags & SA_RESTART) _orig_flags |= f_restart; if(sa.sa_flags & SA_NOCLDSTOP) _orig_flags |= f_nocldstop; if(sigismember(&ss, _signal)) _orig_flags |= f_block; // set the flags _flags = _orig_flags & ~mask | flags; // set the handler if(hdl == NULL) _handler = _orig_handler; else _handler = hdl; // set the new sigaction if(_flags & f_ignore) sa.sa_handler = (typeof(sa.sa_handler))SIG_IGN; if(_handler == default_handler) sa.sa_handler = (typeof(sa.sa_handler))SIG_DFL; else sa.sa_handler = (typeof(sa.sa_handler))superhandler; if(_flags & f_restart) sa.sa_flags |= SA_RESTART; if(_flags & f_nocldstop) sa.sa_flags |= SA_NOCLDSTOP; // install the new sigaction sigaction(_signal, &sa, NULL); // install the new Signal object in the chain _next = _signals[_signal]; _signals[_signal] = this; if(_next != NULL) _next->_predecessor = this; // END CRITICAL SECTION // unblock the signal depending on the flags if(! (_flags & f_block)) sigprocmask(SIG_UNBLOCK, &bs, NULL); } Signal::Signal(const Signal &s) { _signal = s._signal; _flags = s._flags; _handler = s._handler; _predecessor = NULL; // BEGIN CRITICAL SECTION // block the signal for we are going to touch the chain of // Signal objects // prepare for setting the signal mask sigset_t ss, bs; sigemptyset(&bs); sigaddset(&bs, _signal); sigprocmask(SIG_BLOCK, &bs, &ss); // get the current sigaction struct sigaction sa; sigaction(_signal, NULL, &sa); // Save the current state of the signal in _orig_flags _orig_handler = (handler_t)sa.sa_handler; if(_orig_handler == (handler_t)SIG_IGN) _orig_flags |= f_ignore; if(sa.sa_flags & SA_RESTART) _orig_flags |= f_restart; if(sa.sa_flags & SA_NOCLDSTOP) _orig_flags |= f_nocldstop; if(sigismember(&ss, _signal)) _orig_flags |= f_block; // set the new sigaction if(_flags & f_ignore) sa.sa_handler = (typeof(sa.sa_handler))SIG_IGN; if(_handler == default_handler) sa.sa_handler = (typeof(sa.sa_handler))SIG_DFL; else sa.sa_handler = (typeof(sa.sa_handler))superhandler; if(_flags & f_restart) sa.sa_flags |= SA_RESTART; if(_flags & f_nocldstop) sa.sa_flags |= SA_NOCLDSTOP; // install the new sigaction sigaction(_signal, &sa, NULL); // install the new Signal object in the chain _next = _signals[_signal]; _signals[_signal] = this; if(_next != NULL) _next->_predecessor = this; // install into the longjump chain if(_handler == longjmphandler) { _jmp_pred = NULL; if(_jmp_succ != NULL) _jmp_succ->_jmp_pred = this; _jmp_succ = _jmp_signal[_signal]; } else { _jmp_succ = NULL; _jmp_pred = NULL; } // END CRITICAL SECTION // unblock the signal depending on the flags if(! (_flags & f_block)) sigprocmask(SIG_UNBLOCK, &bs, NULL); } Signal::~Signal() { // BEGIN CRITICAL SECTION sigset_t ss, bs; sigemptyset(&bs); sigprocmask(SIG_BLOCK, &bs, &ss); bool block = sigismember(&ss, _signal); // remove us from the chain of longjmp links if(_jmp_succ != NULL) _jmp_succ->_jmp_pred = _jmp_pred; if(_jmp_pred != NULL) _jmp_pred->_jmp_succ = _jmp_succ; else _jmp_signal[_signal] = _jmp_succ; // remove us from the chain of Signal objects if(_next != NULL) _next->_predecessor = _predecessor; if(_predecessor != NULL) // we are in the middle of the chain { // write our original values to our predecessor _predecessor->_next = _next; _predecessor->_orig_flags = _orig_flags; _predecessor->_orig_handler = _orig_handler; } else // i.e. we are the first on the chain { // restore original settings _signals[_signal] = _next; struct sigaction sa; sigaction(_signal, NULL, &sa); if(_orig_flags & f_ignore) sa.sa_handler = (typeof(sa.sa_handler))SIG_IGN; else sa.sa_handler = (typeof(sa.sa_handler))_orig_handler; if(_orig_flags & f_restart) sa.sa_flags |= SA_RESTART; if(_orig_flags & f_nocldstop) sa.sa_flags |= SA_NOCLDSTOP; sigaction(_signal, &sa, NULL); block = _orig_flags & f_block; } // END CRITICAL SECTION // unblock the signal depending on the block value if(! block) sigprocmask(SIG_UNBLOCK, &bs, NULL); } int Signal::flags(int flags, int mask) { // BEGIN CRITICAL SECTION // block the signal for we are going to modify the Signal object // prepare for setting the signal mask sigset_t ss, bs; sigemptyset(&bs); sigaddset(&bs, _signal); sigprocmask(SIG_BLOCK, &bs, &ss); // set the flags int old_flags = _flags; _flags = _flags & ~mask | flags; // set the new sigaction struct sigaction sa; sigaction(_signal, NULL, &sa); if(_flags & f_ignore) sa.sa_handler = (typeof(sa.sa_handler))SIG_IGN; if(_handler == default_handler) sa.sa_handler = (typeof(sa.sa_handler))SIG_DFL; else sa.sa_handler = (typeof(sa.sa_handler))superhandler; if(_flags & f_restart) sa.sa_flags |= SA_RESTART; if(_flags & f_nocldstop) sa.sa_flags |= SA_NOCLDSTOP; // install the new sigaction sigaction(_signal, &sa, NULL); // END CRITICAL SECTION // unblock the signal depending on the flags if(! (_flags & f_block)) sigprocmask(SIG_UNBLOCK, &bs, NULL); return old_flags; } Signal::handler_t Signal::handler(handler_t hdl) // set a handler { // BEGIN CRITICAL SECTION // block the signal for we are going to touch the chain of // Signal objects // prepare for setting the signal mask sigset_t bs; sigemptyset(&bs); sigaddset(&bs, _signal); sigprocmask(SIG_BLOCK, &bs, NULL); // remove us from the chain of jump links if necessary if(_handler == longjmphandler && hdl != longjmphandler) { if(_jmp_succ != NULL) _jmp_succ->_jmp_pred = _jmp_pred; if(_jmp_pred != NULL) _jmp_pred->_jmp_succ = _jmp_succ; else _jmp_signal[_signal] = _jmp_succ; _jmp_succ = NULL; _jmp_pred = NULL; } // set the handler handler_t old_handler = _handler; if(hdl == NULL) _handler = _orig_handler; else _handler = hdl; // set the new sigaction struct sigaction sa; sigaction(_signal, NULL, &sa); if(_flags & f_ignore) sa.sa_handler = (typeof(sa.sa_handler))SIG_IGN; if(_handler == default_handler) sa.sa_handler = (typeof(sa.sa_handler))SIG_DFL; else sa.sa_handler = (typeof(sa.sa_handler))superhandler; // install the new sigaction sigaction(_signal, &sa, NULL); // END CRITICAL SECTION // unblock the signal depending on the flags if(! (_flags & f_block)) sigprocmask(SIG_UNBLOCK, &bs, NULL); return old_handler; } bool Signal::ispending() const // is the signal pending? { sigset_t ss; sigpending(&ss); return sigismember(&ss, _signal); } void Signal::discard() // discard the pending signal { if(ispending()) { ignore(); obey(); } } /********************************************************************** * non local jump stuff **********************************************************************/ class Signal *Signal::_jmp_signal[NSIG] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #if NSIG > 16 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #endif #if NSIG > 32 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #endif #if NSIG > 64 # error NSIG exceeds any reasonable value #endif }; int Signal::longjmphandler(Signal &s) // longjmp to the current JmpBuf { longjmp((jmp_buf)&s._jmp_buf, 1); return 0; // NO! } Signal::JmpBuf &Signal::__jmp_buf() { if(_handler == longjmphandler) // if already in jmp chain { // log off jmp links if(_jmp_succ != NULL) _jmp_succ->_jmp_pred = _jmp_pred; if(_jmp_pred != NULL) _jmp_pred->_jmp_succ = _jmp_succ; else _jmp_signal[_signal] = _jmp_succ; } else handler(longjmphandler); _jmp_succ = _jmp_signal[_signal]; _jmp_signal[_signal] = this; _jmp_pred = NULL; if(_jmp_succ != NULL) _jmp_succ->_jmp_pred = this; return _jmp_buf; }