// -*- C++ -*- //============================================================================= /** * @file Select_Reactor_Base.h * * @author Douglas C. Schmidt */ //============================================================================= #ifndef ACE_SELECT_REACTOR_BASE_H #define ACE_SELECT_REACTOR_BASE_H #include /**/ "ace/pre.h" #include "ace/Timer_Queuefwd.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "ace/Event_Handler.h" #include "ace/Handle_Set.h" #include "ace/Pipe.h" #include "ace/Reactor_Impl.h" #if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) # include "ace/Notification_Queue.h" #endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ #if defined (ACE_WIN32) || defined (ACE_MQX) # ifndef ACE_SELECT_REACTOR_BASE_USES_HASH_MAP # define ACE_SELECT_REACTOR_BASE_USES_HASH_MAP # endif #endif #ifdef ACE_SELECT_REACTOR_BASE_USES_HASH_MAP # include "ace/Null_Mutex.h" # include "ace/Hash_Map_Manager_T.h" # include "ace/Functor.h" /* For ACE_Hash */ # include /* For std::equal_to<> */ #else # include "ace/Array_Base.h" #endif /* ACE_SELECT_REACTOR_BASE_USES_HASH_MAP */ #if !defined (ACE_DISABLE_NOTIFY_PIPE_DEFAULT) # define ACE_DISABLE_NOTIFY_PIPE_DEFAULT 0 #endif /* ACE_DISABLE_NOTIFY_PIPE_DEFAULT */ ACE_BEGIN_VERSIONED_NAMESPACE_DECL // Add useful typedefs to simplify the following code. typedef void (ACE_Handle_Set::*ACE_FDS_PTMF) (ACE_HANDLE); typedef int (ACE_Event_Handler::*ACE_EH_PTMF) (ACE_HANDLE); // Forward declaration. class ACE_Select_Reactor_Impl; class ACE_Sig_Handler; /** * @class ACE_Select_Reactor_Handle_Set * * @brief Track handles we are interested for various events. */ class ACE_Export ACE_Select_Reactor_Handle_Set { public: /// Read events (e.g., input pending, accept pending). ACE_Handle_Set rd_mask_; /// Write events (e.g., flow control abated, non-blocking connection /// complete). ACE_Handle_Set wr_mask_; /// Exception events (e.g., SIG_URG). ACE_Handle_Set ex_mask_; }; /** * @class ACE_Event_Tuple * * @brief An ACE_Event_Handler and its associated ACE_HANDLE. * * One ACE_Event_Handler is registered for one or more * ACE_HANDLE. At various points, this information must be * stored explicitly. This class provides a lightweight * mechanism to do so. */ class ACE_Event_Tuple { public: /// Default constructor. ACE_Event_Tuple (void); /// Constructor. ACE_Event_Tuple (ACE_Event_Handler *eh, ACE_HANDLE h); /// Equality operator. bool operator== (const ACE_Event_Tuple &rhs) const; /// Inequality operator. bool operator!= (const ACE_Event_Tuple &rhs) const; public: /// Handle. ACE_HANDLE handle_; /// ACE_Event_Handler associated with the ACE_HANDLE. ACE_Event_Handler *event_handler_; }; /** * @class ACE_Select_Reactor_Notify * * @brief Unblock the ACE_Select_Reactor from its event loop. * * This implementation is necessary for cases where the * ACE_Select_Reactor is run in a multi-threaded program. In * this case, we need to be able to unblock @c select or @c poll * when updates occur other than in the main * ACE_Select_Reactor thread. To do this, we signal an * auto-reset event the ACE_Select_Reactor is listening on. * If an ACE_Event_Handler and ACE_Select_Reactor_Mask is * passed to @c notify, the appropriate @c handle_* method is * dispatched in the context of the ACE_Select_Reactor thread. */ class ACE_Export ACE_Select_Reactor_Notify : public ACE_Reactor_Notify { public: /// Constructor. ACE_Select_Reactor_Notify (void); /// Destructor. virtual ~ACE_Select_Reactor_Notify (void); /// Initialize. virtual int open (ACE_Reactor_Impl *, ACE_Timer_Queue * = 0, int disable_notify_pipe = ACE_DISABLE_NOTIFY_PIPE_DEFAULT); /// Destroy. virtual int close (void); /** * Called by a thread when it wants to unblock the * ACE_Select_Reactor. This wakeups the ACE_Select_Reactor if * currently blocked in @c select/poll. Pass over both the * @c Event_Handler *and* the @c mask to allow the caller to dictate * which @c Event_Handler method the ACE_Select_Reactor will * invoke. The ACE_Time_Value indicates how long to blocking * trying to notify the ACE_Select_Reactor. If @a timeout == 0, * the caller will block until action is possible, else will wait * until the relative time specified in @c *timeout elapses). */ virtual int notify (ACE_Event_Handler * = 0, ACE_Reactor_Mask = ACE_Event_Handler::EXCEPT_MASK, ACE_Time_Value * timeout = 0); /// Handles pending threads (if any) that are waiting to unblock the /// ACE_Select_Reactor. virtual int dispatch_notifications (int &number_of_active_handles, ACE_Handle_Set &rd_mask); /// Returns the ACE_HANDLE of the notify pipe on which the reactor /// is listening for notifications so that other threads can unblock /// the Select_Reactor virtual ACE_HANDLE notify_handle (void); /// Handle one of the notify call on the @c handle. This could be /// because of a thread trying to unblock the Reactor_Impl virtual int dispatch_notify (ACE_Notification_Buffer &buffer); /// Read one of the notify call on the @a handle into the /// @a buffer. This could be because of a thread trying to unblock /// the Reactor_Impl /// /// Return value semantics for this are: /// -1: nothing read, fatal, unrecoverable error /// 0: nothing read at all /// 1: complete buffer read virtual int read_notify_pipe (ACE_HANDLE handle, ACE_Notification_Buffer &buffer); /// Verify whether the buffer has dispatchable info or not. virtual int is_dispatchable (ACE_Notification_Buffer &buffer); /// Called back by the ACE_Select_Reactor when a thread wants to /// unblock us. virtual int handle_input (ACE_HANDLE handle); /** * Set the maximum number of times that the * ACE_Select_Reactor_Notify::handle_input() method will iterate and * dispatch the ACE_Event_Handlers that are passed in via the * notify pipe before breaking out of its @c recv loop. By default, * this is set to -1, which means "iterate until the pipe is empty." * Setting this to a value like "1 or 2" will increase "fairness" * (and thus prevent starvation) at the expense of slightly higher * dispatching overhead. */ virtual void max_notify_iterations (int); /** * Get the maximum number of times that the * ACE_Select_Reactor_Notify::handle_input() method will iterate and * dispatch the ACE_Event_Handlers that are passed in via the * notify pipe before breaking out of its recv loop. */ virtual int max_notify_iterations (void); /** * Purge any notifications pending in this reactor for the specified * ACE_Event_Handler object. If @a eh == 0, all notifications for all * handlers are removed (but not any notifications posted just to wake up * the reactor itself). Returns the number of notifications purged. * Returns -1 on error. */ virtual int purge_pending_notifications ( ACE_Event_Handler *sh, ACE_Reactor_Mask mask = ACE_Event_Handler::ALL_EVENTS_MASK); /// Dump the state of an object. virtual void dump () const; /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; protected: /** * Keep a back pointer to the ACE_Select_Reactor. If this value * if NULL then the ACE_Select_Reactor has been initialized with * disable_notify_pipe. */ ACE_Select_Reactor_Impl *select_reactor_; /** * Contains the ACE_HANDLE the ACE_Select_Reactor is listening * on, as well as the ACE_HANDLE that threads wanting the * attention of the ACE_Select_Reactor will write to. */ ACE_Pipe notification_pipe_; /** * Keeps track of the maximum number of times that the * ACE_Select_Reactor_Notify::handle_input() method will iterate and * dispatch the ACE_Event_Handlers that are passed in via the * notify pipe before breaking out of its recv loop. By default, * this is set to -1, which means "iterate until the pipe is empty." */ int max_notify_iterations_; #if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) /** * @brief A user-space queue to store the notifications. * * The notification pipe has OS-specific size restrictions. That * is, no more than a certain number of bytes may be stored in the * pipe without blocking. This limit may be too small for certain * applications. In this case, ACE can be configured to store all * the events in user-space. The pipe is still needed to wake up * the reactor thread, but only one event is sent through the pipe * at a time. */ ACE_Notification_Queue notification_queue_; #endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ }; /** * @class ACE_Select_Reactor_Handler_Repository * * @brief Used to map ACE_HANDLEs onto the appropriate * ACE_Event_Handler *. * * This class is necessary to shield differences between UNIX * and Win32. In UNIX, ACE_HANDLE is an int, whereas in Win32 * it's a void *. This class hides all these details from the * bulk of the ACE_Select_Reactor code. All of these methods * are called with the main token lock held. */ class ACE_Export ACE_Select_Reactor_Handler_Repository { public: friend class ACE_Select_Reactor_Handler_Repository_Iterator; typedef ACE_HANDLE key_type; typedef ACE_Event_Handler * value_type; // = The mapping from to . #ifdef ACE_SELECT_REACTOR_BASE_USES_HASH_MAP /** * The NT version implements this via a hash map * @c ACE_Event_Handler*. Since NT implements @c ACE_HANDLE * as a void * we can't directly index into this array. Therefore, * we must explicitly map @c ACE_HANDLE to @c ACE_Event_Handler. */ typedef ACE_Hash_Map_Manager_Ex, std::equal_to, ACE_Null_Mutex> map_type; typedef map_type::size_type max_handlep1_type; #else /** * The UNIX version implements this via a dynamically allocated * array of @c ACE_Event_Handler* that is indexed directly using * the @c ACE_HANDLE value. */ typedef ACE_Array_Base map_type; typedef ACE_HANDLE max_handlep1_type; #endif /* ACE_SELECT_REACTOR_BASE_USES_HASH_MAP */ typedef map_type::size_type size_type; /// Default "do-nothing" constructor. ACE_Select_Reactor_Handler_Repository (ACE_Select_Reactor_Impl &); /// Initialize a repository of the appropriate @a size. /** * On Unix platforms, the size parameter should be as large as the * maximum number of file descriptors allowed for a given process. * This is necessary since a file descriptor is used to directly * index the array of event handlers maintained by the Reactor's * handler repository. Direct indexing is used for efficiency * reasons. */ int open (size_type size); /// Close down the repository. int close (void); // = Search structure operations. /** * Return the @c ACE_Event_Handler* associated with @c ACE_HANDLE. */ ACE_Event_Handler * find (ACE_HANDLE handle); /// Bind the ACE_Event_Handler * to the ACE_HANDLE with the /// appropriate ACE_Reactor_Mask settings. int bind (ACE_HANDLE, ACE_Event_Handler *, ACE_Reactor_Mask); /// Remove the binding of ACE_HANDLE in accordance with the @a mask. int unbind (ACE_HANDLE, ACE_Reactor_Mask mask); /// Remove all the tuples. int unbind_all (void); // = Sanity checking. // Check the @a handle to make sure it's a valid @c ACE_HANDLE that // is within the range of legal handles (i.e., >= 0 && < max_size_). bool invalid_handle (ACE_HANDLE handle); // Check the @a handle to make sure it's a valid @c ACE_HANDLE that // within the range of currently registered handles (i.e., >= 0 && < // @c max_handlep1_). bool handle_in_range (ACE_HANDLE handle); // = Accessors. /// Returns the current table size. size_type size () const; /// Maximum ACE_HANDLE value, plus 1. max_handlep1_type max_handlep1 () const; /// Dump the state of an object. void dump () const; /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; private: /// Remove the binding of @a handle corresponding to position @a pos /// in accordance with the @a mask. int unbind (ACE_HANDLE handle, map_type::iterator pos, ACE_Reactor_Mask mask); /** * @return @c iterator corresponding @c ACE_Event_Handler* * associated with @c ACE_HANDLE. */ map_type::iterator find_eh (ACE_HANDLE handle); private: /// Reference to our @c Select_Reactor. ACE_Select_Reactor_Impl &select_reactor_; #ifndef ACE_SELECT_REACTOR_BASE_USES_HASH_MAP /// The highest currently active handle, plus 1 (ranges between 0 and /// @c max_size_. max_handlep1_type max_handlep1_; #endif /* !ACE_SELECT_REACTOR_BASE_USES_HASH_MAP */ /// Underlying table of event handlers. map_type event_handlers_; }; /** * @class ACE_Select_Reactor_Handler_Repository_Iterator * * @brief Iterate through the ACE_Select_Reactor_Handler_Repository. */ class ACE_Export ACE_Select_Reactor_Handler_Repository_Iterator { public: typedef ACE_Select_Reactor_Handler_Repository::map_type::const_iterator const_base_iterator; explicit ACE_Select_Reactor_Handler_Repository_Iterator ( ACE_Select_Reactor_Handler_Repository const * s); // = Iteration methods. /// Pass back the @a next_item that hasn't been seen in the Set. /// Returns @c false when all items have been seen, else @c true. bool next (ACE_Event_Handler* & next_item); /// Returns @c true when all items have been seen, else @c false. bool done () const; /// Move forward by one element in the set. Returns @c false when /// all the items in the set have been seen, else @c true. bool advance (void); /// Dump the state of an object. void dump () const; /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; private: /// Reference to the Handler_Repository we are iterating over. ACE_Select_Reactor_Handler_Repository const * const rep_; /// Pointer to the current iteration level. const_base_iterator current_; }; /** * @class ACE_Select_Reactor_Impl * * @brief This class simply defines how Select_Reactor's basic interface * functions should look like and provides a common base class for * @c Select_Reactor using various locking mechanism. */ class ACE_Export ACE_Select_Reactor_Impl : public ACE_Reactor_Impl { public: enum { /// Default size of the Select_Reactor's handle table. DEFAULT_SIZE = ACE_DEFAULT_SELECT_REACTOR_SIZE }; /// Constructor. ACE_Select_Reactor_Impl (bool mask_signals = true); friend class ACE_Select_Reactor_Notify; friend class ACE_Select_Reactor_Handler_Repository; /** * Purge any notifications pending in this reactor for the specified * ACE_Event_Handler object. Returns the number of notifications * purged. Returns -1 on error. */ virtual int purge_pending_notifications (ACE_Event_Handler * = 0, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); /// Does the reactor allow the application to resume the handle on /// its own ie. can it pass on the control of handle resumption to /// the application. The select reactor has no handlers that can be /// resumed by the application. So return 0; virtual int resumable_handler (void); protected: /// Allow manipulation of the mask and mask. virtual int bit_ops (ACE_HANDLE handle, ACE_Reactor_Mask mask, ACE_Select_Reactor_Handle_Set &handle_set, int ops); /// Enqueue ourselves into the list of waiting threads at the /// appropriate point specified by . virtual void renew (void) = 0; /// Check to see if the Event_Handler associated with @a handle is /// suspended. Returns 0 if not, 1 if so. virtual int is_suspended_i (ACE_HANDLE handle) = 0; /// When register/unregister occur, then we need to re-eval our /// wait/suspend/dispatch set. virtual void clear_dispatch_mask (ACE_HANDLE handle, ACE_Reactor_Mask mask); /// Table that maps to 's. ACE_Select_Reactor_Handler_Repository handler_rep_; /// Tracks handles that are ready for dispatch from . ACE_Select_Reactor_Handle_Set wait_set_; /// Tracks handles that are currently suspended. ACE_Select_Reactor_Handle_Set suspend_set_; /// Track HANDLES we are interested in for various events that must /// be dispatched *without* going through is interrupted via . bool restart_; /** * Position that the main ACE_Select_Reactor thread is requeued in * the list of waiters during a callback. If this value == * -1 we are requeued at the end of the list. Else if it's 0 then * we are requeued at the front of the list. Else if it's > 1 then * that indicates the number of waiters to skip over. */ int requeue_position_; /// The original thread that created this Select_Reactor. ACE_thread_t owner_; /** * True if state has changed during dispatching of * ACE_Event_Handlers, else false. This is used to determine * whether we need to make another trip through the * 's loop. */ bool state_changed_; /** * If false then the Reactor will not mask the signals during the event * dispatching. This is useful for applications that do not * register any signal handlers and want to reduce the overhead * introduce by the kernel level locks required to change the mask. */ bool mask_signals_; /// Controls/access whether the notify handler should renew the /// Select_Reactor's token or not. bool supress_notify_renew (void); void supress_notify_renew (bool sr); private: /// Determine whether we should renew Select_Reactor's token after handling /// the notification message. bool supress_renew_; ACE_Select_Reactor_Impl (const ACE_Select_Reactor_Impl &) = delete; ACE_Select_Reactor_Impl &operator = (const ACE_Select_Reactor_Impl &) = delete; }; ACE_END_VERSIONED_NAMESPACE_DECL #if defined (__ACE_INLINE__) #include "ace/Select_Reactor_Base.inl" #endif /* __ACE_INLINE__ */ #include /**/ "ace/post.h" #endif /* ACE_SELECT_REACTOR_BASE_H */