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