diff options
Diffstat (limited to 'salhelper')
-rw-r--r-- | salhelper/inc/salhelper/timer.hxx | 235 | ||||
-rw-r--r-- | salhelper/prj/d.lst | 1 | ||||
-rw-r--r-- | salhelper/source/gcc3.map | 23 | ||||
-rw-r--r-- | salhelper/source/makefile.mk | 3 | ||||
-rw-r--r-- | salhelper/source/timer.cxx | 485 |
5 files changed, 746 insertions, 1 deletions
diff --git a/salhelper/inc/salhelper/timer.hxx b/salhelper/inc/salhelper/timer.hxx new file mode 100644 index 000000000..359e1c80f --- /dev/null +++ b/salhelper/inc/salhelper/timer.hxx @@ -0,0 +1,235 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#ifndef _SALHELPER_TIMER_HXX_ +#define _SALHELPER_TIMER_HXX_ + +#include <salhelper/simplereferenceobject.hxx> +#include <osl/time.h> + +namespace salhelper +{ + +/** Helper class for easier manipulation with TimeValue. + * + * Times are seconds in UTC since 01.01.1970 + */ +struct TTimeValue : public TimeValue +{ + TTimeValue() + { + Seconds = 0; + Nanosec = 0; + } + + TTimeValue( sal_uInt32 Secs, sal_uInt32 Nano ) + { + Seconds = Secs; + Nanosec = Nano; + + normalize(); + } + + TTimeValue(sal_uInt32 MilliSecs) + { + Seconds = MilliSecs / 1000L; + Nanosec = (MilliSecs % 1000) * 1000000L; + + normalize(); + } + + TTimeValue( const TTimeValue& rTimeValue ) + { + Seconds = rTimeValue.Seconds; + Nanosec = rTimeValue.Nanosec; + + normalize(); + } + + TTimeValue( const TimeValue& rTimeValue ) + { + Seconds = rTimeValue.Seconds; + Nanosec = rTimeValue.Nanosec; + + normalize(); + } + + void SAL_CALL normalize() + { + if ( Nanosec > 1000000000 ) + { + Seconds += Nanosec / 1000000000; + Nanosec %= 1000000000; + } + } + + void SAL_CALL addTime( const TTimeValue& Delta ) + { + Seconds += Delta.Seconds; + Nanosec += Delta.Nanosec; + + normalize(); + } + + sal_Bool SAL_CALL isEmpty() const + { + return ( ( Seconds == 0 ) && ( Nanosec == 0 ) ); + } +}; + +inline sal_Bool operator<( const TTimeValue& rTimeA, const TTimeValue& rTimeB ) +{ + if ( rTimeA.Seconds < rTimeB.Seconds ) + return sal_True; + else if ( rTimeA.Seconds > rTimeB.Seconds ) + return sal_False; + else + return ( rTimeA.Nanosec < rTimeB.Nanosec ); +} + +inline sal_Bool operator>( const TTimeValue& rTimeA, const TTimeValue& rTimeB ) +{ + if ( rTimeA.Seconds > rTimeB.Seconds ) + return sal_True; + else if ( rTimeA.Seconds < rTimeB.Seconds ) + return sal_False; + else + return ( rTimeA.Nanosec > rTimeB.Nanosec ); +} + +inline sal_Bool operator==( const TTimeValue& rTimeA, const TTimeValue& rTimeB ) +{ + return ( ( rTimeA.Seconds == rTimeB.Seconds ) && + ( rTimeA.Nanosec == rTimeB.Nanosec ) ); +} + +class TimerManager; + +/** Interface for the Timer and handling the event +*/ +class Timer : public salhelper::SimpleReferenceObject +{ +public: + + /** Constructor. + */ + Timer(); + + /** Constructor. + */ + Timer( const TTimeValue& Time ); + + /** Constructor. + */ + Timer( const TTimeValue& Time, const TTimeValue& RepeatTime ); + + /** Start timer. + */ + void SAL_CALL start(); + + /** Abort timer prematurely. + */ + void SAL_CALL stop(); + + /** Returns sal_True if timer is running. + */ + sal_Bool SAL_CALL isTicking() const; + + /** Is the timer expired? + */ + sal_Bool SAL_CALL isExpired() const; + + /** Does pTimer expires before us? + */ + sal_Bool SAL_CALL expiresBefore( const Timer* pTimer ) const; + + /** Set the absolute time when the timer should fire. + */ + void SAL_CALL setAbsoluteTime( const TTimeValue& Time ); + + /** Set the time to fire to 'now' + Remaining. + */ + void SAL_CALL setRemainingTime( const TTimeValue& Remaining ); + + /** Set the time to fire to 'now' + Remaining with repeat interveal + * Repeat. + */ + void SAL_CALL setRemainingTime( const TTimeValue& Remaining, const TTimeValue& Repeat ); + + /** Adds Time to the 'fire time'. + */ + void SAL_CALL addTime( const TTimeValue& Time ); + + /** Returns the remaining time before timer expiration relative to now. + */ + TTimeValue SAL_CALL getRemainingTime() const; + +protected: + + /** Destructor. + */ + virtual ~Timer(); + + /** What should be done when the 'timer fires'. + */ + virtual void SAL_CALL onShot() = 0; + +protected: + + /** holds (initial) exparation time of this timer. + */ + TTimeValue m_aTimeOut; + + /** holds the time of exparation of this timer. + */ + TTimeValue m_aExpired; + + /** holds the time interveal of successive expirations. + */ + TTimeValue m_aRepeatDelta; + + /** Pointer to the next timer (to fire). + */ + Timer* m_pNext; + +private: + + /** Copy constructor disabled. + */ + Timer( const Timer& rTimer ); + + /** Assignment operator disabled. + */ + void SAL_CALL operator=( const Timer& rTimer ); + + friend class TimerManager; +}; + +} + +#endif //_SALHELPER_TIMER_HXX_ diff --git a/salhelper/prj/d.lst b/salhelper/prj/d.lst index 9cf9e3ad8..86b44d042 100644 --- a/salhelper/prj/d.lst +++ b/salhelper/prj/d.lst @@ -9,6 +9,7 @@ mkdir: %_DEST%\inc%_EXT%\salhelper ..\inc\salhelper\refobj.hxx %_DEST%\inc%_EXT%\salhelper\refobj.hxx ..\inc\salhelper\simplereferenceobject.hxx %_DEST%\inc%_EXT%\salhelper\simplereferenceobject.hxx ..\inc\salhelper\singletonref.hxx %_DEST%\inc%_EXT%\salhelper\singletonref.hxx +..\inc\salhelper\timer.hxx %_DEST%\inc%_EXT%\salhelper\timer.hxx ..\%__SRC%\bin\salhelp*.dll %_DEST%\bin%_EXT%\salhelp*.dll ..\%__SRC%\lib\*salhelper*.lib %_DEST%\lib%_EXT%\* diff --git a/salhelper/source/gcc3.map b/salhelper/source/gcc3.map index a558b6ca9..cbbdc5f87 100644 --- a/salhelper/source/gcc3.map +++ b/salhelper/source/gcc3.map @@ -70,4 +70,27 @@ UDK_3.1 { _ZN9salhelper15ConditionWaiter8timedoutD2Ev; # _ZTIN9salhelper15ConditionWaiter8timedoutE; # _ZTSN9salhelper15ConditionWaiter8timedoutE; + + + _ZN9salhelper5TimerC1ERKNS_10TTimeValueE; + _ZN9salhelper5TimerC1ERKNS_10TTimeValueES3_; + _ZN9salhelper5TimerC1Ev; + _ZN9salhelper5TimerC2ERKNS_10TTimeValueE; + _ZN9salhelper5TimerC2ERKNS_10TTimeValueES3_; + _ZN9salhelper5TimerC2Ev; + _ZN9salhelper5TimerD0Ev; + _ZN9salhelper5TimerD1Ev; + _ZN9salhelper5TimerD2Ev; + _ZN9salhelper5Timer5startEv; + _ZN9salhelper5Timer4stopEv; + _ZNK9salhelper5Timer9isTickingEv; + _ZNK9salhelper5Timer9isExpiredEv; + _ZNK9salhelper5Timer13expiresBeforeEPKS0_; + _ZN9salhelper5Timer15setAbsoluteTimeERKNS_10TTimeValueE; + _ZN9salhelper5Timer16setRemainingTimeERKNS_10TTimeValueE; + _ZN9salhelper5Timer16setRemainingTimeERKNS_10TTimeValueES3_; + _ZN9salhelper5Timer7addTimeERKNS_10TTimeValueE; + _ZNK9salhelper5Timer16getRemainingTimeEv; + + } UDK_3_0_0; diff --git a/salhelper/source/makefile.mk b/salhelper/source/makefile.mk index a6b83cb5e..26acb2e30 100644 --- a/salhelper/source/makefile.mk +++ b/salhelper/source/makefile.mk @@ -46,7 +46,8 @@ UNIXVERSIONNAMES=UDK SLOFILES= \ $(SLO)$/condition.obj \ $(SLO)$/dynload.obj \ - $(SLO)$/simplereferenceobject.obj + $(SLO)$/simplereferenceobject.obj \ + $(SLO)$/timer.obj .IF "$(GUI)" == "WNT" SHL1TARGET= $(TARGET)$(UDK_MAJOR)$(COMID) diff --git a/salhelper/source/timer.cxx b/salhelper/source/timer.cxx new file mode 100644 index 000000000..86877d901 --- /dev/null +++ b/salhelper/source/timer.cxx @@ -0,0 +1,485 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <salhelper/timer.hxx> + +#include <osl/diagnose.h> +#include <salhelper/simplereferenceobject.hxx> +#include <osl/thread.hxx> +#include <osl/conditn.hxx> +#include <osl/mutex.hxx> + +using namespace salhelper; + +class salhelper::TimerManager : public osl::Thread +{ + +public: + + /// + TimerManager(); + + /// + ~TimerManager(); + + /// register timer + sal_Bool SAL_CALL registerTimer(salhelper::Timer* pTimer); + + /// unregister timer + sal_Bool SAL_CALL unregisterTimer(salhelper::Timer* pTimer); + + /// lookup timer + sal_Bool SAL_CALL lookupTimer(const salhelper::Timer* pTimer); + + /// retrieves the "Singleton" TimerManager Instance + static TimerManager* SAL_CALL getTimerManager(); + + +protected: + + /// worker-function of thread + virtual void SAL_CALL run(); + + // Checking and triggering of a timer event + void SAL_CALL checkForTimeout(); + + // cleanup Method + virtual void SAL_CALL onTerminated(); + + // sorted-queue data + salhelper::Timer* m_pHead; + // List Protection + osl::Mutex m_Lock; + // Signal the insertion of a timer + osl::Condition m_notEmpty; + + // Synchronize access to TimerManager + static osl::Mutex m_Access; + + // "Singleton Pattern" + static salhelper::TimerManager* m_pManager; + + friend class TimerManagerCleanup; + +}; + +using namespace salhelper; + +///////////////////////////////////////////////////////////////////////////// +// +// Timer class +// + +Timer::Timer() + : m_aTimeOut( 0 ), + m_aExpired( 0 ), + m_aRepeatDelta( 0 ), + m_pNext( NULL ) +{ +} + +Timer::Timer( const TTimeValue& Time ) + : m_aTimeOut( Time ), + m_aExpired( 0 ), + m_aRepeatDelta( 0 ), + m_pNext( NULL ) +{ +} + +Timer::Timer( const TTimeValue& Time, const TTimeValue& Repeat ) + : m_aTimeOut( Time ), + m_aExpired( 0 ), + m_aRepeatDelta( Repeat ), + m_pNext( NULL ) +{ +} + +Timer::~Timer() +{ + stop(); +} + +void Timer::start() +{ + if (! isTicking()) + { + if (! m_aTimeOut.isEmpty()) + setRemainingTime(m_aTimeOut); + + TimerManager *pManager = TimerManager::getTimerManager(); + + OSL_ASSERT(pManager); + + if ( pManager != 0 ) + { + pManager->registerTimer(this); + } + } +} + +void Timer::stop() +{ + TimerManager *pManager = TimerManager::getTimerManager(); + + OSL_ASSERT(pManager); + + if ( pManager != 0 ) + { + pManager->unregisterTimer(this); + } +} + +sal_Bool Timer::isTicking() const +{ + TimerManager *pManager = TimerManager::getTimerManager(); + + OSL_ASSERT(pManager); + + if (pManager) + return pManager->lookupTimer(this); + else + return sal_False; + +} + +sal_Bool Timer::isExpired() const +{ + TTimeValue Now; + + osl_getSystemTime(&Now); + + return !(Now < m_aExpired); +} + +sal_Bool Timer::expiresBefore(const Timer* pTimer) const +{ + OSL_ASSERT(pTimer); + + if ( pTimer != 0 ) + { + return m_aExpired < pTimer->m_aExpired; + } + else + { + return sal_False; + } +} + +void Timer::setAbsoluteTime(const TTimeValue& Time) +{ + m_aTimeOut = 0; + m_aExpired = Time; + m_aRepeatDelta = 0; + + m_aExpired.normalize(); +} + +void Timer::setRemainingTime(const TTimeValue& Remaining) +{ + osl_getSystemTime(&m_aExpired); + + m_aExpired.addTime(Remaining); +} + +void Timer::setRemainingTime(const TTimeValue& Remaining, const TTimeValue& Repeat) +{ + osl_getSystemTime(&m_aExpired); + + m_aExpired.addTime(Remaining); + + m_aRepeatDelta = Repeat; +} + +void Timer::addTime(const TTimeValue& Delta) +{ + m_aExpired.addTime(Delta); +} + +TTimeValue Timer::getRemainingTime() const +{ + TTimeValue Now; + + osl_getSystemTime(&Now); + + sal_Int32 secs = m_aExpired.Seconds - Now.Seconds; + + if (secs < 0) + return TTimeValue(0, 0); + + sal_Int32 nsecs = m_aExpired.Nanosec - Now.Nanosec; + + if (nsecs < 0) + { + if (secs > 0) + { + secs -= 1; + nsecs += 1000000000L; + } + else + return TTimeValue(0, 0); + } + + return TTimeValue(secs, nsecs); +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Timer manager +// + +osl::Mutex salhelper::TimerManager::m_Access; +TimerManager* salhelper::TimerManager::m_pManager = NULL; + +TimerManager::TimerManager() +{ + osl::MutexGuard Guard(&m_Access); + + OSL_ASSERT(m_pManager == 0); + + m_pManager = this; + + m_pHead= 0; + + m_notEmpty.reset(); + + // start thread + create(); +} + +TimerManager::~TimerManager() +{ + osl::MutexGuard Guard(&m_Access); + + if ( m_pManager == this ) + m_pManager = 0; +} + +void TimerManager::onTerminated() +{ + delete this; // mfe: AAARRRGGGHHH!!! +} + +TimerManager* TimerManager::getTimerManager() +{ + osl::MutexGuard Guard(&m_Access); + + if (! m_pManager) + new TimerManager; + + return (m_pManager); +} + +sal_Bool TimerManager::registerTimer(Timer* pTimer) +{ + OSL_ASSERT(pTimer); + + if ( pTimer == 0 ) + { + return sal_False; + } + + osl::MutexGuard Guard(&m_Lock); + + // try to find one with equal or lower remaining time. + Timer** ppIter = &m_pHead; + + while (*ppIter) + { + if (pTimer->expiresBefore(*ppIter)) + { + // next element has higher remaining time, + // => insert new timer before + break; + } + ppIter= &((*ppIter)->m_pNext); + } + + // next element has higher remaining time, + // => insert new timer before + pTimer->m_pNext= *ppIter; + *ppIter = pTimer; + + + if (pTimer == m_pHead) + { + // it was inserted as new head + // signal it to TimerManager Thread + m_notEmpty.set(); + } + + return sal_True; +} + +sal_Bool TimerManager::unregisterTimer(Timer* pTimer) +{ + OSL_ASSERT(pTimer); + + if ( pTimer == 0 ) + { + return sal_False; + } + + // lock access + osl::MutexGuard Guard(&m_Lock); + + Timer** ppIter = &m_pHead; + + while (*ppIter) + { + if (pTimer == (*ppIter)) + { + // remove timer from list + *ppIter = (*ppIter)->m_pNext; + return sal_True; + } + ppIter= &((*ppIter)->m_pNext); + } + + return sal_False; +} + +sal_Bool TimerManager::lookupTimer(const Timer* pTimer) +{ + OSL_ASSERT(pTimer); + + if ( pTimer == 0 ) + { + return sal_False; + } + + // lock access + osl::MutexGuard Guard(&m_Lock); + + // check the list + for (Timer* pIter = m_pHead; pIter != 0; pIter= pIter->m_pNext) + { + if (pIter == pTimer) + { + return sal_True; + } + } + + return sal_False; +} + +void TimerManager::checkForTimeout() +{ + + m_Lock.acquire(); + + if ( m_pHead == 0 ) + { + m_Lock.release(); + return; + } + + Timer* pTimer = m_pHead; + + if (pTimer->isExpired()) + { + // remove expired timer + m_pHead = pTimer->m_pNext; + + pTimer->acquire(); + + m_Lock.release(); + + pTimer->onShot(); + + // restart timer if specified + if ( ! pTimer->m_aRepeatDelta.isEmpty() ) + { + TTimeValue Now; + + osl_getSystemTime(&Now); + + Now.Seconds += pTimer->m_aRepeatDelta.Seconds; + Now.Nanosec += pTimer->m_aRepeatDelta.Nanosec; + + pTimer->m_aExpired = Now; + + registerTimer(pTimer); + } + pTimer->release(); + } + else + { + m_Lock.release(); + } + + + return; +} + +void TimerManager::run() +{ + setPriority( osl_Thread_PriorityBelowNormal ); + + while (schedule()) + { + TTimeValue delay; + TTimeValue* pDelay=0; + + + m_Lock.acquire(); + + if (m_pHead != 0) + { + delay = m_pHead->getRemainingTime(); + pDelay=&delay; + } + else + { + pDelay=0; + } + + + m_notEmpty.reset(); + + m_Lock.release(); + + + m_notEmpty.wait(pDelay); + + checkForTimeout(); + } + +} + + +///////////////////////////////////////////////////////////////////////////// +// +// Timer manager cleanup +// + +// jbu: +// The timer manager cleanup has been removed (no thread is killed anymore). +// So the thread leaks. +// This will result in a GPF in case the salhelper-library gets unloaded before +// process termination. +// -> TODO : rewrite this file, so that the timerManager thread gets destroyed, +// when there are no timers anymore ! |