From 30c45bdd06c4174d28f62133692733d447d008ea Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 16 Mar 2007 15:45:12 +0000 Subject: [PATCH] refactoring: replace wxSocketDispatcher with more generic wxSelectDispatcher (patch 1618976) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44855 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 6 +- include/wx/private/gsocketiohandler.h | 42 +++++ include/wx/private/selectdispatcher.h | 93 ++++++++++ include/wx/private/socketevtdispatch.h | 71 -------- include/wx/unix/private.h | 8 + src/common/gsocketiohandler.cpp | 199 ++++++++++++++++++++ src/common/selectdispatcher.cpp | 240 +++++++++++++++++++++++++ src/dfb/evtloop.cpp | 4 +- src/x11/evtloop.cpp | 4 +- 9 files changed, 590 insertions(+), 77 deletions(-) create mode 100644 include/wx/private/gsocketiohandler.h create mode 100644 include/wx/private/selectdispatcher.h delete mode 100644 include/wx/private/socketevtdispatch.h create mode 100644 src/common/gsocketiohandler.cpp create mode 100644 src/common/selectdispatcher.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index c84b4c7fa1..2e4248bcaf 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -1400,7 +1400,8 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! $(XWIN_LOWLEVEL_SRC) - src/common/socketevtdispatch.cpp + src/common/gsocketiohandler.cpp + src/common/selectdispatcher.cpp src/generic/icon.cpp src/generic/timer.cpp src/x11/app.cpp @@ -1820,7 +1821,8 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/common/fontmgrcmn.cpp - src/common/socketevtdispatch.cpp + src/common/gsocketiohandler.cpp + src/common/selectdispatcher.cpp src/generic/caret.cpp src/generic/colour.cpp src/generic/icon.cpp diff --git a/include/wx/private/gsocketiohandler.h b/include/wx/private/gsocketiohandler.h new file mode 100644 index 0000000000..8db8916253 --- /dev/null +++ b/include/wx/private/gsocketiohandler.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/private/gsocketiohandler.h +// Purpose: class for registering GSocket in wxSelectDispatcher +// Authors: Lukasz Michalski +// Modified by: +// Created: December 2006 +// Copyright: (c) Lukasz Michalski +// RCS-ID: $Id$ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_GSOCKETIOHANDLER_H_ +#define _WX_PRIVATE_GSOCKETIOHANDLER_H_ + +#include "wx/defs.h" +#include "wx/private/selectdispatcher.h" + +#if wxUSE_SOCKETS + +// forward declarations +class GSocket; + +class WXDLLIMPEXP_CORE wxGSocketIOHandler : public wxFDIOHandler +{ +public: + wxGSocketIOHandler(GSocket* socket); + int GetFlags() const; + void RemoveFlag(wxSelectDispatcherEntryFlags flag); + void AddFlag(wxSelectDispatcherEntryFlags flag); + +private: + virtual void OnReadWaiting(int fd); + virtual void OnWriteWaiting(int fd); + virtual void OnExceptionWaiting(int fd); + + GSocket* m_socket; + int m_flags; +}; + +#endif // wxUSE_SOCKETS + +#endif // _WX_PRIVATE_SOCKETEVTDISPATCH_H_ diff --git a/include/wx/private/selectdispatcher.h b/include/wx/private/selectdispatcher.h new file mode 100644 index 0000000000..04072c1be1 --- /dev/null +++ b/include/wx/private/selectdispatcher.h @@ -0,0 +1,93 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/private/selectdispatcher.h +// Purpose: wxSelectDispatcher class +// Authors: Lukasz Michalski +// Modified by: +// Created: December 2006 +// Copyright: (c) Lukasz Michalski +// RCS-ID: $Id$ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_SELECTDISPATCHER_H_ +#define _WX_PRIVATE_SELECTDISPATCHER_H_ + +#include "wx/defs.h" + +#include "wx/hashmap.h" + +static const int wxSELECT_TIMEOUT_INFINITE = -1; + +// handler used to process events on descriptors +class wxFDIOHandler +{ +public: + // called when descriptor is available for non-blocking read + virtual void OnReadWaiting(int fd) = 0; + + // called when descriptor is available for non-blocking write + virtual void OnWriteWaiting(int fd) = 0; + + // called when there is exception on descriptor + virtual void OnExceptionWaiting(int fd) = 0; +}; + +// those flags describes sets where descriptor should be added +enum wxSelectDispatcherEntryFlags +{ + wxSelectInput = 1, + wxSelectOutput = 2, + wxSelectException = 4, + wxSelectAll = wxSelectInput | wxSelectOutput | wxSelectException +}; + +WX_DECLARE_HASH_MAP( + int, + wxFDIOHandler*, + wxIntegerHash, + wxIntegerEqual, + wxFDIOHandlerMap +); + +class WXDLLIMPEXP_CORE wxSelectDispatcher +{ +public: + // returns instance of the table + static wxSelectDispatcher& Get(); + + virtual ~wxSelectDispatcher() + { + } + + // register descriptor in sets. + void RegisterFD(int fd, wxFDIOHandler* handler, int flags = wxSelectAll); + + // unregister descriptor from sets and return handler for cleanup + wxFDIOHandler* UnregisterFD(int fd, int flags = wxSelectAll); + + // return handler for descriptor or null if fd is not registered + wxFDIOHandler* FindHandler(int fd); + + // calls select on registered descriptors and + void RunLoop(int timeout = wxSELECT_TIMEOUT_INFINITE); + +protected: + wxSelectDispatcher() { } + +private: + void ProcessSets(fd_set* readset, fd_set* writeset, fd_set* exeptset, int max_fd); + + fd_set m_readset; + fd_set m_writeset; + fd_set m_exeptset; + + int m_maxFD; + wxFDIOHandlerMap m_handlers; + + static wxSelectDispatcher *ms_instance; + + friend class wxSelectDispatcherModule; +}; + + +#endif // _WX_PRIVATE_SOCKETEVTDISPATCH_H_ diff --git a/include/wx/private/socketevtdispatch.h b/include/wx/private/socketevtdispatch.h deleted file mode 100644 index d474e05f81..0000000000 --- a/include/wx/private/socketevtdispatch.h +++ /dev/null @@ -1,71 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: wx/private/socketevtdispatch.h -// Purpose: wxSocketEventDispatcher class -// Authors: Angel Vidal -// Modified by: -// Created: August 2006 -// Copyright: (c) Angel Vidal -// RCS-ID: $Id$ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifndef _WX_PRIVATE_SOCKETEVTDISPATCH_H_ -#define _WX_PRIVATE_SOCKETEVTDISPATCH_H_ - -#include "wx/defs.h" - -#if wxUSE_SOCKETS - -#ifdef __VMS -#include -#endif - -#include "wx/hash.h" - -// forward declarations -class wxSocketEventDispatcherEntry; -class GSocket; - -enum wxSocketEventDispatcherType -{ - wxSocketEventDispatcherInput, - wxSocketEventDispatcherOutput -}; - -class WXDLLIMPEXP_CORE wxSocketEventDispatcher : public wxHashTable -{ -protected: - wxSocketEventDispatcher() : wxHashTable(wxKEY_INTEGER) {} - -public: - // returns instance of the table - static wxSocketEventDispatcher& Get(); - - virtual ~wxSocketEventDispatcher() - { - WX_CLEAR_HASH_TABLE(*this) - } - - void RegisterCallback(int fd, wxSocketEventDispatcherType socketType, - GSocket* socket); - - void UnregisterCallback(int fd, wxSocketEventDispatcherType socketType); - - void RunLoop(int timeout = 0); - -private: - void AddEvents(fd_set* readset, fd_set* writeset); - - int FillSets(fd_set* readset, fd_set* writeset); - - wxSocketEventDispatcherEntry* FindEntry(int fd); - -private: - static wxSocketEventDispatcher *ms_instance; - - friend class wxSocketEventDispatcherModule; -}; - -#endif // wxUSE_SOCKETS - -#endif // _WX_PRIVATE_SOCKETEVTDISPATCH_H_ diff --git a/include/wx/unix/private.h b/include/wx/unix/private.h index 9d2e338107..3995e70772 100644 --- a/include/wx/unix/private.h +++ b/include/wx/unix/private.h @@ -36,10 +36,18 @@ return FD_ISSET(fd, fds); #pragma warning(pop) } + inline bool wxFD_CLR(int fd, fd_set *fds) + { + #pragma warning(push, 1) + #pragma warning(disable:1469) + return FD_CLR(fd, fds); + #pragma warning(pop) + } #else // !__INTELC__ #define wxFD_ZERO(fds) FD_ZERO(fds) #define wxFD_SET(fd, fds) FD_SET(fd, fds) #define wxFD_ISSET(fd, fds) FD_ISSET(fd, fds) + #define wxFD_CLR(fd, fds) FD_CLR(fd, fds) #endif // __INTELC__/!__INTELC__ diff --git a/src/common/gsocketiohandler.cpp b/src/common/gsocketiohandler.cpp new file mode 100644 index 0000000000..35fd89640e --- /dev/null +++ b/src/common/gsocketiohandler.cpp @@ -0,0 +1,199 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/gsocketiohandler.cpp +// Purpose: implementation of wxFDIOHandler for GSocket +// Author: Angel Vidal, Lukasz Michalski +// Modified by: +// Created: 08.24.06 +// RCS-ID: $Id$ +// Copyright: (c) 2006 Angel vidal +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_SOCKETS + +#include "wx/private/gsocketiohandler.h" +#include "wx/unix/private.h" +#include "wx/gsocket.h" +#include "wx/unix/gsockunx.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxGSocketIOHandler +// ---------------------------------------------------------------------------- + +wxGSocketIOHandler::wxGSocketIOHandler(GSocket* socket) + : m_socket(socket), + m_flags(0) +{ + +}; + +void wxGSocketIOHandler::OnReadWaiting(int fd) +{ + m_socket->Detected_Read(); +}; + +void wxGSocketIOHandler::OnWriteWaiting(int fd) +{ + m_socket->Detected_Write(); +}; + +void wxGSocketIOHandler::OnExceptionWaiting(int fd) +{ + m_socket->Detected_Read(); +}; + +int wxGSocketIOHandler::GetFlags() const +{ + return m_flags; +}; + + +void wxGSocketIOHandler::RemoveFlag(wxSelectDispatcherEntryFlags flag) +{ + m_flags &= ~flag; +}; + +void wxGSocketIOHandler::AddFlag(wxSelectDispatcherEntryFlags flag) +{ + m_flags |= flag; +}; + +// ---------------------------------------------------------------------------- +// GSocket interface +// ---------------------------------------------------------------------------- + +bool GSocketGUIFunctionsTableConcrete::CanUseEventLoop() +{ + return true; +} + +bool GSocketGUIFunctionsTableConcrete::OnInit() +{ + return true; +} + +void GSocketGUIFunctionsTableConcrete::OnExit() +{ +} + +bool GSocketGUIFunctionsTableConcrete::Init_Socket(GSocket *socket) +{ + int *m_id; + + socket->m_gui_dependent = (char *)malloc(sizeof(int)*2); + m_id = (int *)(socket->m_gui_dependent); + + m_id[0] = -1; + m_id[1] = -1; + + return true; +} + +void GSocketGUIFunctionsTableConcrete::Destroy_Socket(GSocket *socket) +{ + free(socket->m_gui_dependent); +} + +void GSocketGUIFunctionsTableConcrete::Install_Callback(GSocket *socket, + GSocketEvent event) +{ + int *m_id = (int *)(socket->m_gui_dependent); + int c; + + if (socket->m_fd == -1) + return; + + switch (event) + { + case GSOCK_LOST: /* fall-through */ + case GSOCK_INPUT: c = 0; break; + case GSOCK_OUTPUT: c = 1; break; + case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; + default: return; + } + + wxGSocketIOHandler* handler = (wxGSocketIOHandler*)(wxSelectDispatcher::Get().FindHandler(socket->m_fd)); + if (handler == NULL) + { + handler = new wxGSocketIOHandler(socket); + }; + + if (c == 0) + { + m_id[0] = socket->m_fd; + handler->AddFlag(wxSelectInput); + } + else + { + m_id[1] = socket->m_fd; + handler->AddFlag(wxSelectOutput); + } + + wxSelectDispatcher::Get().RegisterFD(socket->m_fd,handler,handler->GetFlags()); +} + +void GSocketGUIFunctionsTableConcrete::Uninstall_Callback(GSocket *socket, + GSocketEvent event) +{ + int *m_id = (int *)(socket->m_gui_dependent); + int c; + + switch (event) + { + case GSOCK_LOST: /* fall-through */ + case GSOCK_INPUT: c = 0; break; + case GSOCK_OUTPUT: c = 1; break; + case GSOCK_CONNECTION: c = ((socket->m_server) ? 0 : 1); break; + default: return; + } + + wxGSocketIOHandler* handler = NULL; + if ( m_id[c] != -1 ) + { + if ( c == 0 ) + { + handler = (wxGSocketIOHandler*)wxSelectDispatcher::Get().UnregisterFD(m_id[c], wxSelectInput); + if (handler != NULL) + handler->RemoveFlag(wxSelectInput); + } + else + { + handler = (wxGSocketIOHandler*)wxSelectDispatcher::Get().UnregisterFD(m_id[c], wxSelectOutput); + if (handler != NULL) + handler->RemoveFlag(wxSelectOutput); + } + if (handler && handler->GetFlags() == 0) + delete handler; + } + + m_id[c] = -1; +} + +void GSocketGUIFunctionsTableConcrete::Enable_Events(GSocket *socket) +{ + Install_Callback(socket, GSOCK_INPUT); + Install_Callback(socket, GSOCK_OUTPUT); +} + +void GSocketGUIFunctionsTableConcrete::Disable_Events(GSocket *socket) +{ + Uninstall_Callback(socket, GSOCK_INPUT); + Uninstall_Callback(socket, GSOCK_OUTPUT); +} + +#endif // wxUSE_SOCKETS diff --git a/src/common/selectdispatcher.cpp b/src/common/selectdispatcher.cpp new file mode 100644 index 0000000000..f58665f8ee --- /dev/null +++ b/src/common/selectdispatcher.cpp @@ -0,0 +1,240 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/socketevtdispatch.cpp +// Purpose: implements dispatcher for select() call +// Author: Lukasz Michalski +// Created: December 2006 +// RCS-ID: $Id$ +// Copyright: (c) 2006 Lukasz Michalski +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#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" +#endif + +#include +#include + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#define wxSelectDispatcher_Trace wxT("selectdispatcher") + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSelectDispatcher +// ---------------------------------------------------------------------------- + +wxSelectDispatcher* wxSelectDispatcher::ms_instance = NULL; + +/* static */ +wxSelectDispatcher& wxSelectDispatcher::Get() +{ + if ( !ms_instance ) + ms_instance = new wxSelectDispatcher; + return *ms_instance; +} + +void +wxSelectDispatcher::RegisterFD(int fd, wxFDIOHandler* handler, int flags) +{ + if ((flags & wxSelectInput) == wxSelectInput) + { + wxFD_SET(fd, &m_readset); + wxLogTrace(wxSelectDispatcher_Trace,wxT("Registered fd %d for input events"),fd); + }; + + if ((flags & wxSelectOutput) == wxSelectOutput) + { + wxFD_SET(fd, &m_writeset); + wxLogTrace(wxSelectDispatcher_Trace,wxT("Registered fd %d for output events"),fd); + } + + if ((flags & wxSelectException) == wxSelectException) + { + wxFD_SET(fd, &m_exeptset); + wxLogTrace(wxSelectDispatcher_Trace,wxT("Registered fd %d for exception events"),fd); + }; + + m_handlers[fd] = handler; + if (fd > m_maxFD) + m_maxFD = fd; +} + +wxFDIOHandler* +wxSelectDispatcher::UnregisterFD(int fd, int flags) +{ + // GSocket likes to unregister -1 descriptor + if (fd == -1) + return NULL; + + if ((flags & wxSelectInput) == wxSelectInput) + { + wxLogTrace(wxSelectDispatcher_Trace,wxT("Unregistered fd %d from input events"),fd); + wxFD_CLR(fd, &m_readset); + } + + if ((flags & wxSelectOutput) == wxSelectOutput) + { + wxLogTrace(wxSelectDispatcher_Trace,wxT("Unregistered fd %d from output events"),fd); + wxFD_CLR(fd, &m_writeset); + } + + if ((flags & wxSelectException) == wxSelectException) + { + wxLogTrace(wxSelectDispatcher_Trace,wxT("Unregistered fd %d from exeption events"),fd); + wxFD_CLR(fd, &m_exeptset); + }; + + wxFDIOHandler* ret = NULL; + wxFDIOHandlerMap::const_iterator it = m_handlers.find(fd); + if (it != m_handlers.end()) + { + ret = it->second; + if (!wxFD_ISSET(fd,&m_readset) && !wxFD_ISSET(fd,&m_writeset) && !wxFD_ISSET(fd,&m_exeptset)) + { + m_handlers.erase(it); + if ( m_handlers.empty() ) + m_maxFD = 0; + }; + }; + return ret; +} + +void wxSelectDispatcher::ProcessSets(fd_set* readset, fd_set* writeset, fd_set* exeptset, int max_fd) +{ + // 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 (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 (wxFD_ISSET(i, exeptset)) + { + 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 + { + wxLogError(wxT("Lost fd in exept fdset: %d, removing"),i); + wxFD_CLR(i,&m_exeptset); + }; + }; + }; +} + +wxFDIOHandler* wxSelectDispatcher::FindHandler(int fd) +{ + wxFDIOHandlerMap::const_iterator it = m_handlers.find(fd); + if (it != m_handlers.end()) + return it->second; + return NULL; +}; + +void wxSelectDispatcher::RunLoop(int timeout) +{ + struct timeval tv, *ptv = NULL; + if ( timeout != wxSELECT_TIMEOUT_INFINITE ) + { + ptv = &tv; + tv.tv_sec = 0; + tv.tv_usec = timeout*10; + }; + + int ret; + do + { + fd_set readset = m_readset; + fd_set writeset = m_writeset; + fd_set exeptset = m_exeptset; + wxStopWatch sw; + if ( ptv ) + 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 ( ptv ) + { + ptv->tv_sec = 0; + ptv->tv_usec = timeout - sw.Time()*10; + } + break; + + // timeout + case 0: + break; + + default: + ProcessSets(&readset, &writeset, &exeptset, m_maxFD+1); + }; + } while (ret != 0); +} + +// ---------------------------------------------------------------------------- +// wxSelectDispatcherModule +// ---------------------------------------------------------------------------- + +class wxSelectDispatcherModule: public wxModule +{ +public: + bool OnInit() { wxLog::AddTraceMask(wxSelectDispatcher_Trace); return true; } + void OnExit() { wxDELETE(wxSelectDispatcher::ms_instance); } + +private: + DECLARE_DYNAMIC_CLASS(wxSelectDispatcherModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxSelectDispatcherModule, wxModule) + diff --git a/src/dfb/evtloop.cpp b/src/dfb/evtloop.cpp index ee7154ff1e..c4c6c3bdeb 100644 --- a/src/dfb/evtloop.cpp +++ b/src/dfb/evtloop.cpp @@ -27,7 +27,7 @@ #include "wx/thread.h" #include "wx/timer.h" -#include "wx/private/socketevtdispatch.h" +#include "wx/private/selectdispatcher.h" #include "wx/dfb/private.h" #include "wx/nonownedwnd.h" @@ -141,7 +141,7 @@ void wxEventLoop::OnNextIteration() #if wxUSE_SOCKETS // handle any pending socket events: - wxSocketEventDispatcher::Get().RunLoop(); + wxSelectDispatcher::Get().RunLoop(0); #endif } diff --git a/src/x11/evtloop.cpp b/src/x11/evtloop.cpp index ed86512596..5609a82ab1 100644 --- a/src/x11/evtloop.cpp +++ b/src/x11/evtloop.cpp @@ -30,7 +30,7 @@ #include "wx/module.h" #endif -#include "wx/private/socketevtdispatch.h" +#include "wx/private/selectdispatcher.h" #include "wx/unix/private.h" #include "wx/x11/private.h" #include "X11/Xlib.h" @@ -263,7 +263,7 @@ bool wxEventLoop::Dispatch() #if wxUSE_SOCKETS // handle any pending socket events: - wxSocketEventDispatcher::Get().RunLoop(); + wxSelectDispatcher::Get().RunLoop(0); #endif (void) m_impl->ProcessEvent( &event ); -- 2.45.2