/* * 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. */ #ifndef CXX_SIGNAL_H #define CXX_SIGNAL_H #pragma interface #include #include #include #include /* The class Signal is a C++ interface to the POSIX signal facility of the operating system. Any Signal object is assigned a signal that does not change during the lifetime of the object. All manipulations to the signal that are performed via the Signal object (installation of a handler, ignoring and blocking) are undone when the Signal object is deleted. When a handler is installed it will not be called directly by the operating system, but by a static handler, that will eventually call other handlers registered for the signal. This depends upon the return value passed by the handler function. When a handler function returns zero (0) the next handler for the signal is called, otherwhise the control is given back to the interupted process. Thus signal handlers form a chain (for each signal) where the last registered handler is called first. When a Signal class is dynamically allocated (Signal D), deletion of that Signal object will affect the current behaviour of the process (like signal mask etc.) only if it is the first Signal object on the chain. Otherwhise, the Signal object on top of the deleated Signal (Signal E) is instructed to restore the state that was valid before Signal D was created. */ class Signal { public: enum { f_block = 0x0001, f_ignore = 0x0004, f_disable = f_block | f_ignore, f_restart = 0x0008, f_nocldstop = 0x0010, f_all = -1, }; typedef int (*handler_t)(Signal &); const handler_t default_handler = (handler_t)SIG_DFL; public: Signal(int sig, handler_t hdl = NULL, int flags = 0, int mask = 0); Signal(const Signal&); virtual ~Signal(); int signal() { return _signal; } int flags(int flags, int mask); // set the flags (and return old) handler_t handler(handler_t); // set the handler (and return old) void raise() { ::raise(_signal); } void raise(pid_t pid) { kill(pid, _signal); } // The signal may be blocked in which case a raised signal is kept // pending until it is again unblocked. An ignored signal is discarded // once it is raised and is thus never pending. bool block(bool f = true); bool unblock(bool f = true); bool isblocked() const; bool isunblocked() const; bool ispending() const; void discard(); bool ignore(bool f = true); bool obey(bool f = true); bool isignored() const; bool isobeyed() const; // On BSD systems you can sepcify whether interrupted system calls // should be restarted after return of the signal handler. bool restart_syscalls(bool f = true); bool interrupt_syscalls(bool f = true); bool syscalls_restarted() const; bool syscalls_interrupted() const; // For SIGCHLD only: // normally SIGCHILD is raised when the child is stopped, with // ignore_child_stop(true) SIGCHLD is raised only when the child // exits. bool ignore_child_stop(bool f = true); bool signal_child_stop(bool f = true); bool child_stop_ignored() const; bool child_stop_signaled() const; private: int _signal; handler_t _handler; int _flags; int _orig_flags; handler_t _orig_handler; Signal *_next; Signal *_predecessor; static class Signal *_signals[NSIG]; static void superhandler(int); // non local jump support public: struct JmpBuf { jmp_buf jb; }; JmpBuf &__jmp_buf(); # define atSignal(Signal)\ if( ({\ bool b = (Signal).block();\ int r = setjmp((jmp_buf)&(Signal).__jmp_buf());\ (Signal).block(b); r;\ }) != 0 ) private: // non local jumps require a bit of extra work JmpBuf _jmp_buf; Signal *_jmp_pred; Signal *_jmp_succ; static class Signal *_jmp_signal[NSIG]; static int longjmphandler(Signal &); private: const Signal &operator=(const Signal&); }; // INLINE inline bool Signal::ignore(bool f) { if(f) return flags(f_ignore, 0) & f_ignore; else return flags(0, f_ignore) & f_ignore; } inline bool Signal::obey(bool f) { if(f) return !( flags(0, f_ignore) & f_ignore ); else return !( flags(f_ignore, 0) & f_ignore ); } inline bool Signal::isignored() const { return _flags & f_ignore; } inline bool Signal::isobeyed() const { return !( _flags & f_ignore ); } inline bool Signal::block(bool f) { if(f) return flags(f_block, 0) & f_block; else return flags(0, f_block) & f_block; } inline bool Signal::unblock(bool f) { if(f) return !( flags(0, f_block) & f_block ); else return !( flags(f_block, 0) & f_block ); } inline bool Signal::isblocked() const { return _flags & f_block; } inline bool Signal::isunblocked() const { return !( _flags & f_block ); } inline bool Signal::restart_syscalls(bool f) { if(f) return flags(f_restart, 0) & f_restart; else return flags(0, f_restart) & f_restart; } inline bool Signal::interrupt_syscalls(bool f) { if(f) return !( flags(0, f_restart) & f_restart ); else return !( flags(f_restart, 0) & f_restart ); } inline bool Signal::syscalls_restarted() const { return _flags & f_restart; } inline bool Signal::syscalls_interrupted() const { return !(_flags & f_restart); } inline bool Signal::ignore_child_stop(bool f) { if(f) return flags(f_nocldstop, 0) & f_nocldstop; else return flags(0, f_nocldstop) & f_nocldstop; } inline bool Signal::signal_child_stop(bool f) { if(f) return !( flags(0, f_nocldstop) & f_nocldstop ); else return !( flags(f_nocldstop, 0) & f_nocldstop ); } inline bool Signal::child_stop_ignored() const { return _flags & f_nocldstop; } inline bool Signal::child_stop_signaled() const { return !(_flags & f_nocldstop); } #endif