1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/selectdispatcher.cpp
3 // Purpose: implements dispatcher for select() call
4 // Author: Lukasz Michalski and Vadim Zeitlin
5 // Created: December 2006
7 // Copyright: (c) 2006 Lukasz Michalski
8 // License: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
22 #include "wx/private/selectdispatcher.h"
23 #include "wx/module.h"
25 #include "wx/unix/private.h"
32 #ifdef HAVE_SYS_SELECT_H
33 #include <sys/select.h>
38 #define wxSelectDispatcher_Trace wxT("selectdispatcher")
40 // ============================================================================
42 // ============================================================================
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 int wxSelectSets::ms_flags
[wxSelectSets::Max
] =
55 const char *wxSelectSets::ms_names
[wxSelectSets::Max
] =
62 wxSelectSets::Callback
wxSelectSets::ms_handlers
[wxSelectSets::Max
] =
64 &wxFDIOHandler::OnReadWaiting
,
65 &wxFDIOHandler::OnWriteWaiting
,
66 &wxFDIOHandler::OnExceptionWaiting
,
69 wxSelectSets::wxSelectSets()
71 for ( int n
= 0; n
< Max
; n
++ )
77 bool wxSelectSets::HasFD(int fd
) const
79 for ( int n
= 0; n
< Max
; n
++ )
81 if ( wxFD_ISSET(fd
, &m_fds
[n
]) )
88 bool wxSelectSets::SetFD(int fd
, int flags
)
90 wxCHECK_MSG( fd
>= 0, false, _T("invalid descriptor") );
92 for ( int n
= 0; n
< Max
; n
++ )
94 if ( flags
& ms_flags
[n
] )
96 wxFD_SET(fd
, &m_fds
[n
]);
97 wxLogTrace(wxSelectDispatcher_Trace
,
98 _T("Registered fd %d for %s events"), fd
, ms_names
[n
]);
100 else if ( wxFD_ISSET(fd
, &m_fds
[n
]) )
102 wxFD_CLR(fd
, &m_fds
[n
]);
103 wxLogTrace(wxSelectDispatcher_Trace
,
104 _T("Unregistered fd %d from %s events"), fd
, ms_names
[n
]);
111 int wxSelectSets::Select(int nfds
, struct timeval
*tv
)
113 return select(nfds
, &m_fds
[Read
], &m_fds
[Write
], &m_fds
[Except
], tv
);
116 void wxSelectSets::Handle(int fd
, wxFDIOHandler
& handler
) const
118 for ( int n
= 0; n
< Max
; n
++ )
120 if ( wxFD_ISSET(fd
, &m_fds
[n
]) )
122 wxLogTrace(wxSelectDispatcher_Trace
,
123 _T("Got %s event on fd %d"), ms_names
[n
], fd
);
124 (handler
.*ms_handlers
[n
])();
129 // ----------------------------------------------------------------------------
130 // wxSelectDispatcher
131 // ----------------------------------------------------------------------------
133 static wxSelectDispatcher
*gs_selectDispatcher
= NULL
;
136 wxSelectDispatcher
*wxSelectDispatcher::Get()
138 if ( !gs_selectDispatcher
)
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
;
145 return gs_selectDispatcher
;
149 void wxSelectDispatcher::DispatchPending()
151 if ( gs_selectDispatcher
)
152 gs_selectDispatcher
->RunLoop(0);
155 wxSelectDispatcher::wxSelectDispatcher()
160 bool wxSelectDispatcher::RegisterFD(int fd
, wxFDIOHandler
*handler
, int flags
)
162 if ( !wxFDIODispatcher::RegisterFD(fd
, handler
, flags
) )
165 if ( !m_sets
.SetFD(fd
, flags
) )
174 bool wxSelectDispatcher::ModifyFD(int fd
, wxFDIOHandler
*handler
, int flags
)
176 if ( !wxFDIODispatcher::ModifyFD(fd
, handler
, flags
) )
179 wxASSERT_MSG( fd
<= m_maxFD
, _T("logic error: registered fd > m_maxFD?") );
181 return m_sets
.SetFD(fd
, flags
);
184 wxFDIOHandler
*wxSelectDispatcher::UnregisterFD(int fd
, int flags
)
186 wxFDIOHandler
* const handler
= wxFDIODispatcher::UnregisterFD(fd
, flags
);
188 m_sets
.ClearFD(fd
, flags
);
190 // remove the handler if we don't need it any more
191 if ( !m_sets
.HasFD(fd
) )
195 // need to find new max fd
197 for ( wxFDIOHandlerMap::const_iterator it
= m_handlers
.begin();
198 it
!= m_handlers
.end();
201 if ( it
->first
> m_maxFD
)
210 void wxSelectDispatcher::ProcessSets(const wxSelectSets
& sets
)
212 for ( int fd
= 0; fd
<= m_maxFD
; fd
++ )
214 if ( !sets
.HasFD(fd
) )
217 wxFDIOHandler
* const handler
= FindHandler(fd
);
220 wxFAIL_MSG( _T("NULL handler in wxSelectDispatcher?") );
224 sets
.Handle(fd
, *handler
);
228 void wxSelectDispatcher::RunLoop(int timeout
)
232 if ( timeout
!= TIMEOUT_INFINITE
)
236 tv
.tv_usec
= timeout
*1000;
241 wxSelectSets sets
= m_sets
;
244 if ( ptv
&& timeout
)
245 sw
.Start(ptv
->tv_usec
/10);
247 const int ret
= sets
.Select(m_maxFD
+ 1, ptv
);
251 // continue if we were interrupted by a signal, else bail out
252 if ( errno
!= EINTR
)
254 wxLogSysError(_("Failed to monitor IO channels"));
260 // timeout expired without anything happening
269 timeout
-= sw
.Time();
273 ptv
->tv_usec
= timeout
*1000;
278 // ----------------------------------------------------------------------------
279 // wxSelectDispatcherModule
280 // ----------------------------------------------------------------------------
282 class wxSelectDispatcherModule
: public wxModule
285 virtual bool OnInit() { return true; }
286 virtual void OnExit() { wxDELETE(gs_selectDispatcher
); }
289 DECLARE_DYNAMIC_CLASS(wxSelectDispatcherModule
)
292 IMPLEMENT_DYNAMIC_CLASS(wxSelectDispatcherModule
, wxModule
)