diff options
author | Johnny Willemsen <jwillemsen@remedy.nl> | 2006-11-22 11:36:59 +0000 |
---|---|---|
committer | Johnny Willemsen <jwillemsen@remedy.nl> | 2006-11-22 11:36:59 +0000 |
commit | ecfec47c12065de780958ee23c485f710002c140 (patch) | |
tree | b7f56ac64b653351a988d47d1a59d07672e651a0 /ACE/ace/TkReactor | |
parent | 48d079bd56b9a4a7e71578c5ef3b52133c9d6631 (diff) | |
download | ATCD-ecfec47c12065de780958ee23c485f710002c140.tar.gz |
Wed Nov 22 10:45:12 2006 Johnny Willemsen <jwillemsen@remedy.nl>
Diffstat (limited to 'ACE/ace/TkReactor')
-rw-r--r-- | ACE/ace/TkReactor/ACE_TkReactor.pc.in | 11 | ||||
-rw-r--r-- | ACE/ace/TkReactor/ACE_TkReactor_export.h | 58 | ||||
-rw-r--r-- | ACE/ace/TkReactor/TkReactor.cpp | 439 | ||||
-rw-r--r-- | ACE/ace/TkReactor/TkReactor.h | 136 |
4 files changed, 644 insertions, 0 deletions
diff --git a/ACE/ace/TkReactor/ACE_TkReactor.pc.in b/ACE/ace/TkReactor/ACE_TkReactor.pc.in new file mode 100644 index 00000000000..e53797e600c --- /dev/null +++ b/ACE/ace/TkReactor/ACE_TkReactor.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ACE_TkReactor +Description: ACE TkReactor Library +Requires: ACE +Version: @VERSION@ +Libs: -L${libdir} -lACE_TkReactor +Cflags: -I${includedir} diff --git a/ACE/ace/TkReactor/ACE_TkReactor_export.h b/ACE/ace/TkReactor/ACE_TkReactor_export.h new file mode 100644 index 00000000000..bd74f861e60 --- /dev/null +++ b/ACE/ace/TkReactor/ACE_TkReactor_export.h @@ -0,0 +1,58 @@ + +// -*- C++ -*- +// $Id$ +// Definition for Win32 Export directives. +// This file is generated automatically by generate_export_file.pl -s ACE_TkReactor +// ------------------------------ +#ifndef ACE_TKREACTOR_EXPORT_H +#define ACE_TKREACTOR_EXPORT_H + +#include /**/ "ace/config-all.h" + +#if defined (ACE_AS_STATIC_LIBS) && !defined (ACE_TKREACTOR_HAS_DLL) +# define ACE_TKREACTOR_HAS_DLL 0 +#endif /* ACE_AS_STATIC_LIBS && ACE_TKREACTOR_HAS_DLL */ + +#if !defined (ACE_TKREACTOR_HAS_DLL) +# define ACE_TKREACTOR_HAS_DLL 1 +#endif /* ! ACE_TKREACTOR_HAS_DLL */ + +#if defined (ACE_TKREACTOR_HAS_DLL) && (ACE_TKREACTOR_HAS_DLL == 1) +# if defined (ACE_TKREACTOR_BUILD_DLL) +# define ACE_TkReactor_Export ACE_Proper_Export_Flag +# define ACE_TKREACTOR_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define ACE_TKREACTOR_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else /* ACE_TKREACTOR_BUILD_DLL */ +# define ACE_TkReactor_Export ACE_Proper_Import_Flag +# define ACE_TKREACTOR_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define ACE_TKREACTOR_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* ACE_TKREACTOR_BUILD_DLL */ +#else /* ACE_TKREACTOR_HAS_DLL == 1 */ +# define ACE_TkReactor_Export +# define ACE_TKREACTOR_SINGLETON_DECLARATION(T) +# define ACE_TKREACTOR_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* ACE_TKREACTOR_HAS_DLL == 1 */ + +// Set ACE_TKREACTOR_NTRACE = 0 to turn on library specific tracing even if +// tracing is turned off for ACE. +#if !defined (ACE_TKREACTOR_NTRACE) +# if (ACE_NTRACE == 1) +# define ACE_TKREACTOR_NTRACE 1 +# else /* (ACE_NTRACE == 1) */ +# define ACE_TKREACTOR_NTRACE 0 +# endif /* (ACE_NTRACE == 1) */ +#endif /* !ACE_TKREACTOR_NTRACE */ + +#if (ACE_TKREACTOR_NTRACE == 1) +# define ACE_TKREACTOR_TRACE(X) +#else /* (ACE_TKREACTOR_NTRACE == 1) */ +# if !defined (ACE_HAS_TRACE) +# define ACE_HAS_TRACE +# endif /* ACE_HAS_TRACE */ +# define ACE_TKREACTOR_TRACE(X) ACE_TRACE_IMPL(X) +# include "ace/Trace.h" +#endif /* (ACE_TKREACTOR_NTRACE == 1) */ + +#endif /* ACE_TKREACTOR_EXPORT_H */ + +// End of auto generated file. diff --git a/ACE/ace/TkReactor/TkReactor.cpp b/ACE/ace/TkReactor/TkReactor.cpp new file mode 100644 index 00000000000..942f66d7d1d --- /dev/null +++ b/ACE/ace/TkReactor/TkReactor.cpp @@ -0,0 +1,439 @@ +#include "ace/TkReactor/TkReactor.h" + +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Connector.h" + +ACE_RCSID(ace, TkReactor, "$Id$") + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE (ACE_TkReactor) + +// Must be called with lock held +ACE_TkReactor::ACE_TkReactor (size_t size, + int restart, + ACE_Sig_Handler *h) + : ACE_Select_Reactor (size, restart, h), + ids_ (0), + timeout_ (0) +{ + // When the ACE_Select_Reactor is constructed it creates the notify + // pipe and registers it with the register_handler_i() method. The + // TkReactor overloads this method BUT because the + // register_handler_i occurs when constructing the base class + // ACE_Select_Reactor, the ACE_Select_Reactor register_handler_i() + // is called not the TkReactor register_handler_i(). This means + // that the notify pipe is registered with the ACE_Select_Reactor + // event handling code not the TkReactor and so notfications don't + // work. To get around this we simply close and re-opened the + // notification handler in the constructor of the TkReactor. + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + this->notify_handler_->close (); + this->notify_handler_->open (this, 0); +#endif /* ACE_MT_SAFE */ +} + +ACE_TkReactor::~ACE_TkReactor (void) +{ + // Delete the remaining items in the linked list. + + while (this->ids_) + { + ACE_TkReactorID *TkID = this->ids_->next_; + delete this->ids_; + this->ids_ = TkID; + } +} + +// This is just the <wait_for_multiple_events> from ace/Reactor.cpp +// but we use the Tk functions to wait for an event, not <select> + +int +ACE_TkReactor::wait_for_multiple_events (ACE_Select_Reactor_Handle_Set &handle_set, + ACE_Time_Value *max_wait_time) +{ + ACE_TRACE ("ACE_TkReactor::wait_for_multiple_events"); + int nfound; + + do + { + max_wait_time = this->timer_queue_->calculate_timeout (max_wait_time); + + size_t width = this->handler_rep_.max_handlep1 (); + handle_set.rd_mask_ = this->wait_set_.rd_mask_; + handle_set.wr_mask_ = this->wait_set_.wr_mask_; + handle_set.ex_mask_ = this->wait_set_.ex_mask_; + nfound = TkWaitForMultipleEvents (width, + handle_set, + max_wait_time); + + } while (nfound == -1 && this->handle_error () > 0); + + if (nfound > 0) + { +#if !defined (ACE_WIN32) + handle_set.rd_mask_.sync (this->handler_rep_.max_handlep1 ()); + handle_set.wr_mask_.sync (this->handler_rep_.max_handlep1 ()); + handle_set.ex_mask_.sync (this->handler_rep_.max_handlep1 ()); +#endif /* ACE_WIN32 */ + } + return nfound; // Timed out or input available +} + +void +ACE_TkReactor::TimerCallbackProc (ClientData cd) +{ + ACE_TkReactor *self = (ACE_TkReactor *) cd; + self->timeout_ = 0; + + // Deal with any timer events + ACE_Select_Reactor_Handle_Set handle_set; + self->dispatch (0, handle_set); + self->reset_timeout (); +} + +/** + * @todo the unused mask argument is probably quite useful, but we + * ignore it, why? In fact the following comment probably + * relates to that: + * This could be made shorter if we know which *kind* of event + * we were about to get. Here we use <select> to find out which + * one might be available. + */ +void +ACE_TkReactor::InputCallbackProc (ClientData cd, + int /* mask */) +{ + ACE_TkReactor_Input_Callback *callback = (ACE_TkReactor_Input_Callback *) cd; + ACE_TkReactor *self = callback->reactor_; + ACE_HANDLE handle = callback->handle_; + + // my copy isn't const. + ACE_Time_Value zero = ACE_Time_Value::zero; + + ACE_Select_Reactor_Handle_Set wait_set; + + // Deal with one file event. + + // - read which kind of event + if (self->wait_set_.rd_mask_.is_set (handle)) + wait_set.rd_mask_.set_bit (handle); + if (self->wait_set_.wr_mask_.is_set (handle)) + wait_set.wr_mask_.set_bit (handle); + if (self->wait_set_.ex_mask_.is_set (handle)) + wait_set.ex_mask_.set_bit (handle); + + int result = ACE_OS::select (handle + 1, + wait_set.rd_mask_, + wait_set.wr_mask_, + wait_set.ex_mask_, &zero); + + ACE_Select_Reactor_Handle_Set dispatch_set; + + // - Use only that one file event (removes events for other files). + if (result > 0) + { + if (wait_set.rd_mask_.is_set (handle)) + dispatch_set.rd_mask_.set_bit (handle); + if (wait_set.wr_mask_.is_set (handle)) + dispatch_set.wr_mask_.set_bit (handle); + if (wait_set.ex_mask_.is_set (handle)) + dispatch_set.ex_mask_.set_bit (handle); + + self->dispatch (1, dispatch_set); + } +} + +int +ACE_TkReactor::TkWaitForMultipleEvents (int width, + ACE_Select_Reactor_Handle_Set &wait_set, + ACE_Time_Value *) +{ + // Check to make sure our handle's are all usable. + ACE_Select_Reactor_Handle_Set temp_set = wait_set; + + if (ACE_OS::select (width, + temp_set.rd_mask_, + temp_set.wr_mask_, + temp_set.ex_mask_, + (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) + return -1; // Bad file arguments... + + // Instead of waiting using <select>, just use the Tk mechanism to + // wait for a single event. + + // Wait for something to happen. + ::Tcl_DoOneEvent (0); + + // Reset the width, in case it changed during the upcalls. + width = this->handler_rep_.max_handlep1 (); + + // Now actually read the result needed by the <Select_Reactor> using + // <select>. + return ACE_OS::select (width, + wait_set.rd_mask_, + wait_set.wr_mask_, + wait_set.ex_mask_, + (ACE_Time_Value *) &ACE_Time_Value::zero); +} + +int +ACE_TkReactor::register_handler_i (ACE_HANDLE handle, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_TkReactor::register_handler_i"); + + int result = ACE_Select_Reactor::register_handler_i (handle, + handler, mask); + if (result == -1) + return -1; + + int condition = 0; + +#if !defined ACE_WIN32 + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::READ_MASK)) + ACE_SET_BITS (condition, TK_READABLE); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::WRITE_MASK)) + ACE_SET_BITS (condition, TK_WRITABLE); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::EXCEPT_MASK)) + ACE_SET_BITS (condition, TK_EXCEPTION); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::ACCEPT_MASK)) + ACE_SET_BITS (condition, TK_READABLE); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::CONNECT_MASK)){ + ACE_SET_BITS (condition, TK_READABLE); // connected, you may write + ACE_SET_BITS (condition, TK_WRITABLE); // connected, you have data/err + } +#else + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::READ_MASK)) + ACE_SET_BITS (condition, TK_READABLE); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::WRITE_MASK)) + ACE_SET_BITS (condition, TK_WRITABLE); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::EXCEPT_MASK)) + ACE_NOTSUP_RETURN(-1); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::ACCEPT_MASK)) + ACE_SET_BITS (condition, TK_READABLE); + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::CONNECT_MASK)){ + ACE_SET_BITS (condition, TK_READABLE); // connected, you may write + ACE_SET_BITS (condition, TK_WRITABLE); // connected, you have data/err + } +#endif /* !ACE_WIN32 */ + + if (condition != 0) + { + ACE_TkReactorID *TkID = this->ids_; + + while(TkID) + { + if (TkID->handle_ == handle) + { + ::Tk_DeleteFileHandler (TkID->handle_); + + ACE_TkReactor_Input_Callback *callback; + ACE_NEW_RETURN (callback, + ACE_TkReactor_Input_Callback, + -1); + callback->reactor_ = this; + callback->handle_ = handle; + ::Tk_CreateFileHandler ((int) handle, + condition, + InputCallbackProc, + (ClientData) callback); + return 0; + } + else + TkID = TkID->next_; + } + + ACE_NEW_RETURN (TkID, + ACE_TkReactorID, + -1); + TkID->next_ = this->ids_; + TkID->handle_ = handle; + ACE_TkReactor_Input_Callback *callback; + ACE_NEW_RETURN (callback, + ACE_TkReactor_Input_Callback, + -1); + callback->reactor_ = this; + callback->handle_ = handle; + + ::Tk_CreateFileHandler ((int) handle, + condition, + InputCallbackProc, + (ClientData) callback); + this->ids_ = TkID; + } + return 0; +} + +int +ACE_TkReactor::register_handler_i (const ACE_Handle_Set &handles, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask) +{ + return ACE_Select_Reactor::register_handler_i (handles, + handler, + mask); +} + +int +ACE_TkReactor::remove_handler_i (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_TkReactor::remove_handler_i"); + + // In the registration phase we registered first with + // ACE_Select_Reactor and then with X. Now we are now doing things + // in reverse order. + + // First clean up the corresponding X11Input. + this->remove_TkFileHandler (handle); + + // Now let the reactor do its work. + return ACE_Select_Reactor::remove_handler_i (handle, + mask); +} + +void +ACE_TkReactor::remove_TkFileHandler (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE_TkReactor::remove_TkFileHandler"); + + ACE_TkReactorID *TkID = this->ids_; + + if (TkID) + { + if (TkID->handle_ == handle) + { + ::Tk_DeleteFileHandler (TkID->handle_); + this->ids_ = TkID->next_; + delete TkID; + return; + } + + ACE_TkReactorID *NextID = TkID->next_; + + while (NextID) + { + if (NextID->handle_ == handle) + { + ::Tk_DeleteFileHandler (NextID->handle_); + TkID->next_ = NextID->next_; + delete NextID; + return; + } + else + { + TkID = NextID; + NextID = NextID->next_; + } + } + } +} + +int +ACE_TkReactor::remove_handler_i (const ACE_Handle_Set &handles, + ACE_Reactor_Mask mask) +{ + return ACE_Select_Reactor::remove_handler_i (handles, + mask); +} + +// The following functions ensure that there is an Tk timeout for the +// first timeout in the Reactor's Timer_Queue. + +void +ACE_TkReactor::reset_timeout (void) +{ + if (this->timeout_) + ::Tk_DeleteTimerHandler (this->timeout_); + timeout_ = 0; + + ACE_Time_Value *max_wait_time = + this->timer_queue_->calculate_timeout (0); + + if (max_wait_time) + timeout_ = ::Tk_CreateTimerHandler (max_wait_time->msec (), + TimerCallbackProc, + (ClientData) this); +} + +int +ACE_TkReactor::reset_timer_interval + (long timer_id, + const ACE_Time_Value &interval) +{ + ACE_TRACE ("ACE_TkReactor::reset_timer_interval"); + ACE_MT (ACE_GUARD_RETURN (ACE_Select_Reactor_Token, ace_mon, this->token_, -1)); + + int result = ACE_Select_Reactor::timer_queue_->reset_interval + (timer_id, + interval); + + if (result == -1) + return -1; + else + { + this->reset_timeout (); + return result; + } +} + +long +ACE_TkReactor::schedule_timer (ACE_Event_Handler *event_handler, + const void *arg, + const ACE_Time_Value &delay, + const ACE_Time_Value &interval) +{ + ACE_TRACE ("ACE_TkReactor::schedule_timer"); + ACE_MT (ACE_GUARD_RETURN (ACE_Select_Reactor_Token, ace_mon, this->token_, -1)); + + long result = ACE_Select_Reactor::schedule_timer (event_handler, + arg, + delay, + interval); + if (result == -1) + return -1; + else + { + this->reset_timeout (); + return result; + } +} + +int +ACE_TkReactor::cancel_timer (ACE_Event_Handler *handler, + int dont_call_handle_close) +{ + ACE_TRACE ("ACE_TkReactor::cancel_timer"); + + if (ACE_Select_Reactor::cancel_timer (handler, + dont_call_handle_close) == -1) + return -1; + else + { + this->reset_timeout (); + return 0; + } +} + +int +ACE_TkReactor::cancel_timer (long timer_id, + const void **arg, + int dont_call_handle_close) +{ + ACE_TRACE ("ACE_TkReactor::cancel_timer"); + + if (ACE_Select_Reactor::cancel_timer (timer_id, + arg, + dont_call_handle_close) == -1) + return -1; + else + { + this->reset_timeout (); + return 0; + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/ace/TkReactor/TkReactor.h b/ACE/ace/TkReactor/TkReactor.h new file mode 100644 index 00000000000..80583bb8999 --- /dev/null +++ b/ACE/ace/TkReactor/TkReactor.h @@ -0,0 +1,136 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file TkReactor.h + * + * $Id$ + * + * @author Nagarajan Surendran <naga@cs.wustl.edu> + */ +//============================================================================= + + +#ifndef ACE_TKREACTOR_H +#define ACE_TKREACTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/TkReactor/ACE_TkReactor_export.h" +#include "ace/Select_Reactor.h" +#include /**/ <tk.h> + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_TkReactorID + * + * @brief This little class is necessary due to the way that Microsoft + * implements sockets to be pointers rather than indices. + */ +class ACE_TkReactor_Export ACE_TkReactorID +{ +public: + /// Underlying handle. + ACE_HANDLE handle_; + + /// Pointer to next node in the linked list. + ACE_TkReactorID *next_; +}; + +class ACE_TkReactor; + +class ACE_TkReactor_Export ACE_TkReactor_Input_Callback +{ +public: + ACE_TkReactor *reactor_; + ACE_HANDLE handle_; +}; + +/** + * @class ACE_TkReactor + * + * @brief An object-oriented event demultiplexor and event handler + * dispatcher that uses the Tk functions. + */ +class ACE_TkReactor_Export ACE_TkReactor : public ACE_Select_Reactor +{ +public: + // = Initialization and termination methods. + ACE_TkReactor (size_t size = DEFAULT_SIZE, + int restart = 0, + ACE_Sig_Handler * = 0); + + virtual ~ACE_TkReactor (void); + + // = Timer operations. + virtual long schedule_timer (ACE_Event_Handler *event_handler, + const void *arg, + const ACE_Time_Value &delay, + const ACE_Time_Value &interval); + virtual int reset_timer_interval (long timer_id, + const ACE_Time_Value &interval); + virtual int cancel_timer (ACE_Event_Handler *handler, + int dont_call_handle_close = 1); + virtual int cancel_timer (long timer_id, + const void **arg = 0, + int dont_call_handle_close = 1); + +protected: + // = Register timers/handles with Tk. + /// Register a single <handler>. + virtual int register_handler_i (ACE_HANDLE handle, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask); + + /// Register a set of <handlers>. + virtual int register_handler_i (const ACE_Handle_Set &handles, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask); + + /// Remove the <handler> associated with this <handle>. + virtual int remove_handler_i (ACE_HANDLE handle, + ACE_Reactor_Mask mask); + + /// Remove a set of <handles>. + virtual int remove_handler_i (const ACE_Handle_Set &handles, + ACE_Reactor_Mask); + + /// Removes an Tk FileHandler. + virtual void remove_TkFileHandler (ACE_HANDLE handle); + + /// Wait for events to occur. + virtual int wait_for_multiple_events (ACE_Select_Reactor_Handle_Set &, + ACE_Time_Value *); + + ///Wait for Tk events to occur. + virtual int TkWaitForMultipleEvents (int, + ACE_Select_Reactor_Handle_Set &, + ACE_Time_Value *); + + ACE_TkReactorID *ids_; + Tk_TimerToken timeout_; + +private: + /// This method ensures there's a Tk timeout for the first timeout in + /// the Reactor's Timer_Queue. + void reset_timeout (void); + + // = Integrate with the X callback function mechanism. + static void TimerCallbackProc (ClientData cd); + static void InputCallbackProc (ClientData cd,int mask); + + /// Deny access since member-wise won't work... + ACE_TkReactor (const ACE_TkReactor &); + ACE_TkReactor &operator = (const ACE_TkReactor &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_TK_REACTOR_H */ |