X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f7b3c5ec4c7ee0a566b7e852e8f96bd407f322f3..ec080ef1873995bcd9b20b0fc1a6d208a78540d3:/src/common/selectdispatcher.cpp diff --git a/src/common/selectdispatcher.cpp b/src/common/selectdispatcher.cpp index 5ee2f0242d..7e693c54ca 100644 --- a/src/common/selectdispatcher.cpp +++ b/src/common/selectdispatcher.cpp @@ -1,11 +1,11 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: src/common/socketevtdispatch.cpp +// Name: src/common/selectdispatcher.cpp // Purpose: implements dispatcher for select() call -// Author: Lukasz Michalski +// Author: Lukasz Michalski and Vadim Zeitlin // Created: December 2006 // RCS-ID: $Id$ // Copyright: (c) 2006 Lukasz Michalski -// License: wxWindows licence +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -19,22 +19,22 @@ // for compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SELECT_DISPATCHER + #include "wx/private/selectdispatcher.h" -#include "wx/module.h" -#include "wx/timer.h" #include "wx/unix/private.h" -#include "wx/log.h" #ifndef WX_PRECOMP #include "wx/hash.h" + #include "wx/log.h" + #include "wx/intl.h" #endif -#include -#include - -#ifdef HAVE_SYS_SELECT_H -# include -#endif +#include #define wxSelectDispatcher_Trace wxT("selectdispatcher") @@ -43,204 +43,223 @@ // ============================================================================ // ---------------------------------------------------------------------------- -// wxSelectDispatcher +// wxSelectSets // ---------------------------------------------------------------------------- -wxSelectDispatcher* wxSelectDispatcher::ms_instance = NULL; +int wxSelectSets::ms_flags[wxSelectSets::Max] = +{ + wxFDIO_INPUT, + wxFDIO_OUTPUT, + wxFDIO_EXCEPTION, +}; -/* static */ -wxSelectDispatcher& wxSelectDispatcher::Get() +const char *wxSelectSets::ms_names[wxSelectSets::Max] = { - if ( !ms_instance ) - ms_instance = new wxSelectDispatcher; - return *ms_instance; -} + "input", + "output", + "exceptional", +}; -void -wxSelectDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags) +wxSelectSets::Callback wxSelectSets::ms_handlers[wxSelectSets::Max] = { - if ((flags & wxSelectInput) == wxSelectInput) - { - wxFD_SET(fd, &m_readset); - wxLogTrace(wxSelectDispatcher_Trace,wxT("Registered fd %d for input events"),fd); - }; + &wxFDIOHandler::OnReadWaiting, + &wxFDIOHandler::OnWriteWaiting, + &wxFDIOHandler::OnExceptionWaiting, +}; - if ((flags & wxSelectOutput) == wxSelectOutput) +wxSelectSets::wxSelectSets() +{ + for ( int n = 0; n < Max; n++ ) { - wxFD_SET(fd, &m_writeset); - wxLogTrace(wxSelectDispatcher_Trace,wxT("Registered fd %d for output events"),fd); + wxFD_ZERO(&m_fds[n]); } +} - if ((flags & wxSelectException) == wxSelectException) +bool wxSelectSets::HasFD(int fd) const +{ + for ( int n = 0; n < Max; n++ ) { - wxFD_SET(fd, &m_exeptset); - wxLogTrace(wxSelectDispatcher_Trace,wxT("Registered fd %d for exception events"),fd); - }; + if ( wxFD_ISSET(fd, (fd_set*) &m_fds[n]) ) + return true; + } - m_handlers[fd] = handler; - if (fd > m_maxFD) - m_maxFD = fd; + return false; } -wxFDIOHandler* -wxSelectDispatcher::UnregisterFD(int fd, int flags) +bool wxSelectSets::SetFD(int fd, int flags) { - // GSocket likes to unregister -1 descriptor - if (fd == -1) - return NULL; + wxCHECK_MSG( fd >= 0, false, wxT("invalid descriptor") ); - if ((flags & wxSelectInput) == wxSelectInput) + for ( int n = 0; n < Max; n++ ) { - wxLogTrace(wxSelectDispatcher_Trace,wxT("Unregistered fd %d from input events"),fd); - wxFD_CLR(fd, &m_readset); + if ( flags & ms_flags[n] ) + { + wxFD_SET(fd, &m_fds[n]); + } + else if ( wxFD_ISSET(fd, (fd_set*) &m_fds[n]) ) + { + wxFD_CLR(fd, &m_fds[n]); + } } - if ((flags & wxSelectOutput) == wxSelectOutput) - { - wxLogTrace(wxSelectDispatcher_Trace,wxT("Unregistered fd %d from output events"),fd); - wxFD_CLR(fd, &m_writeset); - } + return true; +} - if ((flags & wxSelectException) == wxSelectException) - { - wxLogTrace(wxSelectDispatcher_Trace,wxT("Unregistered fd %d from exeption events"),fd); - wxFD_CLR(fd, &m_exeptset); - }; +int wxSelectSets::Select(int nfds, struct timeval *tv) +{ + return select(nfds, &m_fds[Read], &m_fds[Write], &m_fds[Except], tv); +} - wxFDIOHandler* ret = NULL; - wxFDIOHandlerMap::const_iterator it = m_handlers.find(fd); - if (it != m_handlers.end()) +bool wxSelectSets::Handle(int fd, wxFDIOHandler& handler) const +{ + for ( int n = 0; n < Max; n++ ) { - ret = it->second; - if (!wxFD_ISSET(fd,&m_readset) && !wxFD_ISSET(fd,&m_writeset) && !wxFD_ISSET(fd,&m_exeptset)) + if ( wxFD_ISSET(fd, (fd_set*) &m_fds[n]) ) { - m_handlers.erase(it); - if ( m_handlers.empty() ) - m_maxFD = 0; - }; - }; - return ret; + wxLogTrace(wxSelectDispatcher_Trace, + wxT("Got %s event on fd %d"), ms_names[n], fd); + (handler.*ms_handlers[n])(); + // callback can modify sets and destroy handler + // this forces that one event can be processed at one time + return true; + } + } + + return false; } -void wxSelectDispatcher::ProcessSets(fd_set* readset, fd_set* writeset, fd_set* exeptset, int max_fd) +// ---------------------------------------------------------------------------- +// wxSelectDispatcher +// ---------------------------------------------------------------------------- + +bool wxSelectDispatcher::RegisterFD(int fd, wxFDIOHandler *handler, int flags) { - // it is safe to remove handler from onXXX methods, - // if you unregister descriptor first. - wxFDIOHandlerMap::const_iterator it = m_handlers.begin(); - for ( int i = 0; i < max_fd; i++ ) - { - wxFDIOHandler* handler = NULL; - if (wxFD_ISSET(i, readset)) - { - wxLogTrace(wxSelectDispatcher_Trace,wxT("Got read event on fd %d"),i); - handler = FindHandler(i); - if (handler != NULL && wxFD_ISSET(i,&m_readset)) - handler->OnReadWaiting(i); - else - { - wxLogError(wxT("Lost fd in read fdset: %d, removing"),i); - wxFD_CLR(i,&m_readset); - }; - }; + if ( !wxMappedFDIODispatcher::RegisterFD(fd, handler, flags) ) + return false; - if (wxFD_ISSET(i, writeset)) - { - wxLogTrace(wxSelectDispatcher_Trace,wxT("Got write event on fd %d"),i); - if (handler == NULL) - handler = FindHandler(i); - if (handler != NULL && wxFD_ISSET(i,&m_writeset)) - handler->OnWriteWaiting(i); - else - { - wxLogError(wxT("Lost fd in write fdset: %d, removing"),i); - wxFD_CLR(i,&m_writeset); - }; - }; + if ( !m_sets.SetFD(fd, flags) ) + return false; + + if ( fd > m_maxFD ) + m_maxFD = fd; - if (wxFD_ISSET(i, exeptset)) + wxLogTrace(wxSelectDispatcher_Trace, + wxT("Registered fd %d: input:%d, output:%d, exceptional:%d"), fd, (flags & wxFDIO_INPUT) == wxFDIO_INPUT, (flags & wxFDIO_OUTPUT), (flags & wxFDIO_EXCEPTION) == wxFDIO_EXCEPTION); + return true; +} + +bool wxSelectDispatcher::ModifyFD(int fd, wxFDIOHandler *handler, int flags) +{ + if ( !wxMappedFDIODispatcher::ModifyFD(fd, handler, flags) ) + return false; + + wxASSERT_MSG( fd <= m_maxFD, wxT("logic error: registered fd > m_maxFD?") ); + + wxLogTrace(wxSelectDispatcher_Trace, + wxT("Modified fd %d: input:%d, output:%d, exceptional:%d"), fd, (flags & wxFDIO_INPUT) == wxFDIO_INPUT, (flags & wxFDIO_OUTPUT) == wxFDIO_OUTPUT, (flags & wxFDIO_EXCEPTION) == wxFDIO_EXCEPTION); + return m_sets.SetFD(fd, flags); +} + +bool wxSelectDispatcher::UnregisterFD(int fd) +{ + m_sets.ClearFD(fd); + + if ( !wxMappedFDIODispatcher::UnregisterFD(fd) ) + return false; + + // remove the handler if we don't need it any more + if ( !m_sets.HasFD(fd) ) + { + if ( fd == m_maxFD ) { - wxLogTrace(wxSelectDispatcher_Trace,wxT("Got exception event on fd %d"),i); - if (handler == NULL) - handler = FindHandler(i); - if (handler != NULL && wxFD_ISSET(i,&m_writeset)) - handler->OnExceptionWaiting(i); - else + // need to find new max fd + m_maxFD = -1; + for ( wxFDIOHandlerMap::const_iterator it = m_handlers.begin(); + it != m_handlers.end(); + ++it ) { - wxLogError(wxT("Lost fd in exept fdset: %d, removing"),i); - wxFD_CLR(i,&m_exeptset); - }; - }; - }; + if ( it->first > m_maxFD ) + { + m_maxFD = it->first; + } + } + } + } + + wxLogTrace(wxSelectDispatcher_Trace, + wxT("Removed fd %d, current max: %d"), fd, m_maxFD); + return true; } -wxFDIOHandler* wxSelectDispatcher::FindHandler(int fd) +int wxSelectDispatcher::ProcessSets(const wxSelectSets& sets) { - wxFDIOHandlerMap::const_iterator it = m_handlers.find(fd); - if (it != m_handlers.end()) - return it->second; - return NULL; -}; + int numEvents = 0; + for ( int fd = 0; fd <= m_maxFD; fd++ ) + { + if ( !sets.HasFD(fd) ) + continue; + + wxFDIOHandler * const handler = FindHandler(fd); + if ( !handler ) + { + wxFAIL_MSG( wxT("NULL handler in wxSelectDispatcher?") ); + continue; + } + + if ( sets.Handle(fd, *handler) ) + numEvents++; + } + + return numEvents; +} -void wxSelectDispatcher::RunLoop(int timeout) +int wxSelectDispatcher::DoSelect(wxSelectSets& sets, int timeout) const { - struct timeval tv, *ptv = NULL; - if ( timeout != wxSELECT_TIMEOUT_INFINITE ) + struct timeval tv, + *ptv; + if ( timeout != TIMEOUT_INFINITE ) { ptv = &tv; tv.tv_sec = 0; - tv.tv_usec = timeout*10; - }; - - int ret; - do + tv.tv_usec = timeout*1000; + } + else // no timeout { - fd_set readset = m_readset; - fd_set writeset = m_writeset; - fd_set exeptset = m_exeptset; - wxStopWatch sw; - if ( ptv && timeout ) - sw.Start(ptv->tv_usec/10); - ret = select(m_maxFD+1, &readset, &writeset, &exeptset, ptv); - switch ( ret ) - { - // TODO: handle unix signals here - case -1: - if ( !timeout ) - { - // it doesn't make sense to remain here - return; - } + ptv = NULL; + } - if ( ptv ) - { - ptv->tv_sec = 0; - ptv->tv_usec = timeout - sw.Time()*10; - } - break; + int ret = sets.Select(m_maxFD + 1, ptv); - // timeout - case 0: - break; + // TODO: we need to restart select() in this case but for now just return + // as if timeout expired + if ( ret == -1 && errno == EINTR ) + ret = 0; - default: - ProcessSets(&readset, &writeset, &exeptset, m_maxFD+1); - }; - } while (ret != 0); + return ret; } -// ---------------------------------------------------------------------------- -// wxSelectDispatcherModule -// ---------------------------------------------------------------------------- +bool wxSelectDispatcher::HasPending() const +{ + wxSelectSets sets(m_sets); + return DoSelect(sets, 0) > 0; +} -class wxSelectDispatcherModule: public wxModule +int wxSelectDispatcher::Dispatch(int timeout) { -public: - bool OnInit() { wxLog::AddTraceMask(wxSelectDispatcher_Trace); return true; } - void OnExit() { wxDELETE(wxSelectDispatcher::ms_instance); } + wxSelectSets sets(m_sets); + switch ( DoSelect(sets, timeout) ) + { + case -1: + wxLogSysError(_("Failed to monitor I/O channels")); + return -1; -private: - DECLARE_DYNAMIC_CLASS(wxSelectDispatcherModule) -}; + case 0: + // timeout expired without anything happening + return 0; -IMPLEMENT_DYNAMIC_CLASS(wxSelectDispatcherModule, wxModule) + default: + return ProcessSets(sets); + } +} +#endif // wxUSE_SELECT_DISPATCHER