]> git.saurik.com Git - wxWidgets.git/blame - src/unix/timerunx.cpp
avoiding reentrancy problems and congestion
[wxWidgets.git] / src / unix / timerunx.cpp
CommitLineData
c2ca375c
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/unix/timerunx.cpp
3// Purpose: wxTimer implementation for non-GUI applications under Unix
4// Author: Lukasz Michalski
5// Created: 15/01/2005
6// RCS-ID: $Id$
7// Copyright: (c) 2007 Lukasz Michalski
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19#include "wx/wxprec.h"
20
8e913f79
VZ
21#if wxUSE_TIMER
22
c2ca375c
VZ
23#ifndef WX_PRECOMP
24 #include "wx/log.h"
25 #include "wx/module.h"
26 #include "wx/app.h"
27 #include "wx/list.h"
28 #include "wx/hashmap.h"
29 #include "wx/event.h"
30#endif
31
1d043598 32#include "wx/apptrait.h"
c2ca375c 33#include "wx/longlong.h"
cec1b1ab 34#include "wx/time.h"
f7d8cefd 35#include "wx/vector.h"
c2ca375c
VZ
36
37#include <sys/time.h>
38#include <signal.h>
39
40#include "wx/unix/private/timer.h"
41
42#include "wx/listimpl.cpp"
faa80db0 43WX_DEFINE_LIST(wxTimerList)
c2ca375c
VZ
44
45// trace mask for the debugging messages used here
46#define wxTrace_Timer wxT("timer")
47
48// ----------------------------------------------------------------------------
49// local functions
50// ----------------------------------------------------------------------------
51
52// helper function to format wxUsecClock_t
53static inline wxString wxUsecClockAsString(wxUsecClock_t usec)
54{
55 #if wxUSE_LONGLONG
56 return usec.ToString();
57 #else // wxUsecClock_t == double
9a83f860 58 return wxString::Format(wxT("%.0f"), usec);
c2ca375c
VZ
59 #endif
60}
61
62// ============================================================================
63// wxTimerScheduler implementation
64// ============================================================================
65
66wxTimerScheduler *wxTimerScheduler::ms_instance = NULL;
67
68wxTimerScheduler::~wxTimerScheduler()
69{
70 for ( wxTimerList::iterator node = m_timers.begin();
71 node != m_timers.end();
72 ++node )
73 {
74 delete *node;
75 }
76}
77
78void wxTimerScheduler::AddTimer(wxUnixTimerImpl *timer, wxUsecClock_t expiration)
79{
80 DoAddTimer(new wxTimerSchedule(timer, expiration));
81}
82
83void wxTimerScheduler::DoAddTimer(wxTimerSchedule *s)
84{
85 // do an insertion sort to keep the list sorted in expiration order
86 wxTimerList::iterator node;
87 for ( node = m_timers.begin(); node != m_timers.end(); ++node )
88 {
89 wxASSERT_MSG( (*node)->m_timer != s->m_timer,
9a83f860 90 wxT("adding the same timer twice?") );
c2ca375c
VZ
91
92 if ( (*node)->m_expiration > s->m_expiration )
93 break;
94 }
95
96 m_timers.insert(node, s);
97
98 wxLogTrace(wxTrace_Timer, wxT("Inserted timer %d expiring at %s"),
99 s->m_timer->GetId(),
100 wxUsecClockAsString(s->m_expiration).c_str());
101}
102
103void wxTimerScheduler::RemoveTimer(wxUnixTimerImpl *timer)
104{
105 wxLogTrace(wxTrace_Timer, wxT("Removing timer %d"), timer->GetId());
106
107 for ( wxTimerList::iterator node = m_timers.begin();
108 node != m_timers.end();
109 ++node )
110 {
111 if ( (*node)->m_timer == timer )
112 {
113 delete *node;
114 m_timers.erase(node);
115 return;
116 }
117 }
118
9a83f860 119 wxFAIL_MSG( wxT("removing inexistent timer?") );
c2ca375c
VZ
120}
121
122bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
123{
124 if ( m_timers.empty() )
125 return false;
126
9a83f860 127 wxCHECK_MSG( remaining, false, wxT("NULL pointer") );
c2ca375c 128
cec1b1ab 129 *remaining = (*m_timers.begin())->m_expiration - wxGetUTCTimeUSec();
c2ca375c
VZ
130 if ( *remaining < 0 )
131 {
132 // timer already expired, don't wait at all before notifying it
133 *remaining = 0;
134 }
135
136 return true;
137}
138
aa8cbe0b 139bool wxTimerScheduler::NotifyExpired()
c2ca375c
VZ
140{
141 if ( m_timers.empty() )
aa8cbe0b
VZ
142 return false;
143
cec1b1ab 144 const wxUsecClock_t now = wxGetUTCTimeUSec();
c2ca375c 145
f7d8cefd
VZ
146 typedef wxVector<wxUnixTimerImpl *> TimerImpls;
147 TimerImpls toNotify;
148 for ( wxTimerList::iterator next,
149 cur = m_timers.begin(); cur != m_timers.end(); cur = next )
c2ca375c
VZ
150 {
151 wxTimerSchedule * const s = *cur;
152 if ( s->m_expiration > now )
153 {
154 // as the list is sorted by expiration time, we can skip the rest
155 break;
156 }
157
158 // remember next as we will delete the node pointed to by cur
159 next = cur;
160 ++next;
161
162 m_timers.erase(cur);
163
164 // check whether we need to keep this timer
165 wxUnixTimerImpl * const timer = s->m_timer;
166 if ( timer->IsOneShot() )
167 {
74e10fcc
VZ
168 // the timer needs to be stopped but don't call its Stop() from
169 // here as it would attempt to remove the timer from our list and
170 // we had already done it, so we just need to reset its state
171 timer->MarkStopped();
172
c2ca375c
VZ
173 // don't need it any more
174 delete s;
175 }
176 else // reschedule the next timer expiration
177 {
d45242a6
VZ
178 // always keep the expiration time in the future, i.e. base it on
179 // the current time instead of just offsetting it from the current
180 // expiration time because it could happen that we're late and the
181 // current expiration time is (far) in the past
182 s->m_expiration = now + timer->GetInterval()*1000;
c2ca375c
VZ
183 DoAddTimer(s);
184 }
185
f7d8cefd
VZ
186 // we can't notify the timer from this loop as the timer event handler
187 // could modify m_timers (for example, but not only, by stopping this
188 // timer) which would render our iterators invalid, so do it after the
189 // loop end
190 toNotify.push_back(timer);
191 }
192
193 if ( toNotify.empty() )
194 return false;
195
196 for ( TimerImpls::const_iterator i = toNotify.begin(),
197 end = toNotify.end();
198 i != end;
199 ++i )
200 {
201 (*i)->Notify();
c2ca375c 202 }
aa8cbe0b 203
f7d8cefd 204 return true;
c2ca375c
VZ
205}
206
207// ============================================================================
208// wxUnixTimerImpl implementation
209// ============================================================================
210
211wxUnixTimerImpl::wxUnixTimerImpl(wxTimer* timer)
212 : wxTimerImpl(timer)
213{
214 m_isRunning = false;
215}
216
217bool wxUnixTimerImpl::Start(int milliseconds, bool oneShot)
218{
219 // notice that this will stop an already running timer
220 wxTimerImpl::Start(milliseconds, oneShot);
221
cec1b1ab 222 wxTimerScheduler::Get().AddTimer(this, wxGetUTCTimeUSec() + m_milli*1000);
c2ca375c
VZ
223 m_isRunning = true;
224
225 return true;
226}
227
228void wxUnixTimerImpl::Stop()
229{
230 if ( m_isRunning )
231 {
232 wxTimerScheduler::Get().RemoveTimer(this);
233
234 m_isRunning = false;
235 }
236}
237
238bool wxUnixTimerImpl::IsRunning() const
239{
240 return m_isRunning;
241}
242
243wxUnixTimerImpl::~wxUnixTimerImpl()
244{
9a83f860 245 wxASSERT_MSG( !m_isRunning, wxT("must have been stopped before") );
c2ca375c
VZ
246}
247
248// ============================================================================
249// wxTimerUnixModule: responsible for freeing the global timer scheduler
250// ============================================================================
251
252class wxTimerUnixModule : public wxModule
253{
254public:
255 wxTimerUnixModule() {}
256 virtual bool OnInit() { return true; }
257 virtual void OnExit() { wxTimerScheduler::Shutdown(); }
258
259 DECLARE_DYNAMIC_CLASS(wxTimerUnixModule)
260};
261
262IMPLEMENT_DYNAMIC_CLASS(wxTimerUnixModule, wxModule)
263
264// ============================================================================
265// global functions
266// ============================================================================
267
1d043598
VZ
268wxTimerImpl *wxConsoleAppTraits::CreateTimerImpl(wxTimer *timer)
269{
270 return new wxUnixTimerImpl(timer);
271}
272
8e913f79
VZ
273#endif // wxUSE_TIMER
274