Flow 1.0.2
Flow project: Full implementation reference.
|
A user-set collection of sockets and desired conditions on those sockets (such as: "socket has data to read"), with the ability to wait for those conditions to become true and signal the user when so. More...
#include <event_set.hpp>
Classes | |
class | Socket_as_any_equals |
Equality predicate class used in storing various sockets of types wrapped as boost::any s in the Sockets type. More... | |
class | Socket_as_any_hash |
Hasher class used in storing various sockets of types wrapped as boost::any s in the Sockets type. More... | |
Public Types | |
enum class | State { S_INACTIVE , S_WAITING , S_CLOSED } |
A state of an Event_set. More... | |
enum class | Event_type { S_PEER_SOCKET_READABLE , S_PEER_SOCKET_WRITABLE , S_SERVER_SOCKET_ACCEPTABLE } |
Type of event or condition of interest supported by class Event_set. More... | |
using | Sockets = util::Linked_hash_set< boost::any, Socket_as_any_hash, Socket_as_any_equals > |
A set of sockets of one type, used to communicate sets of desired and resulting events in various Event_set APIs. More... | |
using | Event_handler = Function< void(bool)> |
The type for custom handler passed to async_wait(), which is executed when one or more active events detected, or interrupted as if by signal. More... | |
Public Types inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Event_set > > | |
using | Ptr = boost::shared_ptr< Event_set > |
Short-hand for ref-counted pointer to mutable values of type Target_type::element_type (a-la T* ). More... | |
using | Const_ptr = Const_target_ptr |
Short-hand for ref-counted pointer to immutable values of type Target_type::element_type (a-la T const * ). More... | |
Public Member Functions | |
~Event_set () | |
Boring destructor. Note that deletion is to be handled exclusively via shared_ptr , never explicitly. More... | |
State | state () const |
Current State of the Event_set. More... | |
Node * | node () const |
Node that produced this Event_set. More... | |
void | close (Error_code *err_code=0) |
Clears all stored resources (any desired events, result events, and any handler saved by async_wait()) and moves state to State::S_CLOSED. More... | |
template<typename Socket > | |
bool | add_wanted_socket (typename Socket::Ptr sock, Event_type ev_type, Error_code *err_code=0) |
Adds the given socket to the set of sockets we want to know are "ready" by the definition of the given event type. More... | |
template<typename Socket > | |
bool | remove_wanted_socket (typename Socket::Ptr sock, Event_type ev_type, Error_code *err_code=0) |
Opposite of add_wanted_socket(). More... | |
bool | swap_wanted_sockets (Sockets *target_set, Event_type ev_type, Error_code *err_code) |
Efficiently exchanges the current set of sockets we want to know are "ready" by the definiton of the given event type. More... | |
bool | clear_wanted_sockets (Event_type ev_type, Error_code *err_code=0) |
Identical to swap_wanted_sockets(&sockets, ev_type, err_code) , where originally sockets is empty and is afterwards cleared; but more efficient. More... | |
bool | events_wanted (Error_code *err_code=0) const |
Returns true if and only if at least one wanted event for at least one socket is registered (via add_wanted_socket(), swap_wanted_sockets(), etc.). More... | |
bool | poll (Error_code *err_code=0) |
Checks for all previously described events that currently hold, saves them for retrieval via emit_result_sockets(), etc., and returns. More... | |
bool | sync_wait (Error_code *err_code=0) |
Blocks indefinitely until one or more of the previously described events hold – or the wait is interrupted; saves them for retrieval via emit_result_sockets(), etc. More... | |
template<typename Rep , typename Period > | |
bool | sync_wait (const boost::chrono::duration< Rep, Period > &max_wait, Error_code *err_code=0) |
Same as the other sync_wait() but will stop waiting if the timeout given as argument expires. More... | |
bool | async_wait (const Event_handler &on_event, Error_code *err_code=0) |
Moves object to State::S_WAITING state, saves the given handler to be executed later (in a different, unspecified thread), when one or more of the previously described events hold; and immediately returns. More... | |
bool | async_wait_finish (Error_code *err_code=0) |
Moves object from State::S_WAITING to State::S_INACTIVE, and forgets any handler saved by async_wait(), or does nothing if state is already INACTIVE. More... | |
bool | events_detected (Error_code *err_code=0) const |
Returns true if and only if the last wait, if any, detected at least one event. More... | |
bool | emit_result_sockets (Sockets *target_set, Event_type ev_type, Error_code *err_code=0) |
Gets the sockets that satisfy the condition of the given Event_type detected during the last wait. More... | |
bool | clear_result_sockets (Event_type ev_type, Error_code *err_code=0) |
Identical to emit_result_sockets(&sockets, ev_type, err_code) , where originally sockets is empty and is afterwards cleared; but more efficient. More... | |
bool | clear (Error_code *err_code=0) |
Forgets all sockets stored in this object in any fashion. More... | |
Public Member Functions inherited from flow::log::Log_context | |
Log_context (Logger *logger=0) | |
Constructs Log_context by storing the given pointer to a Logger and a null Component. More... | |
template<typename Component_payload > | |
Log_context (Logger *logger, Component_payload component_payload) | |
Constructs Log_context by storing the given pointer to a Logger and a new Component storing the specified generically typed payload (an enum value). More... | |
Log_context (const Log_context &src) | |
Copy constructor that stores equal Logger* and Component values as the source. More... | |
Log_context (Log_context &&src) | |
Move constructor that makes this equal to src , while the latter becomes as-if default-constructed. More... | |
Log_context & | operator= (const Log_context &src) |
Assignment operator that behaves similarly to the copy constructor. More... | |
Log_context & | operator= (Log_context &&src) |
Move assignment operator that behaves similarly to the move constructor. More... | |
void | swap (Log_context &other) |
Swaps Logger pointers and Component objects held by *this and other . More... | |
Logger * | get_logger () const |
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect. More... | |
const Component & | get_log_component () const |
Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect. More... | |
Private Types | |
using | Mutex = util::Mutex_recursive |
Short-hand for reentrant mutex type. More... | |
using | Lock_guard = util::Lock_guard< Mutex > |
Short-hand for RAII lock guard of Mutex. Use instead of boost::lock_guard for release() at least. More... | |
using | Ev_type_to_socks_map = util::Linked_hash_map< Event_type, Sockets > |
Short-hand for type storing a set of socket sets – one per possible Event_type enum value. More... | |
Private Member Functions | |
Event_set (log::Logger *logger_ptr) | |
Constructs object; initializes all values to well-defined but possibly meaningless values (0, empty, etc.). More... | |
bool | ok_to_mod_socket_set (Error_code *err_code) const |
Helper that ensures the state of *this is such that one may modify the m_can and m_want socket sets. More... | |
bool | sync_wait_impl (const Fine_duration &max_wait, Error_code *err_code) |
Same as the public sync_wait(max_wait) but uses a Fine_clock -based Fine_duration non-template type for implementation convenience and to avoid code bloat in specifying timeout. More... | |
Static Private Member Functions | |
static Ev_type_to_socks_map | empty_ev_type_to_socks_map () |
Creates a maximally empty Ev_type_to_socks_map: it will have all possible Event_type as keys but only empty Sockets sets as values. More... | |
static void | clear_ev_type_to_socks_map (Ev_type_to_socks_map *ev_type_to_socks_map) |
Helper that clears each Sockets set inside an Ev_type_to_socks_map. More... | |
static bool | ev_type_to_socks_map_entry_is_empty (const Ev_type_to_socks_map::Value &ev_type_and_socks) |
Functional helper that checks whether a given pair in an Ev_type_to_socks_map contains an empty set of Sockets or not. More... | |
static std::string | ev_type_to_socks_map_sizes_to_str (const Ev_type_to_socks_map &ev_type_to_socks_map) |
Helper that returns a loggable string summarizing the sizes of the socket sets, by type, stored in an Ev_type_to_socks_map. More... | |
static std::string | sock_as_any_to_str (const boost::any &sock_as_any) |
Helper that returns a loggable string representing the socket stored in the given boost::any that stores a value allowed by the members of Event_type enum . More... | |
Private Attributes | |
State | m_state |
See state(). Should be set before user gets access to *this . Must not be modified by non-W threads after that. More... | |
Node * | m_node |
See node(). Should be set before user gets access to *this . Must not be modified by non-W threads after that. More... | |
Ev_type_to_socks_map | m_want |
The sockets, categorized by Event_type of interest, to check for "ready" status (as defined in the doc header for each Event_type), in the next wait (State::S_WAITING state). More... | |
Ev_type_to_socks_map | m_can |
The sockets, categorized by Event_type of interest, that were found to be "ready" (as defined in the doc header for each Event_type), during the last wait (State::S_WAITING state). More... | |
Event_handler | m_on_event |
During State::S_WAITING, stores the handler (a void function with 1 bool argument) that will be called once one or more events are found to hold. More... | |
bool | m_baseline_check_pending |
While in State::S_WAITING, if this is true , an exhaustive check of all desired events is yet to be performed (in thread W); if false , it has alredy been performed (in thread W), and only "delta" checks need to be checked from now on during this wait. More... | |
Mutex | m_mutex |
Mutex protecting ALL data in this object. More... | |
Static Private Attributes | |
static const boost::unordered_map< Event_type, Function< bool(const Node *, const boost::any &)> > | S_EV_TYPE_TO_IS_ACTIVE_NODE_MTD |
Mapping from each possible Event_type to the Node method that determines whether the condition defined by that Event_type is currently true for the socket wrapped in the boost::any argument passed to the method. More... | |
Friends | |
class | Node |
See rationale for friend ing Node in class Event_set documentation header. More... | |
Related Functions | |
(Note that these are not member functions.) | |
std::ostream & | operator<< (std::ostream &os, Event_set::State state) |
Prints string representation of given Event_set state to given standard ostream and returns the latter. More... | |
std::ostream & | operator<< (std::ostream &os, Event_set::Event_type ev_type) |
Prints string representation of given event type to given standard ostream and returns the latter. More... | |
Additional Inherited Members | |
Static Public Member Functions inherited from flow::util::Shared_ptr_alias_holder< boost::shared_ptr< Event_set > > | |
static Ptr | ptr_cast (const From_ptr &ptr_to_cast) |
Provides syntactic-sugary way to perform a static_pointer_cast<> from a compatible smart pointer type From_ptr , typically From_ptr::element_type being in the same class hierarchy as Target_ptr::element_type . More... | |
static Const_ptr | const_ptr_cast (const From_ptr &ptr_to_cast) |
Identical to ptr_cast() but adds const -ness (immutability) to the pointed-to type. More... | |
static Ptr | dynamic_ptr_cast (const From_ptr &ptr_to_cast) |
Equivalent to ptr_cast() but a dynamic_pointer_cast instead of static. More... | |
static Const_ptr | dynamic_const_ptr_cast (const From_ptr &ptr_to_cast) |
Identical to const_ptr_cast() but a dynamic_pointer_cast instead of static. More... | |
A user-set collection of sockets and desired conditions on those sockets (such as: "socket has data to read"), with the ability to wait for those conditions to become true and signal the user when so.
net_flow
; this is found in asio::Node doc header. This should help hugely in choosing the right type of operating mode in the context of a non-trivial application, possibly featuring other types of I/O in addition to the Flow protocol. This fulfills the same role as BSD sockets' select()
(and its more powerful non-portable equivalents like epoll, kqueue, etc.). In addition to the feature set provided by functions such as select()
, Event_set provides a way to work together with the OS's built-in select()
equivalent; that is to say it provides a way to add Flow-protocol sockets into an event loop written in terms of select()
or spritiually similar facilities (epoll, kqueue, etc.).
The simplest way to use Event_set is to not use it directly at all. Instead, use the blocking methods such as Peer_socket::sync_receive(), Peer_socket::sync_send(), Node::sync_connect(), and Server_socket::sync_accept(). Such methods will internally construct an Event_set with the target socket and perform work (namely some Event_set::sync_wait() calls) on it, hidden from the caller. This mode of operation is analogous to BSD sockets' blocking functions (e.g., recv()
in blocking mode – POSIX O_NONBLOCK
bit set / WinSock FIONBIO
mode is enabled).
This is often insufficient, as in event loops of any complexity. The next simplest way to use Event_set is to use a synchronous wait. To do so, construct an Event_set, add the desired (socket, desired event on that socket) pairs to it (see the swap_wanted_sockets(), add_wanted_socket(), remove_wanted_socket() methods), then perform sync_wait() (with an optional timeout). Once that method returns (which happens once either 1 or more events are active, there is a timeout, or wait is interrupted via Node::interrupt_all_waits()), examine which events (if any) were found to be active, then perform the appropriate operation (e.g., serv->accept()
if Acceptable, sock->send()
if Writable) on each active socket/event pair. This mode of operation is analogous to FD_SET(); select(); FD_ISSET()
or epoll_ctl(); epoll_wait()
. The key feature is that the sync_wait() (like select()
or epoll_wait()
) call blocks the calling thread until there are events or a timeout or a global interrupt (the latter similar to POSIX EINTR
caused by a signal). Additionally, the Event_set::poll() method is analogous to a select()
call with a 0 timeout.
The above is sufficient when writing an event loop that works only with Flow-protocol sockets. However, many practical applications will use an event loop that works with Flow-protocol sockets and other resources (e.g., TCP sockets, pipes) simultaneously. Then what?
We now discuss Event_set::async_wait(). The basic deficiency of sync_wait() is simply that it will only wake up if there's a Flow-protocol event and knows nothing about anything else. Similarly, your select()
-or-equivalent-of-choice will know nothing of Flow-protocol events, since it can only work with standard file descriptors (or whatever), not Flow sockets. For this case Event_set provides asynchronous waiting. As before, you'll construct an Event_set and add some desired sockets/events. Then, call async_wait(F)
, where F()
is a function. async_wait() will IMMEDIATELY return. However, another, unspecified, thread will wait for the desired condition(s) to become true. Once that occurs, that unspecified thread will call F()
. F()
can do whatever you want (but see restrictions documented on async_wait()); however in the use case described in this paragraph it will probably want to do something that will wake up the select()
(or epoll_wait()
, or ...) of your main event loop. For example, you can set up a Unix domain socket or pipe and add it into your select()
(or equivalent's) event set; and then have F()
write 1 byte to it. Once this occurs, that select()
(etc.) will wake up; you can call async_wait_finish()
and then check the active Flow-protocol events using the same techniques as shown in the preceding paragraph, after having called sync_wait().
The following illustrates the preceding paragraph. In this example, we are interested in a single TCP socket from which to read; and a single Flow socket from which to read. This can be extended to more native and Flow socket types, more sockets, and more sophisticated native mechanisms than select()
; but basically this is it. (However, in case of select()
and its peculiar FD_SET()
semantics, please note that this examples combines sel_read_set
to handle both the special local "linking" socket comm_sock
and the TCP-readable socket tcp_sock
. If you want to check for another type of event than being "readable" – e.g., "writable" – then with select()
you'd need to make a separate event set, perhaps named sel_write_set
, and it would not be handling comm_sock
, in whose case we only care about readability. Note also that the example event loop iteration shown below models situation where tcp_sock
and flow_sock
happen to both become readable just about at the same time, causing select()
to return with 2 sockets in readable state simultaneously for illustration purposes. Realistically probably one would become readable; then in another loop iteration the other would... but this would be annoyingly lengthy to show; and though this is less probable, it's still possible.
The above are informal suggestions for use. Here is the more formal description of operation of an Event_set. Event_set is a simple state machine with three states: INACTIVE, WAITING, CLOSED. After construction (which is done by Node in a factory fashion), Event_set is in INACTIVE state. CLOSED means the Event_set has been Event_set::close()d, or the originating Node has been destroyed. It is not possible to perform any operations on a CLOSED Event_set, nor is it possible to exit the CLOSED state. A CLOSED Event_set stores no resources and will be deleted via shared_ptr<>
mechanics once all user references to it are gone.
The rest of the time, Event_set switches back and forth between INACTIVE and WAITING. In INACTIVE, you may set and examine the desired sockets/events. The following are supported (see also Event_set::Event_type enum
values)
sock->receive()
with unlimited target buffer space would return either a non-zero number of bytes or indicate an error. (Therefore "not Readable" means it would return 0 but no error.)sock->send()
. Note, however, that typically this is more likely to be immediately true on a given socket; if there's space in the Send buffer for a certain small amount of data, then the socket owning it is Writable; whereas data have to actually have arrived from the other side for it to be Readable. Nevertheless, if network conditions are such that the Send buffer cannot be purged via sending its contents to the other side, then eventually it won't be Writable either (so don't count on writability without checking).serv->accept()
would return either a non-null Server_socket::Ptr or indicate an error. (Therefore "not Acceptable" means it would return null but no error.)The desired events can be specified with swap_wanted_sockets(), add_wanted_socket(), and remove_wanted_socket(). Note that all of these methods are efficient (no copying of socket sets involved). Also note that all the socket objects passed to an Event_set must come from the same Node as that Event_set; else behavior is undefined.
Also in INACTIVE, you may examine the results of the last wait, if any. Do this using emit_result_sockets(), etc. Note that these methods are also efficient (no copying) and can only be used once for each wait (all subsequent uses yield empty socket sets).
In WAITING state, a wait for the specified events has started. async_wait(), sync_wait(), and poll() change state from INACTIVE to WAITING. In WAITING state, all of the above methods return errors. The following pieces of code change state back to INACTIVE: async_wait_finish(), sync_wait() (once an event is true, or timeout), poll() (immediately), and an unspecified non-user thread if async_wait() was used, and an event has been asynchronously detected.
In particular, if Event_set e
is used by 1 thread, and that thread performs only sync_wait()s for waiting, user code will never be able to observe the WAITING state, as sync_wait() will go INACTIVE->WAITING->INACTIVE internally.
They are entirely independent. In particular, you may put the same socket+event combo into 2 different Event_set objects and wait on both Event_sets simultaneously. If that socket/event holds for both Event_set objects at the same time, both will be signalled. I informally recommend against using this. For example, if the event is "sock is
Readable," and you will receive()
as a result, which of the two receive()
calls gets what data? However there may be a reasonable use case for the Acceptable event.
Any POSIX blocking function, once it has started waiting, will exit with errno == EINTR
if a signal is delivered. (Sometimes this is just annoying, but sometimes it's useful: if SIGTERM handler sets some global terminate flag, then the signal delivery will immediately break out of the blocking call, so the flag can be immediately checked by the main code (and then the program can cleanly exit, for example).) Event_set::sync_wait() and Event_set::async_wait() support similar functionality. Call Node::interrupt_all_waits() to interrupt any Event_set object(s) within that Node currently in WAITING state. They enter INACTIVE state, and it is indicated to the user of each sync_wait() or async_wait() that the reason for the wait's finish was an interruption (see those functions for details on how this is communicated). Conceptually this is similar to POSIX blocking select()
or blocking recv()
returning -1/EINTR
.
To actually cause signals to trigger Node::interrupt_all_waits() (as occurs by default, conceptually, in POSIX programs w/r/t EINTR
), the user has two basic options. They can either register signal handlers that'll explicitly invoke that method; or they can let Node do so automatically for SIGINT and SIGTERM. This is controlled by the Node option Node_options::m_st_capture_interrupt_signals_internally.
Same as for Peer_socket. (Briefly: all operations safe for simultaneous execution on separate or the same object.) An informal recommendation, however, is to only use a given Event_set in one thread. Otherwise things will get confusing, quickly, with no practical benefit of which I, at least, am aware.
The crux of the implementation is in async_wait(), as all other wait types are built on it. Therefore there is a giant comment inside that method that is required reading for understanding this class's innards (which, IMO, are some of the trickiest logic in all of the library).
As with Peer_socket and Server_socket, much of the implementation (as opposed to interface) of Event_set functionality resides in class Node. In particular anything to do with thread W is in Node. The actual code is in event_set.cpp, but since the logic involves Node state, and Event_set is subservient to the Node, in terms of objects it makes more sense to keep it in class Node. However, when no Node state is involved, Event_set logic is actually typically coded in Event_set methods, to a greater extent than in Peer_socket or Server_socket, which are mere data stores in comparison.
Definition at line 247 of file event_set.hpp.
|
private |
Short-hand for type storing a set of socket sets – one per possible Event_type enum
value.
In practice, the key set for a value of this type is all Event_type members; use empty_ev_type_to_socks_map() to create a maximally empty such structure.
Definition at line 798 of file event_set.hpp.
using flow::net_flow::Event_set::Event_handler = Function<void (bool)> |
The type for custom handler passed to async_wait(), which is executed when one or more active events detected, or interrupted as if by signal.
Definition at line 386 of file event_set.hpp.
|
private |
Short-hand for RAII lock guard of Mutex. Use instead of boost::lock_guard
for release()
at least.
Definition at line 791 of file event_set.hpp.
|
private |
Short-hand for reentrant mutex type.
We explicitly rely on reentrant behavior, so this isn't "just in case." (One shouldn't use reentrant mutexes "just in case"; it should be entirely conscious and on-purpose; one should use non-reentrant mutexes, all else being equal.)
Definition at line 788 of file event_set.hpp.
using flow::net_flow::Event_set::Sockets = util::Linked_hash_set<boost::any, Socket_as_any_hash, Socket_as_any_equals> |
A set of sockets of one type, used to communicate sets of desired and resulting events in various Event_set APIs.
As a rule, a given Sockets object will store sockets of one underlying type; meaning the boost::any
s stored inside one such set can ALL be boost::any_cast<>
to the same type. Which type that is is usually determined by the associated Event_type value, typically supplied alongside a Sockets set in another argument. For example, if ev_type == Event_type::S_PEER_SOCKET_READABLE
, then every boost::any
in the set can be decoded as follows: Peer_socket::Ptr sock = any_cast<Peer_socket::Ptr>(sock_as_any)
, where sock_as_any
is an element in a Sockets.
As of this writing, the type is chronologically ordered; meaning sockets will be stored in order from latest to oldest to be inserted into the structure. E.g., emit_result_sockets() will produce a set containing of readable sockets, in reverse chronological order in which they were detected as being readable. This may or may not be useful in debugging.
This type is also used internally extensively.
unordered_set
would also work and take somewhat less memory and computational overhead. It would become unordered, instead of ordered chronologically, but that seems like a price possibly worth paying.Note, also, the to-do in emit_result_sockets() doc header, regarding using variant
instead of any
. Not only would that be faster and arguably safer, being compile-time in nature; but we'd get hashing/equality for free – hence the code would be much pithier (no need for Socket_as_any_hash or Socket_as_any_equals).
Definition at line 372 of file event_set.hpp.
|
strong |
Type of event or condition of interest supported by class Event_set.
When specifying interest in some socket reaching a certain condition, or when requesting the results of that interest, the user essentially specifies a pair of data: an enumeration value of this type and a socket of a certain type (that type is specified in the very name of the Event_type). For example, I may be interested in Event_type::S_PEER_SOCKET_READABLE becoming true for Peer_socket::Ptr sock
. The precise meaning is documented for each enumeration value.
You will note a few different structures, such as Event_set::m_want and Event_set::m_can, are keyed by this type. Doing it that way, instead of simply having a simpler Event_set::m_want-like structure (etc.) exist 3x, has its plusses and minuses. Historically, this was actually implemented that other way first, but I wanted to play with boost::any
to see if it makes the code more elegant. It has certainly resulted in significantly fewer methods and less code; and in code that is more generic (and, in principle, extensible if we somehow come up with another event type of interest); and less bug-prone. The code is also arguably more opaque and harder to grok right off the bat, as it's more abstract. Finally, from the user's point of view, it is slightly harder to use in that when emitting results of an Event_set::[a]sync_wait()
, one must any_cast<>
to the proper socket type – easy but requires a small learning curve. I'll say overall it is better this way than the other way.
In terms of extending this enum
, which seems unlikely, the following would be involved. Add a value for the enum
; then add clauses for it in Socket_as_any_hash::operator(), Socket_as_any_equals::operator(), Event_set::sock_as_any_to_str(). Extend the structures in Event_set::empty_ev_type_to_socks_map() and S_EV_TYPE_TO_IS_ACTIVE_NODE_MTD. The latter will need a new method written in Node that checks for whether the condition of this type currently holds for the given socket – whose type, by the way, you will need to decide and document in the doc header for the new enum
value. Finally, you'll need to find all situations throughout the code where the condition may change from not holding to holding and possibly save it into Node::m_sock_events when detected (for example, see when m_sock_events[S_PEER_SOCKET_READABLE]
is insert()
ed into).
Enumerator | |
---|---|
S_PEER_SOCKET_READABLE | Event type specifying the condition of interest wherein a target In other words, specifies the condition where a Peer_socket is Readable. In Event_set::Sockets structures associated with this Event_set::Event_type, |
S_PEER_SOCKET_WRITABLE | Event type specifying the condition of interest wherein a target In other words, specifies the condition where a Peer_socket is Writable. In Event_set::Sockets structures associated with this Event_set::Event_type, |
S_SERVER_SOCKET_ACCEPTABLE | Event type specifying the condition of interest wherein a target In other words, specifies the condition where a Server_socket is Acceptable. In Event_set::Sockets structures associated with this Event_set::Event_type, |
Definition at line 306 of file event_set.hpp.
|
strong |
A state of an Event_set.
Enumerator | |
---|---|
S_INACTIVE | Default state; valid Event_set that is not currently waiting on events. All user operations are valid in this state. |
S_WAITING | Waiting state: valid Event_set that is currently waiting on previously described events. In this state only async_wait_finish() may be called without resulting in an error. |
S_CLOSED | Node has disowned the Peer_socket; all further operations will result in error. |
Definition at line 259 of file event_set.hpp.
flow::net_flow::Event_set::~Event_set | ( | ) |
Boring destructor. Note that deletion is to be handled exclusively via shared_ptr
, never explicitly.
Definition at line 54 of file event_set.cpp.
References FLOW_LOG_TRACE.
|
explicitprivate |
Constructs object; initializes all values to well-defined but possibly meaningless values (0, empty, etc.).
logger_ptr | The Logger implementation to use subsequently. |
Definition at line 42 of file event_set.cpp.
References FLOW_LOG_TRACE.
Referenced by flow::net_flow::Node::event_set_create().
bool flow::net_flow::Event_set::add_wanted_socket | ( | typename Socket::Ptr | sock, |
Event_type | ev_type, | ||
Error_code * | err_code = 0 |
||
) |
Adds the given socket to the set of sockets we want to know are "ready" by the definition of the given event type.
See individual Event_type enumeration members' doc comments for exact definition of readiness for each Event_type. For example, Event_type::S_PEER_SOCKET_READABLE means we want to know when sock->receive()
would yield either some data or an error, but not no data and no error.
Socket | type to which ev_type applies. E.g., Peer_socket for PEER_SOCKET_READABLE. |
sock | Socket to add. Must be from the same Node as the one originating this Event_set. |
ev_type | The condition we are interested in sock reaching. |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_ALREADY_EXISTS, error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
true
if and only if no error occurred (*err_code
is success). Definition at line 1015 of file event_set.hpp.
References FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_mutex, m_want, ok_to_mod_socket_set(), and flow::net_flow::error::S_EVENT_SET_EVENT_ALREADY_EXISTS.
bool flow::net_flow::Event_set::async_wait | ( | const Event_handler & | on_event, |
Error_code * | err_code = 0 |
||
) |
Moves object to State::S_WAITING state, saves the given handler to be executed later (in a different, unspecified thread), when one or more of the previously described events hold; and immediately returns.
State will go back to State::S_INACTIVE when the handler fires; or when async_wait_finish() is called by the user (whichever happens first). State may also change to State::S_CLOSED if this->close()
is called, or the Node is destroyed. The saved handler will be forgotten at that time. Once INACTIVE is entered, emit_result_sockets(), etc., are to be used to access the detected events. on_event() must take one bool argument. If this argument is false
, use emit_result_sockets(), etc., to access the detected events. If this argument is true
, then Node::interrupt_all_waits() was invoked and has interrupted this wait (conceptually similar to EINTR
in POSIX). In the latter case, do no use emit_result_sockets(), etc., as no events are active due to the interruption.
In a non-error invocation, state() will be INACTIVE before the call and WAITING after it. In an error invocation, state() will not change, and the method will return immediately. Additionally, on_event() will NEVER be called, if another thread calls this->close()
before async_wait_finish() is called, and before the Node is destroyed. So don't do that.
Restrictions on what on_event()
is allowed to do: It is allowed to do anything except make any net_flow
call related to the net_flow::Node originating the current Event_set; doing so results in undefined behavior. Informally, it also must not block; spending significant time in on_event()
will disrupt the functionality of the Node. Even more informally, the goal of on_event()
should be to quickly signal the user's thread(s) that the events hold (using the technique of the user's choice) and then return – beyond that, the handling of the ready events should be in the user's thread(s).
Tip: Call async_wait_finish() before checking the saved results, using emit_result_sockets(). Doing so BEFORE any events are detected will finish this asynchronous wait. Doing so AFTER any events are detected will be a harmless NOOP.
Tip: Use lambdas (or bind()
) to make async_wait() asynchronously call any arbitrary function or method with any arbitrary arguments – NOT just a free void
function with 1 argument. Outside the scope of discussion here, but if this doesn't ring a bell, please look into lambdas (bind()
as a backup).
Rationale for no timeout argument: Since the caller of async_wait() retains flow control without blocking, the user code can enforce its own timeout logic, if necessary, and simply call async_wait_finish() when desired. In fact that is just what sync_wait() (with timeout argument) does internally.
on_event | The function to call as soon as as one or more events previously described hold, AND this->state() is still State::S_WAITING. (Also see above tip.) on_event(bool was_interrupted) will be called. |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_DOUBLE_WAIT_OR_POLL, error::Code::S_EVENT_SET_CLOSED. |
true
if and only if no error occurred (*err_code
is success). Definition at line 72 of file event_set.cpp.
References async_wait(), ev_type_to_socks_map_entry_is_empty(), flow::net_flow::Node::event_set_async_wait(), FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, m_mutex, m_node, m_state, m_want, S_CLOSED, flow::net_flow::error::S_EVENT_SET_CLOSED, flow::net_flow::error::S_EVENT_SET_DOUBLE_WAIT_OR_POLL, flow::net_flow::error::S_EVENT_SET_NO_EVENTS, S_INACTIVE, and S_WAITING.
Referenced by async_wait(), and sync_wait_impl().
bool flow::net_flow::Event_set::async_wait_finish | ( | Error_code * | err_code = 0 | ) |
Moves object from State::S_WAITING to State::S_INACTIVE, and forgets any handler saved by async_wait(), or does nothing if state is already INACTIVE.
Use this to cut short an asynchronous wait started by async_wait(). After return, emit_result_sockets(), etc., can be used to check the active events (if any) detected during the last wait.
In a non-error invocation, state() will be State::S_INACTIVE or State::S_WAITING before the call and State::S_INACTIVE after it. In an error invocation, state() will not change.
You might call async_wait_finish() while another thread is executing a timeout-less sync_wait() (which is also invoked by blocking methods like Peer_socket::sync_receive()). However that will cause that sync_wait() to NEVER return. So don't do that.
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED. |
true
if and only if no error occurred (*err_code
is success). In particular, state() being State::S_INACTIVE when the method starts is not an error. Definition at line 215 of file event_set.cpp.
References async_wait_finish(), FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_mutex, m_on_event, m_state, S_CLOSED, flow::net_flow::error::S_EVENT_SET_CLOSED, S_INACTIVE, and S_WAITING.
Referenced by async_wait_finish(), and sync_wait_impl().
bool flow::net_flow::Event_set::clear | ( | Error_code * | err_code = 0 | ) |
Forgets all sockets stored in this object in any fashion.
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
Definition at line 705 of file event_set.cpp.
References clear(), clear_ev_type_to_socks_map(), ev_type_to_socks_map_sizes_to_str(), FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_can, m_mutex, m_want, and ok_to_mod_socket_set().
Referenced by clear().
|
staticprivate |
Helper that clears each Sockets set inside an Ev_type_to_socks_map.
Thus, it is equivalent to *ev_type_to_socks_map = empty_ev_type_to_socks_map()
, but perhaps faster.
ev_type_to_socks_map | Target map. |
Definition at line 747 of file event_set.cpp.
Referenced by clear(), flow::net_flow::Node::event_set_all_check_delta(), flow::net_flow::Node::event_set_async_wait(), flow::net_flow::Node::event_set_close_worker(), flow::net_flow::Node::interrupt_all_waits_worker(), and poll().
bool flow::net_flow::Event_set::clear_result_sockets | ( | Event_type | ev_type, |
Error_code * | err_code = 0 |
||
) |
Identical to emit_result_sockets(&sockets, ev_type, err_code)
, where originally sockets
is empty and is afterwards cleared; but more efficient.
ev_type | See emit_result_sockets(). |
err_code | Same. |
Definition at line 649 of file event_set.cpp.
References flow::util::Linked_hash_set< Key, Hash, Pred >::clear(), clear_result_sockets(), FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_can, m_mutex, ok_to_mod_socket_set(), and flow::util::Linked_hash_set< Key, Hash, Pred >::size().
Referenced by clear_result_sockets().
bool flow::net_flow::Event_set::clear_wanted_sockets | ( | Event_type | ev_type, |
Error_code * | err_code = 0 |
||
) |
Identical to swap_wanted_sockets(&sockets, ev_type, err_code)
, where originally sockets
is empty and is afterwards cleared; but more efficient.
ev_type | See swap_wanted_sockets(). |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
true
if and only if no error occurred (*err_code
is success). Definition at line 527 of file event_set.cpp.
References flow::util::Linked_hash_set< Key, Hash, Pred >::clear(), clear_wanted_sockets(), FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_mutex, m_want, ok_to_mod_socket_set(), and flow::util::Linked_hash_set< Key, Hash, Pred >::size().
Referenced by clear_wanted_sockets().
void flow::net_flow::Event_set::close | ( | Error_code * | err_code = 0 | ) |
Clears all stored resources (any desired events, result events, and any handler saved by async_wait()) and moves state to State::S_CLOSED.
In particular Node will have disowned this object by the time close() returns.
You might call close() while state is State::S_WAITING, but if a timeout-less sync_wait() is executing in another thread, it will NEVER return. Similarly, if state is currently WAITING due to async_wait(), the handler saved by async_wait() will NEVER be called. So don't do that. However, first closing one or more sockets being waited on by those calls and THEN calling this->close()
is perfectly safe, in that sync_wait() will exit, or the handler will be called. (In fact when Node shuts down it does just that.)
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED. |
Definition at line 464 of file event_set.cpp.
References close(), flow::net_flow::Node::event_set_close(), flow::error::exec_void_and_throw_on_error(), FLOW_ERROR_EMIT_ERROR, FLOW_UTIL_WHERE_AM_I_STR, m_mutex, m_node, m_state, S_CLOSED, and flow::net_flow::error::S_EVENT_SET_CLOSED.
Referenced by close().
bool flow::net_flow::Event_set::emit_result_sockets | ( | Sockets * | target_set, |
Event_type | ev_type, | ||
Error_code * | err_code = 0 |
||
) |
Gets the sockets that satisfy the condition of the given Event_type detected during the last wait.
More precisely, moves all sockets satisfying that condition detected during the last wait (if any) into the set provided by the user. Because it is a move (for efficiency among other reasons), the subsequent calls to the same method will yield empty sets (until the next wait operation). Calling before any wait will also yield an empty set.
Note that the accumulated sockets are NOT preserved across waits. That is, if you start a wait, the preceding wait's results are wiped out.
Making the method a one-off that returns nothing after the first invocation (per wait) allows for thread safety without sacrificing efficiency by adding set copy.
First, prepare a (usually empty) target socket set structure. Second, call emit_result_sockets() to transfer the results to it. Third, for each socket of interest, any_cast<>
it from boost::any
to the socket pointer of the appropriate type. (Recall that boost::any
stores an object of any type inside it, so to get access to that you must know to what to cast it; but this is easy, since by specifying ev_type
you are implying a certain socket type.) Example:
target_set | Pointer to set of sockets to which to load the current internal set of result sockets of type ev_type found during the last wait. Any elements here at call time will be removed. |
ev_type | The condition we are interested in which sockets have reached during the last wait. |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
true
if and only if no error occurred (*err_code
is success).boost:any
s each of which stores either a Peer_socket::Ptr
or a Server_socket::Ptr
; Sockets should be changed to store C++17 std::variant
s. Performance, both internally and externally, would improve by using this type-safe compile-time mechanism (which is akin to union
s but much more pleasant to use). At the time this feature was written, Flow was in C++11, so variant
s were not available, and the author wanted to play around with any
s instead of haxoring old-school union
s. variant
is much nicer, however, and the dynamic nature of any
is entirely unnecessary here. Definition at line 613 of file event_set.cpp.
References flow::util::Linked_hash_set< Key, Hash, Pred >::clear(), emit_result_sockets(), FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_can, m_mutex, ok_to_mod_socket_set(), flow::util::Linked_hash_set< Key, Hash, Pred >::size(), and flow::util::Linked_hash_set< Key, Hash, Pred >::swap().
Referenced by emit_result_sockets().
|
staticprivate |
Creates a maximally empty Ev_type_to_socks_map: it will have all possible Event_type as keys but only empty Sockets sets as values.
Definition at line 736 of file event_set.cpp.
References S_PEER_SOCKET_READABLE, S_PEER_SOCKET_WRITABLE, and S_SERVER_SOCKET_ACCEPTABLE.
|
staticprivate |
Functional helper that checks whether a given pair
in an Ev_type_to_socks_map contains an empty set of Sockets or not.
ev_type_and_socks | A value (key and mapped, not just mapped) from an Ev_type_to_socks_map. |
true
if and only if the socket set is empty. Definition at line 756 of file event_set.cpp.
Referenced by async_wait(), flow::net_flow::Node::event_set_all_check_delta(), flow::net_flow::Node::event_set_fire_if_got_events(), events_detected(), events_wanted(), and sync_wait_impl().
|
staticprivate |
Helper that returns a loggable string summarizing the sizes of the socket sets, by type, stored in an Ev_type_to_socks_map.
ev_type_to_socks_map | A valid such map. |
Definition at line 761 of file event_set.cpp.
References flow::util::ostream_op_to_string(), and flow::util::Linked_hash_map< Key, Mapped, Hash, Pred >::size().
Referenced by clear(), flow::net_flow::Node::event_set_all_check_delta(), and events_detected().
bool flow::net_flow::Event_set::events_detected | ( | Error_code * | err_code = 0 | ) | const |
Returns true
if and only if the last wait, if any, detected at least one event.
In other words, returns true
if and only if emit_result_sockets() would currently emit at least one socket, if tried with all possible Event_type.
One can still use emit_result_sockets()
to get the specific events after calling this.
select()
returns 0 or higher; and one uses the check of whether its return value is 0 or non-zero. Non-zero is actually some complex index thing, but often that detail is not necessary (much like emit_result_sockets()
is unnecessary, analogously), as the mere presence or absence of 1+ events is enough information. For example, if only one event for one socket is being waited on, one can check this and confidently perform the appropriate I/O operation for that one socket, if and only if this returns true
– or select()
would return non-zero. Slightly more wastefully, but still not bad at all, is when (say) 2 event types are being waited on, but for only 1 socket. In that case true
return => just perform both I/O operations; one OR both of them should yield something (and the one that doesn't hardly uses any resources). Similarly, even if you're waiting on a few sockets, if it's a limited number (like, say, 2-3), then indiscriminately trying all possible I/O on all 2-3 sockets is only slightly wasteful: and the code is quite a bit shorter than carefully checking emit_result_sockets()
(or doing FD_ISSET()
, etc., in the analogous select()
code). err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_RESULT_CHECK_WHEN_WAITING. |
true
if there are active events; false
if there are no active events (then *err_code
is success) or there was an error (*err_code
is failure; i.e., bool(*err_code) == true
). Definition at line 576 of file event_set.cpp.
References ev_type_to_socks_map_entry_is_empty(), ev_type_to_socks_map_sizes_to_str(), events_detected(), FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_can, m_mutex, m_state, S_CLOSED, flow::net_flow::error::S_EVENT_SET_CLOSED, flow::net_flow::error::S_EVENT_SET_RESULT_CHECK_WHEN_WAITING, S_INACTIVE, and S_WAITING.
Referenced by events_detected().
bool flow::net_flow::Event_set::events_wanted | ( | Error_code * | err_code = 0 | ) | const |
Returns true
if and only if at least one wanted event for at least one socket is registered (via add_wanted_socket(), swap_wanted_sockets(), etc.).
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED. |
true
if there are wanted events; false
if there are no wanted events (then *err_code
is success) or there was an error (*err_code
is failure; i.e., bool(*err_code) == true
). Definition at line 553 of file event_set.cpp.
References ev_type_to_socks_map_entry_is_empty(), events_wanted(), FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, m_mutex, m_state, m_want, S_CLOSED, and flow::net_flow::error::S_EVENT_SET_CLOSED.
Referenced by events_wanted().
Node * flow::net_flow::Event_set::node | ( | ) | const |
|
private |
Helper that ensures the state of *this
is such that one may modify the m_can and m_want socket sets.
Pre-condition: m_mutex is locked.
err_code | If false returned, sets this to the reason why socket sets are not OK to modify. Otherwise sets it to success. Possible errors: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
true
if OK to modify; false
if not OK to modify. Definition at line 675 of file event_set.cpp.
References FLOW_ERROR_EMIT_ERROR, m_state, S_CLOSED, flow::net_flow::error::S_EVENT_SET_CLOSED, flow::net_flow::error::S_EVENT_SET_IMMUTABLE_WHEN_WAITING, S_INACTIVE, and S_WAITING.
Referenced by add_wanted_socket(), clear(), clear_result_sockets(), clear_wanted_sockets(), emit_result_sockets(), remove_wanted_socket(), and swap_wanted_sockets().
bool flow::net_flow::Event_set::poll | ( | Error_code * | err_code = 0 | ) |
Checks for all previously described events that currently hold, saves them for retrieval via emit_result_sockets(), etc., and returns.
This is akin to a non-blocking sync_wait() (which does not exist; poll() does), a/k/a a select()
with a timeout of zero.
In a non-error invocation, state() will be State::S_INACTIVE before and after the call. In an error invocation, state() will not change.
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_DOUBLE_WAIT_OR_POLL. |
true
if and only if no error occurred (*err_code
is success). Definition at line 266 of file event_set.cpp.
References clear_ev_type_to_socks_map(), flow::net_flow::Node::event_set_check_baseline(), FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, m_baseline_check_pending, m_can, m_mutex, m_node, m_state, poll(), S_CLOSED, flow::net_flow::error::S_EVENT_SET_CLOSED, flow::net_flow::error::S_EVENT_SET_DOUBLE_WAIT_OR_POLL, S_INACTIVE, and S_WAITING.
Referenced by poll(), and sync_wait_impl().
bool flow::net_flow::Event_set::remove_wanted_socket | ( | typename Socket::Ptr | sock, |
Event_type | ev_type, | ||
Error_code * | err_code = 0 |
||
) |
Opposite of add_wanted_socket().
See | add_wanted_socket(). |
sock | Socket to remove. |
ev_type | See add_wanted_socket(). |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_EVENT_DOES_NOT_EXIST, error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
true
if and only if no error occurred (*err_code
is success). Definition at line 1052 of file event_set.hpp.
References flow::util::Linked_hash_set< Key, Hash, Pred >::erase(), FLOW_ERROR_EMIT_ERROR, FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_mutex, m_want, ok_to_mod_socket_set(), and flow::net_flow::error::S_EVENT_SET_EVENT_DOES_NOT_EXIST.
|
staticprivate |
Helper that returns a loggable string representing the socket stored in the given boost::any
that stores a value allowed by the members of Event_type enum
.
sock_as_any | See above. sock_as_any.empty() is also allowed. |
Definition at line 777 of file event_set.cpp.
References flow::util::ostream_op_to_string().
Referenced by flow::net_flow::Node::event_set_all_check_delta(), and flow::net_flow::Node::event_set_check_baseline().
Event_set::State flow::net_flow::Event_set::state | ( | ) | const |
Current State of the Event_set.
Note that this may change the moment the method returns.
Definition at line 60 of file event_set.cpp.
References m_mutex, and m_state.
Referenced by operator<<().
bool flow::net_flow::Event_set::swap_wanted_sockets | ( | Sockets * | target_set, |
Event_type | ev_type, | ||
Error_code * | err_code | ||
) |
Efficiently exchanges the current set of sockets we want to know are "ready" by the definiton of the given event type.
See individual Event_type enumeration members' doc comments for exact definition of readiness for each Event_type. For example, Event_type::S_PEER_SOCKET_READABLE means we want to know when sock->receive()
would yield either some data or an error, but not no data and no error. Use this to perform arbitrarily complex operations on the internal set storing sockets of interest for the given event type ev_type
, when the add_wanted_socket() and remove_wanted_socket() methods are insufficient. For example:
The swap paradigm (precursor to the "move" paradigm added in C++11) allows arbitrarily complex operations without sacrificing performance or thread safety.
target_set | Pointer to set of sockets to which to load the current internal set. Currently contained sockets must be from the same Node that originated this Event_set. |
ev_type | See add_wanted_socket(). |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_EVENT_SET_CLOSED, error::Code::S_EVENT_SET_IMMUTABLE_WHEN_WAITING. |
true
if and only if no error occurred (*err_code
is success). Definition at line 493 of file event_set.cpp.
References FLOW_ERROR_EXEC_AND_THROW_ON_ERROR, FLOW_LOG_TRACE, m_mutex, m_want, ok_to_mod_socket_set(), flow::util::Linked_hash_set< Key, Hash, Pred >::size(), flow::util::Linked_hash_set< Key, Hash, Pred >::swap(), and swap_wanted_sockets().
Referenced by swap_wanted_sockets().
bool flow::net_flow::Event_set::sync_wait | ( | const boost::chrono::duration< Rep, Period > & | max_wait, |
Error_code * | err_code = 0 |
||
) |
Same as the other sync_wait() but will stop waiting if the timeout given as argument expires.
If the timeout expires, it is the error code error::Code::S_WAIT_USER_TIMEOUT. This is akin to a select()
call with a finite timeout.
An additional error situation is possible in addition to that described in the 2nd/3rd paragraphs of the other sync_wait()'s doc header: if this is close()
d during the wait, and the wait times out, error::Code::S_EVENT_SET_CLOSED will be emitted when this timeout is detected. On the positive side, that means sync_wait(timeout)
will eventually exit no matter what.
Tip: Typical types you might use for max_wait
: boost::chrono::milliseconds
, boost::chrono::seconds
, boost::chrono::high_resolution_clock::duration
.
No guarantees are made as to the accuracy of the timeout timer, although you can optimistically provide arbitrarily precise values for max_wait
.
Rep | See boost::chrono::duration documentation (and see above tip). |
Period | See boost::chrono::duration documentation (and see above tip). |
max_wait | The maximum amount of time from now to wait before giving up on the wait and returning. "duration<Rep, Period>::max()" will eliminate the time limit and cause indefinite wait. |
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: Same as the other sync_wait() plus: error::Code::S_WAIT_USER_TIMEOUT. |
true
if and only if no error occurred (*err_code
is success). Timeout expiring IS an error, in particular. Definition at line 1092 of file event_set.hpp.
References flow::util::chrono_duration_to_fine_duration(), and sync_wait_impl().
bool flow::net_flow::Event_set::sync_wait | ( | Error_code * | err_code = 0 | ) |
Blocks indefinitely until one or more of the previously described events hold – or the wait is interrupted; saves them for retrieval via emit_result_sockets(), etc.
; and returns. This is akin to a select()
call with no (i.e., infinite) timeout.
The special case of Node::interrupt_all_waits() interrupting this wait – which is conceptually similar to EINTR
in POSIX – manifests itself as error::Code::S_WAIT_INTERRUPTED. In this case, emit_result_sockets() (etc.) should not be used, as one should assume no events are active due to the interruption.
In a non-error invocation, state() will be State::S_INACTIVE before and after the call, unless underlying Node is destroyed, in which case the final state may be State::S_CLOSED. In an error invocation, state() will not change, and the method will return immediately. Additionally, the method will NEVER return, if another thread calls this->close()
or this->async_wait_finish()
during this sync_wait() (so don't do that).
err_code | See flow::Error_code docs for error reporting semantics. Generated codes: error::Code::S_WAIT_INTERRUPTED, error::Code::S_EVENT_SET_NO_EVENTS, error::Code::S_EVENT_SET_DOUBLE_WAIT_OR_POLL, error::Code::S_EVENT_SET_CLOSED. |
true
if and only if no error occurred (*err_code
is success). Definition at line 458 of file event_set.cpp.
References sync_wait().
Referenced by sync_wait().
|
private |
Same as the public sync_wait(max_wait)
but uses a Fine_clock
-based Fine_duration
non-template type for implementation convenience and to avoid code bloat in specifying timeout.
max_wait | See the public sync_wait() with a max_wait argument. "duration<Rep, Period>::max()" maps to the value Fine_duration::max() for this argument. |
err_code | See sync_wait(). |
Definition at line 336 of file event_set.cpp.
References async_wait(), async_wait_finish(), ev_type_to_socks_map_entry_is_empty(), FLOW_LOG_INFO, m_can, m_mutex, poll(), and flow::net_flow::error::S_WAIT_INTERRUPTED.
Referenced by sync_wait().
|
friend |
See rationale for friend
ing Node in class Event_set documentation header.
Definition at line 776 of file event_set.hpp.
|
related |
Prints string representation of given event type to given standard ostream
and returns the latter.
os | Stream to print to. |
ev_type | Value to serialize. |
os
. Definition at line 1532 of file event_set.cpp.
|
related |
Prints string representation of given Event_set state to given standard ostream
and returns the latter.
os | Stream to print to. |
state | Value to serialize. |
os
. Definition at line 1509 of file event_set.cpp.
References state().
|
private |
While in State::S_WAITING, if this is true
, an exhaustive check of all desired events is yet to be performed (in thread W); if false
, it has alredy been performed (in thread W), and only "delta" checks need to be checked from now on during this wait.
See details in giant comment block inside async_wait().
Definition at line 934 of file event_set.hpp.
Referenced by poll().
|
private |
The sockets, categorized by Event_type of interest, that were found to be "ready" (as defined in the doc header for each Event_type), during the last wait (State::S_WAITING state).
For each WAITING period, each set in m_can following that period must be a subset of the corresponding m_want set when entering that period.
E.g., m_can[S_PEER_SOCKET_READABLE]
after WAITING is a subset of m_want[S_PEER_SOCKET_READABLE]
when just starting WAITING.
Definition at line 920 of file event_set.hpp.
Referenced by clear(), clear_result_sockets(), emit_result_sockets(), events_detected(), poll(), and sync_wait_impl().
|
mutableprivate |
Mutex protecting ALL data in this object.
Definition at line 937 of file event_set.hpp.
Referenced by add_wanted_socket(), async_wait(), async_wait_finish(), clear(), clear_result_sockets(), clear_wanted_sockets(), close(), emit_result_sockets(), events_detected(), events_wanted(), node(), poll(), remove_wanted_socket(), state(), swap_wanted_sockets(), and sync_wait_impl().
|
private |
See node(). Should be set before user gets access to *this
. Must not be modified by non-W threads after that.
Definition at line 904 of file event_set.hpp.
Referenced by async_wait(), close(), node(), and poll().
|
private |
During State::S_WAITING, stores the handler (a void
function with 1 bool
argument) that will be called once one or more events are found to hold.
m_on_event.empty()
at all other times.
Definition at line 926 of file event_set.hpp.
Referenced by async_wait_finish().
|
private |
See state(). Should be set before user gets access to *this
. Must not be modified by non-W threads after that.
Definition at line 901 of file event_set.hpp.
Referenced by async_wait(), async_wait_finish(), close(), events_detected(), events_wanted(), ok_to_mod_socket_set(), poll(), and state().
|
private |
The sockets, categorized by Event_type of interest, to check for "ready" status (as defined in the doc header for each Event_type), in the next wait (State::S_WAITING state).
Definition at line 910 of file event_set.hpp.
Referenced by add_wanted_socket(), async_wait(), clear(), clear_wanted_sockets(), events_wanted(), remove_wanted_socket(), and swap_wanted_sockets().
|
staticprivate |
Mapping from each possible Event_type to the Node method that determines whether the condition defined by that Event_type is currently true for the socket wrapped in the boost::any
argument passed to the method.
E.g., bool Node::sock_is_readable(const boost::any sock_as_any) const
is to return true if and only if sock = boost::any_cast<Peer_socket::Ptr>(sock_as_any)
– which is a Peer_socket::Ptr – would yield non-zero or zero and error if one were to execute sock->receive()
. Note that the latter condition is defined by the doc comment on Event_type::S_PEER_SOCKET_READABLE.
Definition at line 897 of file event_set.hpp.
Referenced by flow::net_flow::Node::event_set_check_baseline().