From: Christian P. <cp...@us...> - 2005-04-23 17:48:11
|
Update of /cvsroot/pclasses/pclasses2/src/System In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4241/src/System Modified Files: SignalListener.h SignalListener.posix.cpp Log Message: - Major updated to POSIX signal handling code Index: SignalListener.posix.cpp =================================================================== RCS file: /cvsroot/pclasses/pclasses2/src/System/SignalListener.posix.cpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- SignalListener.posix.cpp 26 Feb 2005 16:48:13 -0000 1.3 +++ SignalListener.posix.cpp 23 Apr 2005 17:48:03 -0000 1.4 @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005 by Christian Prochnow * + * Copyright (C) 2005 by Christian Prochnow, SecuLogiX GmbH * * cp...@se... * * * * This program is free software; you can redistribute it and/or modify * @@ -19,37 +19,47 @@ ***************************************************************************/ #include "pclasses/System/EventQueue.h" +#include "pclasses/CircularQueue.h" #include "SignalListener.h" #include "FdListener.h" + #include <signal.h> #include <unistd.h> #include <fcntl.h> - +#include <errno.h> + namespace P { namespace System { +// previously installed signal handlers will be saved ... +struct sigaction savedSigActions[64]; + + class SignalFdListener: public FdListener { public: SignalFdListener(int handle) - : FdListener(handle, FdListener::Read) + : FdListener(handle, FdListener::Read), _signals(64) { for(unsigned int i = 0; i < sizeof(_listeners) / sizeof(SignalListener*); i++) { _listeners[i] = 0; + savedSigActions[i].sa_flags = 0; + savedSigActions[i].sa_sigaction = 0; + savedSigActions[i].sa_handler = 0; } - System::FdListenerList& lst = - System::FdListenerList::instance(EventQueue::instance()); + FdListenerList& lst = + FdListenerList::instance(EventQueue::instance()); lst.addListener(this); } ~SignalFdListener() { - System::FdListenerList& lst = - System::FdListenerList::instance(EventQueue::instance()); + FdListenerList& lst = + FdListenerList::instance(EventQueue::instance()); lst.removeListener(this); } @@ -58,9 +68,9 @@ { if(!_instance) { - //int ret = /* unused var */ - ::pipe(_signalPipe); - // ^^^ todo??? check for error + int ret = ::pipe(_signalPipe); + if(ret != 0) + throw SystemError(errno, "Could not create pipe", P_SOURCEINFO); // make pipe nonblocking ... ::fcntl(_signalPipe[0], F_SETFL, O_NONBLOCK); @@ -72,11 +82,17 @@ return *_instance; } + /* + Adds a SignalListener to the list of handled signals + */ void addListener(int sig, SignalListener& l) { _listeners[sig] = &l; } + /* + Removes a SignalListener from the list of handled signals + */ void removeListener(SignalListener& l) { for(unsigned int i = 0; @@ -87,75 +103,107 @@ } } - void writeSignal(int sig) + /* + Queues the signal that was delivered and wakes up the + SignalFdListener ... + Note: This method is called directly from the signal handler !! + */ + void writeSignal(int sig, const sigval& sv) { - // read current pending signals ... - sigset_t sigSet; - int ret = ::read(_signalPipe[0], &sigSet, sizeof(sigset_t)); - if(ret != sizeof(sigset_t)) - sigemptyset(&sigSet); - - // add pending signal to set and write back to pipe - sigaddset(&sigSet, sig); - ::write(_signalPipe[1], &sigSet, sizeof(sigset_t)); + QueuedSig qs; + qs.sig = sig; + qs.val = sv; + _signals.push(qs); + ::write(_signalPipe[1], "W", 1); } protected: + + /* + Will be called by the FdListenerList after an event has occured + on our signal pipe. This should occur right after a signal has been + queued by a call to writeSignal(). + */ void onRead() { + // block all signals ... sigset_t blockedSet, oldSet; sigfillset(&blockedSet); sigprocmask(SIG_SETMASK, &blockedSet, &oldSet); - sigset_t sigSet; - int ret = ::read(fd(), &sigSet, sizeof(sigset_t)); - if(ret == sizeof(sigset_t)) + // deliver queued signals ... + QueuedSig qs; + while(!_signals.empty()) { - for(int i = 0; i < 64; i++) - { - if(sigismember(&sigSet, i) == 1 && _listeners[i]) - _listeners[i]->onSignal(); - } + qs = _signals.front(); + _signals.pop(); + + if(_listeners[qs.sig]) + _listeners[qs.sig]->onSignal(qs.val); } + // clear the signal pipe ... we don't want to get signaled forever + char tmp[64]; + int ret = ::read(fd(), tmp, 64); + + // restore blocked signal state ... sigprocmask(SIG_SETMASK, &oldSet, 0); } private: - SignalListener* _listeners[64]; - static int _signalPipe[2]; + struct QueuedSig { + int sig; + sigval val; + }; + + SignalListener* _listeners[64]; + CircularQueue<QueuedSig> _signals; + static int _signalPipe[2]; static SignalFdListener* _instance; }; int SignalFdListener::_signalPipe[2]; SignalFdListener* SignalFdListener::_instance = 0; -void signal_handler(int sig) +void signal_handler(int sig, siginfo_t* sigInfo, void* context) { SignalFdListener& l = SignalFdListener::instance(); - l.writeSignal(sig); + l.writeSignal(sig, sigInfo->si_value); + + // call previous signal handler ... + if(savedSigActions[sig].sa_flags & SA_SIGINFO + && savedSigActions[sig].sa_sigaction) + savedSigActions[sig].sa_sigaction(sig, sigInfo, context); + else if(savedSigActions[sig].sa_handler) + savedSigActions[sig].sa_handler(sig); } SignalListener::SignalListener(int sig) { - struct sigaction sa; - sa.sa_handler = &signal_handler; - sigfillset(&sa.sa_mask); // block all signals during signal handler's execution - sa.sa_flags = SA_RESTART; // restart system calls - - SignalFdListener& l = SignalFdListener::instance(); - l.addListener(sig, *this); - - sigaction(sig, &sa, 0); + setup(sig); } SignalListener::~SignalListener() { SignalFdListener& l = SignalFdListener::instance(); l.removeListener(*this); + + //TODO: restore previous signal handler ... } +void SignalListener::setup(int sig) +{ + struct sigaction sa; + sa.sa_sigaction = &signal_handler; + sigfillset(&sa.sa_mask); // block all signals during signal handler's execution + sa.sa_flags = SA_RESTART|SA_SIGINFO; // restart system calls, use 3 param sighandler + + SignalFdListener& l = SignalFdListener::instance(); + l.addListener(sig, *this); + sigaction(sig, &sa, &savedSigActions[sig]); } -} +} //! namespace System + +} //! namespace P Index: SignalListener.h =================================================================== RCS file: /cvsroot/pclasses/pclasses2/src/System/SignalListener.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- SignalListener.h 17 Feb 2005 14:15:18 -0000 1.1 +++ SignalListener.h 23 Apr 2005 17:48:03 -0000 1.2 @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005 by Christian Prochnow * + * Copyright (C) 2005 by Christian Prochnow, SecuLogiX GmbH * * cp...@se... * * * * This program is free software; you can redistribute it and/or modify * @@ -20,19 +20,24 @@ #ifndef P_System_SignalListener #define P_System_SignalListener - + #include "pclasses/Export.h" +#include <signal.h> namespace P { namespace System { +//! Internal signal-listener for POSIX-systems class PSYSTEM_EXPORT SignalListener { public: SignalListener(int sig); virtual ~SignalListener(); - virtual void onSignal() = 0; + virtual void onSignal(const sigval& sv) = 0; + + private: + void setup(int sig); }; } // !namespace System |