From: Christian P. <cp...@us...> - 2005-04-23 18:01:16
|
Update of /cvsroot/pclasses/pclasses2/src/System In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9521/src/System Added Files: Timer.posix.cpp Log Message: Since we now have the cool signal-handling code, it makes this Timer possible! --- NEW FILE: Timer.posix.cpp --- /*************************************************************************** * Copyright (C) 2005 by Christian Prochnow * * cp...@se... * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pclasses/System/Timer.h" #include "pclasses/System/EventQueue.h" #include "../System/SignalListener.h" #include <signal.h> #include <time.h> #include <errno.h> namespace P { namespace System { class Timer::Handle: public EventListener { public: Handle(EventQueue& evq, Timer* t) : EventListener(evq, t), timer(t), armed(false) { setup(); } Handle(Timer* t) : EventListener(t), timer(t), armed(false) { setup(); } ~Handle() { timer_delete(timerId); } void signaled(const Event& ev) { Timer* tmr = (Timer*)ev.sender(); tmr->sigExpired.fire(); tmr->expired(); } void setup() { sigevent se; se.sigev_notify = SIGEV_SIGNAL; se.sigev_signo = SIGALRM; se.sigev_value.sival_ptr = timer; if(timer_create(CLOCK_REALTIME, &se, &timerId) != 0) throw SystemError(errno, "Could not create timer", P_SOURCEINFO); } Timer* timer; bool armed; bool singleShot; timer_t timerId; }; class TimerSignalHandler: public System::SignalListener { public: TimerSignalHandler() : SignalListener(SIGALRM) { } void onSignal(const sigval& sv) { Timer::Handle* timer = 0; CriticalSection::ScopedLock lck(_timersCs); std::list<Timer::Handle*>::iterator i = _timers.begin(); while(i != _timers.end()) { timer = *i; if(timer->timer == sv.sival_ptr) { if(timer->singleShot) timer->armed = false; // we post this Event since signals are always handled by the // main-thread, and the EventListener may use a EventQueue // that runs in another thread... timer->eventQueue().post(Event(timer->sender(), 0)); } ++i; } } void add(Timer::Handle* timer) { CriticalSection::ScopedLock lck(_timersCs); _timers.push_back(timer); } void remove(Timer::Handle* timer) { CriticalSection::ScopedLock lck(_timersCs); std::list<Timer::Handle*>::iterator i = _timers.begin(); while(i != _timers.end()) { if(*i == timer) { _timers.erase(i); break; } ++i; } } static TimerSignalHandler& instance() { if(!_instance) { static CriticalSection cs; CriticalSection::ScopedLock lck(cs); _instance = new TimerSignalHandler(); } return *_instance; } private: CriticalSection _timersCs; std::list<Timer::Handle*> _timers; static TimerSignalHandler* _instance; }; TimerSignalHandler* TimerSignalHandler::_instance = 0; Timer::Timer() : _handle(new Handle(this)) { } Timer::Timer(EventQueue& evq) : _handle(new Handle(evq, this)) { } Timer::~Timer() { stop(); delete _handle; } void Timer::start(unsigned int timeout, bool singleShot) { unsigned int sec = timeout / 1000; unsigned int nsec = (timeout % 1000) * 1000000; struct itimerspec newVal, oldVal; newVal.it_value.tv_sec = sec; newVal.it_value.tv_nsec = nsec; newVal.it_interval.tv_sec = singleShot ? 0 : sec; newVal.it_interval.tv_nsec = singleShot ? 0 : nsec; if(timer_settime(_handle->timerId, 0, &newVal, &oldVal) != 0) throw SystemError(errno, "Could not set timer", P_SOURCEINFO); _handle->singleShot = singleShot; if(!_handle->armed) { TimerSignalHandler& timerSigHandler = TimerSignalHandler::instance(); timerSigHandler.add(_handle); _handle->armed = true; } } void Timer::stop() { if(_handle->armed) { struct itimerspec newVal, oldVal; newVal.it_value.tv_sec = 0; newVal.it_value.tv_nsec = 0; newVal.it_interval.tv_sec = 0; newVal.it_interval.tv_nsec = 0; if(timer_settime(_handle->timerId, 0, &newVal, &oldVal) != 0) throw SystemError(errno, "Could not set timer", P_SOURCEINFO); TimerSignalHandler& timerSigHandler = TimerSignalHandler::instance(); timerSigHandler.remove(_handle); _handle->armed = false; } } bool Timer::active() const throw() { return _handle->armed; } void Timer::expired() { } } // !namespace System } // !namespace P |