// // This file is part of the aMule Project. // // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #include "Timer.h" // Interface declaration #include "GetTickCount.h" // Needed for GetTickCountFullRes #include "MuleThread.h" // Needed for CMuleThread //////////////////////// Timer Thread //////////////////// class CTimerThread : public CMuleThread { public: CTimerThread() : CMuleThread(wxTHREAD_JOINABLE) { } void* Entry() { CTimerEvent evt(m_id); uint32 lastEvent = GetTickCountFullRes(); do { // current time uint32 now = GetTickCountFullRes(); // This is typically zero, because lastEvent was already incremented by one period. sint32 delta = now - lastEvent; if (delta > 100 * m_period) { // We're way too far behind. Probably what really happened is // the system time was adjusted backwards a bit. So, // the calculation of delta has produced an absurd value. delta = 100 * m_period; lastEvent = now - delta; } // Wait one period (adjusted by the difference just calculated) sint32 timeout = ((m_period < delta) ? 0 : (m_period - delta)); // In normal operation, we will never actually acquire the // semaphore; we will always timeout. This is used to // implement a Sleep operation which the owning CTimer can // interrupt by posting to the semaphore. So, it follows // that if we do acquire the semaphore it means the owner // wants us to exit. if (m_sleepSemaphore.WaitTimeout(timeout) == wxSEMA_TIMEOUT) { // Increment for one event only, so no events can be lost. lastEvent += m_period; wxPostEvent(m_owner, evt); } else { break; } } while (!m_oneShot); return NULL; } sint32 m_period; bool m_oneShot; wxEvtHandler* m_owner; int m_id; wxSemaphore m_sleepSemaphore; }; ////////////////////// CTimer //////////////////////// CTimer::~CTimer() { Stop(); } CTimer::CTimer(wxEvtHandler* owner, int id) { wxASSERT(owner); m_owner = owner; m_id = id; m_thread = NULL; } bool CTimer::IsRunning() const { return (m_thread && m_thread->IsRunning()); } bool CTimer::Start(int millisecs, bool oneShot) { wxCHECK_MSG(m_id != -1, false, wxT("Invalid target-ID for timer-events.")); // Since this class generally matches wxTimer, calling // start on a running timer stops and then restarts it. Stop(); m_thread = new CTimerThread(); m_thread->m_period = millisecs; m_thread->m_oneShot = oneShot; m_thread->m_owner = m_owner; m_thread->m_id = m_id; if (m_thread->Create() == wxTHREAD_NO_ERROR) { if (m_thread->Run() == wxTHREAD_NO_ERROR) { return true; } } // Something went wrong ... m_thread->Stop(); delete m_thread; m_thread = NULL; return false; } void CTimer::Stop() { if (m_thread) { m_thread->m_sleepSemaphore.Post(); m_thread->Stop(); delete m_thread; m_thread = NULL; } } DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_TIMER) CTimerEvent::CTimerEvent(int id) : wxEvent(id, MULE_EVT_TIMER) { } wxEvent* CTimerEvent::Clone() const { return new CTimerEvent(GetId()); } // File_checked_for_headers