]> git.saurik.com Git - wxWidgets.git/blame - src/common/selectdispatcher.cpp
use C++ compiler for va_copy test, at least under IRIX the C99 C compiler has it...
[wxWidgets.git] / src / common / selectdispatcher.cpp
CommitLineData
30c45bdd 1///////////////////////////////////////////////////////////////////////////////
b46b1d59 2// Name: src/common/selectdispatcher.cpp
30c45bdd 3// Purpose: implements dispatcher for select() call
b46b1d59 4// Author: Lukasz Michalski and Vadim Zeitlin
30c45bdd
VZ
5// Created: December 2006
6// RCS-ID: $Id$
7// Copyright: (c) 2006 Lukasz Michalski
8// License: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// for compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#include "wx/private/selectdispatcher.h"
23#include "wx/module.h"
24#include "wx/timer.h"
25#include "wx/unix/private.h"
26#include "wx/log.h"
27
28#ifndef WX_PRECOMP
29 #include "wx/hash.h"
30#endif
31
30c45bdd 32#ifdef HAVE_SYS_SELECT_H
b46b1d59 33 #include <sys/select.h>
30c45bdd
VZ
34#endif
35
b46b1d59
VZ
36#include <errno.h>
37
30c45bdd
VZ
38#define wxSelectDispatcher_Trace wxT("selectdispatcher")
39
40// ============================================================================
41// implementation
42// ============================================================================
43
44// ----------------------------------------------------------------------------
b46b1d59 45// wxSelectSets
30c45bdd
VZ
46// ----------------------------------------------------------------------------
47
b46b1d59
VZ
48int wxSelectSets::ms_flags[wxSelectSets::Max] =
49{
50 wxFDIO_INPUT,
51 wxFDIO_OUTPUT,
52 wxFDIO_EXCEPTION,
53};
30c45bdd 54
b46b1d59 55const char *wxSelectSets::ms_names[wxSelectSets::Max] =
30c45bdd 56{
b46b1d59
VZ
57 "input",
58 "output",
59 "exceptional",
60};
30c45bdd 61
b46b1d59 62wxSelectSets::Callback wxSelectSets::ms_handlers[wxSelectSets::Max] =
30c45bdd 63{
b46b1d59
VZ
64 &wxFDIOHandler::OnReadWaiting,
65 &wxFDIOHandler::OnWriteWaiting,
66 &wxFDIOHandler::OnExceptionWaiting,
67};
30c45bdd 68
b46b1d59
VZ
69wxSelectSets::wxSelectSets()
70{
71 for ( int n = 0; n < Max; n++ )
30c45bdd 72 {
b46b1d59 73 wxFD_ZERO(&m_fds[n]);
30c45bdd 74 }
b46b1d59 75}
30c45bdd 76
b46b1d59
VZ
77bool wxSelectSets::HasFD(int fd) const
78{
79 for ( int n = 0; n < Max; n++ )
30c45bdd 80 {
b46b1d59
VZ
81 if ( wxFD_ISSET(fd, &m_fds[n]) )
82 return true;
83 }
30c45bdd 84
b46b1d59 85 return false;
30c45bdd
VZ
86}
87
b46b1d59 88bool wxSelectSets::SetFD(int fd, int flags)
30c45bdd 89{
b46b1d59 90 wxCHECK_MSG( fd >= 0, false, _T("invalid descriptor") );
30c45bdd 91
b46b1d59 92 for ( int n = 0; n < Max; n++ )
30c45bdd 93 {
b46b1d59
VZ
94 if ( flags & ms_flags[n] )
95 {
96 wxFD_SET(fd, &m_fds[n]);
97 wxLogTrace(wxSelectDispatcher_Trace,
98 _T("Registered fd %d for %s events"), fd, ms_names[n]);
99 }
100 else if ( wxFD_ISSET(fd, &m_fds[n]) )
101 {
102 wxFD_CLR(fd, &m_fds[n]);
103 wxLogTrace(wxSelectDispatcher_Trace,
104 _T("Unregistered fd %d from %s events"), fd, ms_names[n]);
105 }
30c45bdd
VZ
106 }
107
b46b1d59
VZ
108 return true;
109}
30c45bdd 110
b46b1d59
VZ
111int wxSelectSets::Select(int nfds, struct timeval *tv)
112{
113 return select(nfds, &m_fds[Read], &m_fds[Write], &m_fds[Except], tv);
114}
30c45bdd 115
b46b1d59
VZ
116void wxSelectSets::Handle(int fd, wxFDIOHandler& handler) const
117{
118 for ( int n = 0; n < Max; n++ )
30c45bdd 119 {
b46b1d59 120 if ( wxFD_ISSET(fd, &m_fds[n]) )
30c45bdd 121 {
b46b1d59
VZ
122 wxLogTrace(wxSelectDispatcher_Trace,
123 _T("Got %s event on fd %d"), ms_names[n], fd);
124 (handler.*ms_handlers[n])();
125 }
126 }
30c45bdd
VZ
127}
128
b46b1d59
VZ
129// ----------------------------------------------------------------------------
130// wxSelectDispatcher
131// ----------------------------------------------------------------------------
132
133static wxSelectDispatcher *gs_selectDispatcher = NULL;
134
135/* static */
136wxSelectDispatcher *wxSelectDispatcher::Get()
30c45bdd 137{
b46b1d59 138 if ( !gs_selectDispatcher )
30c45bdd 139 {
b46b1d59
VZ
140 // the dispatcher should be only created from one thread so it should
141 // be ok to use a global without any protection here
142 gs_selectDispatcher = new wxSelectDispatcher;
143 }
30c45bdd 144
b46b1d59
VZ
145 return gs_selectDispatcher;
146}
147
148/* static */
149void wxSelectDispatcher::DispatchPending()
150{
151 if ( gs_selectDispatcher )
152 gs_selectDispatcher->RunLoop(0);
153}
30c45bdd 154
b46b1d59
VZ
155wxSelectDispatcher::wxSelectDispatcher()
156{
157 m_maxFD = -1;
158}
159
160bool wxSelectDispatcher::RegisterFD(int fd, wxFDIOHandler *handler, int flags)
161{
162 if ( !wxFDIODispatcher::RegisterFD(fd, handler, flags) )
163 return false;
164
165 if ( !m_sets.SetFD(fd, flags) )
166 return false;
167
168 if ( fd > m_maxFD )
169 m_maxFD = fd;
170
171 return true;
172}
173
174bool wxSelectDispatcher::ModifyFD(int fd, wxFDIOHandler *handler, int flags)
175{
176 if ( !wxFDIODispatcher::ModifyFD(fd, handler, flags) )
177 return false;
178
179 wxASSERT_MSG( fd <= m_maxFD, _T("logic error: registered fd > m_maxFD?") );
180
181 return m_sets.SetFD(fd, flags);
182}
183
184wxFDIOHandler *wxSelectDispatcher::UnregisterFD(int fd, int flags)
185{
186 wxFDIOHandler * const handler = wxFDIODispatcher::UnregisterFD(fd, flags);
187
188 m_sets.ClearFD(fd, flags);
189
190 // remove the handler if we don't need it any more
191 if ( !m_sets.HasFD(fd) )
192 {
193 if ( fd == m_maxFD )
30c45bdd 194 {
b46b1d59
VZ
195 // need to find new max fd
196 m_maxFD = -1;
197 for ( wxFDIOHandlerMap::const_iterator it = m_handlers.begin();
198 it != m_handlers.end();
199 ++it )
30c45bdd 200 {
b46b1d59
VZ
201 if ( it->first > m_maxFD )
202 m_maxFD = it->first;
203 }
204 }
205 }
206
207 return handler;
30c45bdd
VZ
208}
209
b46b1d59 210void wxSelectDispatcher::ProcessSets(const wxSelectSets& sets)
30c45bdd 211{
b46b1d59
VZ
212 for ( int fd = 0; fd <= m_maxFD; fd++ )
213 {
214 if ( !sets.HasFD(fd) )
215 continue;
216
217 wxFDIOHandler * const handler = FindHandler(fd);
218 if ( !handler )
219 {
220 wxFAIL_MSG( _T("NULL handler in wxSelectDispatcher?") );
221 continue;
222 }
223
224 sets.Handle(fd, *handler);
225 }
226}
30c45bdd
VZ
227
228void wxSelectDispatcher::RunLoop(int timeout)
229{
b46b1d59
VZ
230 struct timeval tv,
231 *ptv = NULL;
232 if ( timeout != TIMEOUT_INFINITE )
30c45bdd
VZ
233 {
234 ptv = &tv;
235 tv.tv_sec = 0;
b46b1d59
VZ
236 tv.tv_usec = timeout*1000;
237 }
30c45bdd 238
b46b1d59 239 for ( ;; )
30c45bdd 240 {
b46b1d59
VZ
241 wxSelectSets sets = m_sets;
242
30c45bdd 243 wxStopWatch sw;
f7b3c5ec 244 if ( ptv && timeout )
30c45bdd 245 sw.Start(ptv->tv_usec/10);
b46b1d59
VZ
246
247 const int ret = sets.Select(m_maxFD + 1, ptv);
30c45bdd
VZ
248 switch ( ret )
249 {
30c45bdd 250 case -1:
b46b1d59
VZ
251 // continue if we were interrupted by a signal, else bail out
252 if ( errno != EINTR )
f7b3c5ec 253 {
b46b1d59 254 wxLogSysError(_("Failed to monitor IO channels"));
f7b3c5ec
VZ
255 return;
256 }
30c45bdd
VZ
257 break;
258
30c45bdd 259 case 0:
b46b1d59
VZ
260 // timeout expired without anything happening
261 return;
30c45bdd
VZ
262
263 default:
b46b1d59
VZ
264 ProcessSets(sets);
265 }
266
267 if ( ptv )
268 {
269 timeout -= sw.Time();
270 if ( timeout <= 0 )
271 break;
272
273 ptv->tv_usec = timeout*1000;
274 }
275 }
30c45bdd
VZ
276}
277
278// ----------------------------------------------------------------------------
279// wxSelectDispatcherModule
280// ----------------------------------------------------------------------------
281
b46b1d59 282class wxSelectDispatcherModule : public wxModule
30c45bdd
VZ
283{
284public:
b46b1d59
VZ
285 virtual bool OnInit() { return true; }
286 virtual void OnExit() { wxDELETE(gs_selectDispatcher); }
30c45bdd
VZ
287
288private:
289 DECLARE_DYNAMIC_CLASS(wxSelectDispatcherModule)
290};
291
292IMPLEMENT_DYNAMIC_CLASS(wxSelectDispatcherModule, wxModule)
293