1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5//
6// Any parts of this program derived from the xMule, lMule or eMule project,
7// or contributed by third-party developers are copyrighted by their
8// respective authors.
9//
10// This program is free software; you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation; either version 2 of the License, or
13// (at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
23//
24
25#include "Timer.h"		// Interface declaration
26#include "GetTickCount.h"	// Needed for GetTickCountFullRes
27#include "MuleThread.h"		// Needed for CMuleThread
28
29
30//////////////////////// Timer Thread ////////////////////
31
32class CTimerThread : public CMuleThread
33{
34public:
35	CTimerThread()
36		: CMuleThread(wxTHREAD_JOINABLE)
37	{
38	}
39
40	void* Entry() {
41		CTimerEvent evt(m_id);
42
43		uint32 lastEvent = GetTickCountFullRes();
44		do {
45			// current time
46			uint32 now = GetTickCountFullRes();
47			// This is typically zero, because lastEvent was already incremented by one period.
48			sint32 delta = now - lastEvent;
49			if (delta > 100 * m_period) {
50				// We're way too far behind.  Probably what really happened is
51				// the system time was adjusted backwards a bit.  So,
52				// the calculation of delta has produced an absurd value.
53				delta = 100 * m_period;
54				lastEvent = now - delta;
55			}
56
57			// Wait one period (adjusted by the difference just calculated)
58			sint32 timeout = ((m_period < delta) ? 0 : (m_period - delta));
59
60			// In normal operation, we will never actually acquire the
61			// semaphore; we will always timeout.  This is used to
62			// implement a Sleep operation which the owning CTimer can
63			// interrupt by posting to the semaphore.  So, it follows
64			// that if we do acquire the semaphore it means the owner
65			// wants us to exit.
66			if (m_sleepSemaphore.WaitTimeout(timeout) == wxSEMA_TIMEOUT) {
67				// Increment for one event only, so no events can be lost.
68				lastEvent += m_period;
69
70				wxPostEvent(m_owner, evt);
71			} else {
72				break;
73			}
74		} while (!m_oneShot);
75
76		return NULL;
77	}
78
79	sint32			m_period;
80	bool			m_oneShot;
81	wxEvtHandler*	m_owner;
82	int				m_id;
83	wxSemaphore		m_sleepSemaphore;
84};
85
86
87////////////////////// CTimer ////////////////////////
88
89CTimer::~CTimer()
90{
91	Stop();
92}
93
94
95CTimer::CTimer(wxEvtHandler* owner, int id)
96{
97	wxASSERT(owner);
98	m_owner = owner;
99	m_id = id;
100	m_thread = NULL;
101}
102
103
104bool CTimer::IsRunning() const
105{
106	return (m_thread && m_thread->IsRunning());
107}
108
109
110bool CTimer::Start(int millisecs, bool oneShot)
111{
112	wxCHECK_MSG(m_id != -1, false, wxT("Invalid target-ID for timer-events."));
113
114	// Since this class generally matches wxTimer, calling
115	// start on a running timer stops and then restarts it.
116	Stop();
117
118	m_thread = new CTimerThread();
119	m_thread->m_period	= millisecs;
120	m_thread->m_oneShot	= oneShot;
121	m_thread->m_owner	= m_owner;
122	m_thread->m_id		= m_id;
123
124	if (m_thread->Create() == wxTHREAD_NO_ERROR) {
125		if (m_thread->Run() == wxTHREAD_NO_ERROR) {
126			return true;
127		}
128	}
129
130	// Something went wrong ...
131	m_thread->Stop();
132	delete m_thread;
133	m_thread = NULL;
134
135	return false;
136}
137
138
139void CTimer::Stop()
140{
141	if (m_thread) {
142		m_thread->m_sleepSemaphore.Post();
143		m_thread->Stop();
144		delete m_thread;
145		m_thread = NULL;
146	}
147}
148
149
150DEFINE_LOCAL_EVENT_TYPE(MULE_EVT_TIMER)
151
152CTimerEvent::CTimerEvent(int id)
153	: wxEvent(id, MULE_EVT_TIMER)
154{
155}
156
157
158wxEvent* CTimerEvent::Clone() const
159{
160	return new CTimerEvent(GetId());
161}
162
163// File_checked_for_headers
164