2
3
5#include <so_5/agent.hpp>
6#include <so_5/mbox.hpp>
7#include <so_5/enveloped_msg.hpp>
8#include <so_5/environment.hpp>
9#include <so_5/send_functions.hpp>
11#include <so_5/impl/internal_env_iface.hpp>
12#include <so_5/impl/coop_private_iface.hpp>
14#include <so_5/impl/delivery_filter_storage.hpp>
15#include <so_5/impl/msg_tracing_helpers.hpp>
16#include <so_5/impl/process_unhandled_exception.hpp>
17#include <so_5/impl/std_message_sinks.hpp>
18#include <so_5/impl/subscription_storage_iface.hpp>
20#include <so_5/impl/enveloped_msg_details.hpp>
22#include <so_5/details/abort_on_fatal_error.hpp>
24#include <so_5/spinlocks.hpp>
41 static constexpr std::array<
char, 16> hex_symbols{
42 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
43 '8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'
54 std::uintptr_t ptr_as_uint =
59 constexpr unsigned int half_octet = 4u;
60 unsigned bits_to_process =
sizeof(
void *) * (half_octet * 2u);
61 while( bits_to_process >= half_octet )
63 const auto index =
static_cast<std::size_t>(
64 (ptr_as_uint >> (bits_to_process - half_octet)) & 0x0Fu
67 *(it++) = hex_symbols[ index ];
69 bits_to_process -= half_octet;
87 "Name of an agent can't be empty" );
89 constexpr std::size_t max_unit_value =
90 std::numeric_limits<
unsigned int>::max();
91 if( max_unit_value < length )
93 "Name of an agent is too long (length should fit "
94 "into unsigned int)" );
96 return static_cast<
unsigned int>( length );
111 m_value.reset(
new char[ value.size() ] );
112 std::copy( std::begin(value), std::end(value),
m_value.get() );
137 :
m_value{ std::exchange( other
.m_value, std::unique_ptr<
char[] >{} ) }
162 std::string_view result;
178
179
180
181
185 std::ostringstream ss;
186 ss <<
"<state:target=" << agent <<
":this=" << st <<
">";
209 const state_t & state_to_switch )
217 const state_t & current_state )
noexcept
242 duration_t::zero()
);
249 const state_t & current_state )
noexcept
275 std::string state_name,
276 state_t * parent_state,
277 std::size_t nested_level,
293 "max nesting deep for agent states is " +
310 : state_t
{ agent
, std::string()
, nullptr, 0
, state_history
}
316 std::string state_name )
322 std::string state_name,
324 : state_t
{ agent
, std::move(state_name)
, nullptr, 0
, state_history
}
334 std::string state_name )
340 std::string state_name,
344 std::move(state_name)
,
352 " is already defined: " +
365 std::string state_name )
371 std::string state_name,
375 std::move(state_name)
,
403state_t::
operator == (
const state_t & state )
const noexcept
405 return &state ==
this;
411 auto getter = [
this]() -> std::string {
426#if defined(__clang__
)
427#pragma clang diagnostic push
428#pragma clang diagnostic ignored "-Wexit-time-destructors"
429#pragma clang diagnostic ignored "-Wglobal-constructors"
433
434
435
436
437
438
439
440
442 nullptr, "<AWAITING_DEREGISTRATION_AFTER_UNHANDLED_EXCEPTION>" );
445
446
447
448
449
450
451
452
454 nullptr, "<DEADLETTER_STATE>" );
456#if defined(__clang__
)
457#pragma clang diagnostic pop
482 const state_t & state_to_switch )
484 if( duration_t::zero() == timeout )
486 "zero can't be used as time limit for state: " +
493 timeout, std::cref(state_to_switch) );
528 const state_t * s =
this;
539 "there is no initial substate for composite state: " +
585
586
587
588
589
590
596 mbox_t standard_mbox )
598 mbox_t result
{ std::move(standard_mbox)
};
600 const auto & factory =
604 result
= factory( agent_ptr, std::move(result) );
611 "MPSC mbox is expected as the direct mbox "
620
621
622
623
624
625
626
627
629subscription_storage_factory_t
715 state_t::path_t path;
718 const auto past_the_end = [&path,
this]() {
719 auto r = begin(path);
724 return past_the_end != std::find( begin(path), past_the_end, &state_to_check );
738 agent_state_listener_unique_ptr_t state_listener )
742 std::move( state_listener )
) );
797 "an attempt to switch agent state when another state "
798 "switch operation is in progress for the same agent" );
812 const state_t & new_state )
865 "agent_t::so_coop() can be completed because agent is not bound "
866 "to any cooperation" );
904 enum class demand_type_t {
905 message, enveloped_msg, other
911 const auto demand_type =
913 demand_type_t::message :
915 demand_type_t::enveloped_msg : demand_type_t::other));
917 if( demand_type_t::other != demand_type )
921 d
, "create_execution_hint" );
922 if( demand_type_t::message == demand_type )
929 current_thread_id_t thread_id ) {
949 current_thread_id_t thread_id ) {
968 current_thread_id_t thread_id ) {
993 "agent_t::so_this_coop_disp_binder() can be completed "
994 "because agent is not bound to any cooperation" );
1018 agent_ref_t agent_ref
( this );
1067 log_stream <<
"Unexpected error: m_event_queue contains "
1068 "nullptr. Unable to push demand_handler_on_finish for "
1069 "the agent (" <<
this <<
"). Application will be aborted"
1084 const mbox_t & mbox_ref,
1085 std::type_index msg_type,
1086 const state_t & target_state,
1087 const event_handler_method_t & method,
1101 "new subscription can't made for deactivated agent" );
1115 const mbox_t & mbox,
1116 const std::type_index & msg_type,
1117 const event_handler_method_t & method,
1126 "new deadletter handler can't be set for deactivated agent" );
1140 const mbox_t & mbox,
1141 const std::type_index & msg_type )
1154 const std::type_index & msg_type )
1161 std::string(
"message type without "
1162 "predefined limit for that type, type: " ) +
1170 const mbox_t & mbox,
1171 const std::type_index & msg_type,
1172 const state_t & target_state )
1185 const mbox_t & mbox,
1186 const std::type_index & msg_type )
1193 "do_drop_subscription_for_all_states" );
1200 const mbox_t & mbox,
1201 const std::type_index & msg_type,
1202 const state_t & target_state )
const noexcept
1210 const mbox_t & mbox,
1211 const std::type_index & msg_type )
const noexcept
1220
1221
1222
1223
1224
1225
1226inline demand_handler_pfn_t
1229 const message_ref_t & msg )
1250 log_stream <<
"message that has data and message_kind_t::signal!"
1251 "Signals can't have data. Application will be aborted!"
1268 const std::type_index & msg_type,
1269 const message_ref_t & message )
1288 current_thread_id_t working_thread_id,
1295 working_thread_id
);
1301 catch(
const std::exception & x )
1330 current_thread_id_t working_thread_id,
1338 working_thread_id
);
1344 catch(
const std::exception & x )
1372 current_thread_id_t working_thread_id,
1378 d
, "demand_handler_on_message" );
1395 current_thread_id_t working_thread_id,
1401 d
, "demand_handler_on_enveloped_msg" );
1413 current_thread_id_t working_thread_id,
1416 event_handler_method_t method )
1432 catch(
const std::exception & x )
1446 current_thread_id_t working_thread_id,
1486 const char * operation_name )
const
1490 std::ostringstream s;
1493 <<
": operation is enabled only on agent's working thread; "
1494 <<
"working_thread_id: ";
1521 const mbox_t & mbox,
1522 const std::type_index & msg_type,
1523 delivery_filter_unique_ptr_t filter )
1531 "new delivery filter can't be set for deactivated agent" );
1549 const mbox_t & mbox,
1550 const std::type_index & msg_type )
noexcept
1564 if( !search_result )
1568 return search_result;
1574 const char * context_marker )
1578 if( !search_result )
1591 return search_result;
1602 return search_result;
1618 if( !search_result )
1621 }
while( search_result ==
nullptr && s !=
nullptr );
1623 return search_result;
1638 const state_t & state_to_be_set )
1647 "unable to switch agent to another state because the "
1648 "agent is already deactivated" );
1673 "unable to switch agent to alien state "
1674 "(the state that doesn't belong to this agent)" );
1679 const state_t & state_to_be_set )
noexcept
1681 state_t::path_t old_path;
1682 state_t::path_t new_path;
1692 std::size_t first_diff = 0;
1693 for(; first_diff < std::min(
1697 if( old_path[ first_diff ] != new_path[ first_diff ] )
1705 *
this, *current_st
);
1721 *
this, state_to_be_set
);
1723 for( std::size_t i = first_diff;
virtual mbox_id_t id() const =0
Unique ID of this mbox.
virtual mbox_type_t type() const =0
Get the type of message box.
Interface for message sink.
agent_context_t(environment_t &env, agent_tuning_options_t options)
agent_tuning_options_t & options()
Read-Write access to agent options.
environment_t & env() const
Access to SObjectizer Environment.
Helper class for holding agent's identity (name or pointer).
agent_identity_t(std::string_view name) noexcept
Initializing constructor for case when agent has a user specified name.
agent_identity_t(const agent_t *pointer) noexcept
Initializing constructor for case when agent has no user specified name.
Interface of the agent state listener.
static demand_handler_pfn_t get_demand_handler_on_start_ptr() noexcept
impl::state_listener_controller_t m_state_listener_controller
State listeners controller.
static void process_enveloped_msg(current_thread_id_t working_thread_id, execution_demand_t &d, const impl::event_handler_data_t *handler_data)
Actual implementation of enveloped message handling.
std::unique_ptr< impl::sinks_storage_t > m_message_sinks
Holder of message sinks for that agent.
void do_change_agent_state(const state_t &state_to_be_set)
Perform actual operations related to state switch.
void so_initiate_agent_definition()
A correct initiation of so_define_agent method call.
so_5::current_thread_id_t m_working_thread_id
Working thread id.
default_rw_spinlock_t m_event_queue_lock
Event queue operation protector.
const name_for_agent_t m_name
Optional name for the agent.
static const impl::event_handler_data_t * find_deadletter_handler(execution_demand_t &demand)
Search for event handler between deadletter handlers.
static demand_handler_pfn_t get_demand_handler_on_message_ptr() noexcept
bool is_agent_deactivated() const noexcept
Is agent already deactivated.
void so_switch_to_awaiting_deregistration_state()
Switching agent to special state in case of unhandled exception.
const state_t & so_current_state() const
Access to the current agent state.
static void process_message(current_thread_id_t working_thread_id, execution_demand_t &d, thread_safety_t thread_safety, event_handler_method_t method)
Actual implementation of message handling.
agent_ref_t create_ref()
Make an agent reference.
bool so_is_active_state(const state_t &state_to_check) const noexcept
Is a state activated?
void ensure_operation_is_on_working_thread(const char *operation_name) const
Enables operation only if it is performed on agent's working thread.
bool so_was_defined() const
Is method define_agent already called?
agent_status_t
Enumeration of possible agent statuses.
@ defined
Agent is defined.
@ state_switch_in_progress
State switch operation is in progress.
void destroy_all_subscriptions_and_filters() noexcept
Destroy all agent's subscriptions.
void so_create_deadletter_subscription(const mbox_t &mbox, const std::type_index &msg_type, const event_handler_method_t &method, thread_safety_t thread_safety)
Create a subscription for a deadletter handler.
void shutdown_agent() noexcept
Agent shutdown deriver.
void ensure_binding_finished()
Ensures that all agents from cooperation are bound to dispatchers.
coop_t * m_agent_coop
Agent is belong to this cooperation.
void so_drop_subscription(const mbox_t &mbox, const state_t &target_state)
Drop subscription for the state specified.
agent_status_t m_current_status
Current agent status.
event_queue_t * m_event_queue
A pointer to event_queue.
virtual void so_define_agent()
Hook on define agent for SObjectizer.
void drop_all_delivery_filters() noexcept
Drops all delivery filters.
bool do_check_subscription_presence(const mbox_t &mbox, const std::type_index &msg_type, const state_t &target_state) const noexcept
Check the presence of a subscription.
void do_state_switch(const state_t &state_to_be_set) noexcept
Actual action for switching agent state.
std::unique_ptr< impl::delivery_filter_storage_t > m_delivery_filters
Delivery filters for that agents.
void return_to_default_state_if_possible() noexcept
Return agent to the default state.
agent_t(environment_t &env)
Constructor.
void do_set_delivery_filter(const mbox_t &mbox, const std::type_index &msg_type, delivery_filter_unique_ptr_t filter)
Set a delivery filter.
mbox_t so_make_new_direct_mbox()
Create a new direct mbox for that agent.
static execution_hint_t so_create_execution_hint(execution_demand_t &demand)
Create execution hint for the specified demand.
void so_change_state(const state_t &new_state)
Change the current state of the agent.
void push_event(const message_limit::control_block_t *limit, mbox_id_t mbox_id, const std::type_index &msg_type, const message_ref_t &message)
Push event into the event queue.
coop_handle_t so_coop() const
Get a handle of agent's coop.
void so_deregister_agent_coop_normally()
A helper method for deregistering agent's coop in case of normal deregistration.
void do_drop_delivery_filter(const mbox_t &mbox, const std::type_index &msg_type) noexcept
Drop a delivery filter.
virtual exception_reaction_t so_exception_reaction() const noexcept
A reaction from SObjectizer to an exception from agent's event.
void so_deactivate_agent()
Deactivate the agent.
disp_binder_shptr_t so_this_coop_disp_binder() const
Returns the dispatcher binder that is used as the default binder for the agent's coop.
abstract_message_sink_t & detect_sink_for_message_type(const std::type_index &msg_type)
Helper function that returns a message sink to be used for subscriptions for specified message type.
static void demand_handler_on_message(current_thread_id_t working_thread_id, execution_demand_t &d)
Calls event handler for message.
virtual void so_evt_finish()
Hook of agent finish in SObjectizer.
static demand_handler_pfn_t get_demand_handler_on_finish_ptr() noexcept
void so_add_nondestroyable_listener(agent_state_listener_t &state_listener)
Add a state listener to the agent.
static const impl::event_handler_data_t * handler_finder_msg_tracing_disabled(execution_demand_t &demand, const char *context_marker)
Handler finder for the case when message delivery tracing is disabled.
const state_t * m_current_state_ptr
Current agent state.
const mbox_t m_direct_mbox
A direct mbox for the agent.
const priority_t m_priority
Priority of the agent.
agent_identity_t so_agent_name() const noexcept
Get an optional name of the agent.
static const impl::event_handler_data_t * handler_finder_msg_tracing_enabled(execution_demand_t &demand, const char *context_marker)
Handler finder for the case when message delivery tracing is enabled.
void bind_to_coop(coop_t &coop)
Bind agent to the cooperation.
static const impl::event_handler_data_t * find_event_handler_for_current_state(execution_demand_t &demand)
Actual search for event handler with respect to parent-child relationship between agent states.
static void demand_handler_on_start(current_thread_id_t working_thread_id, execution_demand_t &d)
Calls so_evt_start method for agent.
const mbox_t & so_direct_mbox() const
Get the agent's direct mbox.
impl::subscription_storage_unique_ptr_t m_subscriptions
All agent's subscriptions.
void so_destroy_deadletter_subscription(const mbox_t &mbox, const std::type_index &msg_type)
Destroy a subscription for a deadletter handler.
static void demand_handler_on_finish(current_thread_id_t working_thread_id, execution_demand_t &d)
Calls so_evt_finish method for agent.
bool do_check_deadletter_presence(const mbox_t &mbox, const std::type_index &msg_type) const noexcept
Check the presence of a deadletter handler.
void do_drop_subscription_for_all_states(const mbox_t &mbox, const std::type_index &msg_type)
Remove subscription for all states.
agent_t(context_t ctx)
Constructor which simplifies agent construction with or without agent's tuning options.
static agent_tuning_options_t tuning_options()
Create tuning options object with default values.
void so_add_destroyable_listener(agent_state_listener_unique_ptr_t state_listener)
Add a state listener to the agent.
environment_t & so_environment() const noexcept
Access to the SObjectizer Environment which this agent is belong.
const state_t & so_default_state() const
Access to the agent's default state.
subscription_bind_t so_subscribe(const mbox_t &mbox_ref)
Initiate subscription.
void so_bind_to_dispatcher(event_queue_t &queue) noexcept
Binding agent to the dispatcher.
environment_t & m_env
SObjectizer Environment for which the agent is belong.
void so_deregister_agent_coop(int dereg_reason)
A helper method for deregistering agent's coop.
void do_drop_subscription(const mbox_t &mbox, const std::type_index &msg_type, const state_t &target_state)
Remove subscription for the state specified.
agent_t(environment_t &env, agent_tuning_options_t tuning_options)
Constructor which allows specification of agent's tuning options.
handler_finder_t m_handler_finder
Function for searching event handler.
virtual void so_evt_start()
Hook on agent start inside SObjectizer.
static demand_handler_pfn_t get_demand_handler_on_enveloped_msg_ptr() noexcept
void so_create_event_subscription(const mbox_t &mbox_ref, std::type_index type_index, const state_t &target_state, const event_handler_method_t &method, thread_safety_t thread_safety, event_handler_kind_t handler_kind)
Create a subscription for an event.
static void demand_handler_on_enveloped_msg(current_thread_id_t working_thread_id, execution_demand_t &d)
Handles the enveloped message.
A collector for agent tuning options.
so_5::priority_t query_priority() const noexcept
Get priority value.
name_for_agent_t giveout_agent_name() noexcept
Gives away the name for an agent.
const custom_direct_mbox_factory_t & query_custom_direct_mbox_factory() const noexcept
Get a reference to custom direct mbox factory.
bool is_user_provided_subscription_storage_factory() const noexcept
Does a user provide a specific subscription_storage_factory?
const subscription_storage_factory_t & query_subscription_storage_factory() const noexcept
message_limit::description_container_t giveout_message_limits()
Type of smart handle for a cooperation.
exception_reaction_t exception_reaction() const noexcept
Get the current exception rection flag for that cooperation.
std::mutex m_lock
A lock for synchonization of some operations on coop.
disp_binder_shptr_t coop_disp_binder() const noexcept(noexcept(disp_binder_shptr_t{ this->m_coop_disp_binder }))
Return the default dispatcher binder for the coop.
coop_handle_t handle() noexcept
Get handle for this coop.
virtual void access_hook(access_context_t context, handler_invoker_t &invoker) noexcept=0
An implementation of handler_invoker interface.
agent_demand_handler_invoker_t(current_thread_id_t work_thread_id, execution_demand_t &demand, const so_5::impl::event_handler_data_t &handler_data)
Initializing constructor.
void deregister_coop(coop_handle_t coop, int reason) noexcept
Deregister the cooperation.
An interface of event queue for agent.
virtual void push(execution_demand_t demand)=0
Enqueue new event to the queue.
virtual void push_evt_finish(execution_demand_t demand) noexcept=0
Enqueue a demand for evt_finish event.
virtual void push_evt_start(execution_demand_t demand)=0
Enqueue a demand for evt_start event.
A hint for a dispatcher for execution of event for the concrete execution_demand.
execution_hint_t(execution_demand_t &demand, direct_func_t direct_func, thread_safety_t thread_safety)
Initializing constructor.
static execution_hint_t create_empty_execution_hint(execution_demand_t &demand)
A special class for accessing private members of agent_coop.
static void decrement_usage_count(coop_t &coop)
static void increment_usage_count(coop_t &coop) noexcept
Storage for message delivery filters.
void drop_all() noexcept
Drop all defined filters.
void set_delivery_filter(const mbox_t &mbox, const std::type_index &msg_type, delivery_filter_unique_ptr_t filter, so_5::outliving_reference_t< abstract_message_sink_t > owner)
Set a delivery filter.
void drop_delivery_filter(const mbox_t &mbox, const std::type_index &msg_type) noexcept
Remove delivery filter.
A helper class for accessing the functionality of environment-class which is specific for SObjectizer...
event_queue_t * event_queue_on_bind(agent_t *agent, event_queue_t *original_queue) noexcept
Call the event_queue_hook when an agent is being bound to a particular event_queue.
subscription_storage_factory_t default_subscription_storage_factory() const noexcept(noexcept(subscription_storage_factory_t{}=subscription_storage_factory_t{}))
Get the default storage subscription factory.
void event_queue_on_unbind(agent_t *agent, event_queue_t *queue) noexcept
Call the event_queue_hook when an agent is being unbound from its event_queue.
mbox_t create_ordinary_mpsc_mbox(agent_t &single_consumer)
Create multi-producer/single-consumer mbox that handles message limits.
bool is_msg_tracing_enabled() const
Is message delivery tracing enabled?
internal_env_iface_t(environment_t &env)
Initializing constructor.
mbox_t create_limitless_mpsc_mbox(agent_t &single_consumer)
Create multi-producer/single-consumer mbox that ignores message limits.
virtual abstract_message_sink_t * find_or_create(const std::type_index &msg_type)=0
void add(internal_state_listener_unique_ptr_t listener)
Add a new listener.
static auto wrap_nondestroyable(agent_state_listener_t &listener)
void changed(agent_t &agent, const state_t &state) noexcept
Handle state change.
static auto wrap_destroyable(agent_state_listener_unique_ptr_t listener)
agent_t::agent_status_t m_previous_status
state_switch_guard_t(agent_t &agent)
virtual const event_handler_data_t * find_handler(mbox_id_t mbox_id, const std::type_index &msg_type, const state_t ¤t_state) const noexcept=0
virtual void drop_subscription(const mbox_t &mbox, const std::type_index &msg_type, const state_t &target_state) noexcept=0
virtual void drop_subscription_for_all_states(const mbox_t &mbox, const std::type_index &msg_type) noexcept=0
virtual void create_event_subscription(const mbox_t &mbox, const std::type_index &msg_type, abstract_message_sink_t &message_sink, const state_t &target_state, const event_handler_method_t &method, thread_safety_t thread_safety, event_handler_kind_t handler_kind)=0
virtual void drop_all_subscriptions() noexcept=0
Drop all subscriptions.
intrusive_ptr_t(T *obj) noexcept
Constructor for a raw pointer.
intrusive_ptr_t(intrusive_ptr_t &&o) noexcept
Move constructor.
T * operator->() const noexcept
intrusive_ptr_t & operator=(intrusive_ptr_t &&o) noexcept
Move operator.
T & operator*() const noexcept
intrusive_ptr_t() noexcept
Default constructor.
A base class for agent messages.
friend message_kind_t message_kind(const message_t &what)
Helper method for quering kind of the message.
A message wrapped to be used as type of argument for event handlers.
Type for holding agent name.
unsigned int m_length
Name length.
name_for_agent_t & operator=(name_for_agent_t &&other) noexcept
name_for_agent_t(const name_for_agent_t &)
name_for_agent_t(name_for_agent_t &&other) noexcept
std::unique_ptr< char[] > m_value
Name storage.
bool has_value() const noexcept
Does this object have a value?
name_for_agent_t & operator=(const name_for_agent_t &)
std::string_view as_string_view() const
Get the value as a string_view.
name_for_agent_t()
Default constructor makes an null value.
name_for_agent_t(std::string_view value)
Initializing constructor.
Wrapper around a pointer to partially constructed agent.
partially_constructed_agent_ptr_t(agent_t *ptr)
Scoped guard for shared locks.
read_lock_guard_t(Lock &l)
bool is_target(const agent_t *agent) const noexcept
Is agent owner of this state?
state_t & time_limit(duration_t timeout, const state_t &state_to_switch)
Set up a time limit for the state.
state_t & drop_time_limit()
Drop time limit for the state if defined.
on_exit_handler_t m_on_exit
Handler for the exit from the state.
history_t m_state_history
Type of state history.
const state_t * parent_state() const noexcept
Get a parent state if exists.
void fill_path(path_t &path) const noexcept
A helper method for building a path from top-level state to this state.
state_t(initial_substate_of parent, std::string state_name, history_t state_history)
Constructor for the case when state is the initial substate of some parent state.
state_t(substate_of parent)
Constructor for the case when state is a substate of some parent state.
std::size_t nested_level() const noexcept
Query nested level for the state.
bool is_active() const noexcept
Is this state or any of its substates activated?
state_t(state_t &&other)
Move constructor.
state_t(agent_t *target_agent, std::string state_name, state_t *parent_state, std::size_t nested_level, history_t state_history)
Fully initialized constructor.
std::string m_state_name
State name.
state_t(agent_t *agent, std::string state_name, history_t state_history)
state_t * m_parent_state
Parent state.
state_t(substate_of parent, std::string state_name, history_t state_history)
Constructor for the case when state is a substate of some parent state.
const state_t * actual_state_to_enter() const
Find actual state to be activated for agent.
state_t(initial_substate_of parent)
Constructor for the case when state is the initial substate of some parent state.
const state_t * m_initial_substate
The initial substate.
bool operator==(const state_t &state) const noexcept
state_t(initial_substate_of parent, std::string state_name)
Constructor for the case when state is the initial substate of some parent state.
size_t m_substate_count
Number of substates.
state_t(agent_t *agent, history_t state_history)
void call_on_enter() const noexcept
Call for on enter handler if defined.
bool operator!=(const state_t &state) const noexcept
void call_on_exit() const noexcept
Call for on exit handler if defined.
agent_t *const m_target_agent
Owner of this state.
std::string query_name() const
Get textual name of the state.
static constexpr const std::size_t max_deep
Max deep of nested states.
state_t(substate_of parent, std::string state_name)
Constructor for the case when state is a substate of some parent state.
const state_t * m_last_active_substate
Last active substate.
void handle_time_limit_on_enter() const
A special handler of time limit to be used on entering into state.
state_t(agent_t *agent, std::string state_name)
void activate() const
Switch agent to that state.
history_t
Type of history for state.
@ none
State has no history.
@ deep
State has deep history.
@ shallow
State has shallow history.
on_enter_handler_t m_on_enter
Handler for the enter to the state.
std::unique_ptr< time_limit_t > m_time_limit
A definition of time limit for the state.
std::size_t m_nested_level
Nesting level for state.
void update_history_in_parent_states() const
A helper method which is used during state change for update state with history.
void handle_time_limit_on_exit() const
A special handler of time limit to be used on exiting from state.
std::enable_if< details::lambda_traits::is_lambda< Lambda >::value, subscription_bind_t & >::type event(Lambda &&lambda, thread_safety_t thread_safety=not_thread_safe)
Make subscription to the message by lambda-function.
subscription_bind_t & in(const state_t &state)
Set up a state in which events are allowed be processed.
An indentificator for the timer.
void release() noexcept
Release the timer event.
#define SO_5_LOG_ERROR(logger, var_name)
A special macro for helping error logging.
#define SO_5_THROW_EXCEPTION(error_code, desc)
demand_handler_pfn_t select_demand_handler_for_message(const agent_t &agent, const message_ref_t &msg)
A helper function to select actual demand handler in dependency of message kind.
mbox_t make_direct_mbox_with_respect_to_custom_factory(partially_constructed_agent_ptr_t agent_ptr, const agent_tuning_options_t &tuning_options, mbox_t standard_mbox)
Helper for creation of the direct mbox for an agent.
unsigned int ensure_valid_agent_name_length(std::size_t length)
std::string create_anonymous_state_name(const agent_t *agent, const state_t *st)
const state_t deadletter_state(nullptr, "<DEADLETTER_STATE>")
A special object to be used as state for make subscriptions for deadletter handlers.
subscription_storage_factory_t detect_subscription_storage_factory_to_use(environment_t &env, const agent_tuning_options_t &tuning_options)
Helper for selection of subscription storage factory.
const state_t awaiting_deregistration_state(nullptr, "<AWAITING_DEREGISTRATION_AFTER_UNHANDLED_EXCEPTION>")
A special object for the state in which agent is awaiting for deregistration after unhandled exceptio...
Enumeration of cooperation deregistration reasons.
const int normal
Normal deregistration.
Some reusable and low-level classes/functions which can be used in public header files.
void abort_on_fatal_error(L logging_lambda) noexcept
auto do_with_rollback_on_exception(Main_Action main_action, Rollback_Action rollback_action) -> decltype(main_action())
Helper function for do some action with rollback in the case of an exception.
auto invoke_noexcept_code(L lambda) noexcept -> decltype(lambda())
envelope_t & message_to_envelope(const message_ref_t &src_msg)
A helper function for casting message instance to envelope instance.
access_context_t
Information about context on that enveloped message is handled.
Internal namespace with details of agent_t implementation.
Various helpers for message delivery tracing mechanism.
void safe_trace_state_leaving(const agent_t &state_owner, const state_t &state)
Helper for tracing the fact of leaving a state.
void safe_trace_state_entering(const agent_t &state_owner, const state_t &state)
Helper for tracing the fact of entering into a state.
void trace_deadletter_handler_search_result(const execution_demand_t &demand, const char *context_marker, const event_handler_data_t *search_result)
Helper for tracing the result of search of deadletter handler.
void trace_event_handler_search_result(const execution_demand_t &demand, const char *context_marker, const event_handler_data_t *search_result)
Helper for tracing the result of event handler search.
Details of SObjectizer run-time implementations.
void process_unhandled_unknown_exception(current_thread_id_t working_thread_id, agent_t &a_exception_producer) noexcept
Processor of unhandled exception of unknown type from agent's event handler.
void process_unhandled_exception(current_thread_id_t working_thread_id, const std::exception &ex, agent_t &a_exception_producer) noexcept
Processor of unhandled exception from agent's event handler.
static std::unique_ptr< sinks_storage_t > create_sinks_storage_if_necessary(partially_constructed_agent_ptr_t owner_ptr, so_5::message_limit::description_container_t &&descriptions)
Create info_storage object if there are some message limits.
All stuff related to message limits.
Private part of message limit implementation.
const int rc_state_nesting_is_too_deep
Nesting of agent states is too deep.
const int rc_initial_substate_already_defined
Initial substate for a composite state is already defined.
mbox_type_t
Type of the message box.
@ multi_producer_single_consumer
exception_reaction_t
A reaction of SObjectizer to an exception from agent event.
@ abort_on_exception
Execution of application must be aborted immediatelly.
current_thread_id_t null_current_thread_id()
Get NULL thread id.
const thread_safety_t not_thread_safe
Shorthand for thread unsafety indicator.
const thread_safety_t thread_safe
Shorthand for thread safety indicator.
const int rc_operation_enabled_only_on_agent_working_thread
An attempt to perform an operation which is enabled only on agent's working thread.
const int rc_agent_unknown_state
Trying to switch to the unknown state.
const int rc_invalid_time_limit_for_state
Invalid value of time limit for an agent's state.
thread_safety_t
Thread safety indicator.
@ user_type_message
Message is an user type message.
@ enveloped_msg
Message is an envelope with some other message inside.
const int rc_empty_agent_name
Name for an agent can't be empty.
const int rc_agent_deactivated
Agent can't change state because the agent is already deactivated.
SO_5_FUNC void swap(name_for_agent_t &a, name_for_agent_t &b) noexcept
timer_id_t send_periodic(Target &&target, std::chrono::steady_clock::duration pause, std::chrono::steady_clock::duration period, Args &&... args)
A utility function for creating and delivering a periodic message to the specified destination.
const int rc_another_state_switch_in_progress
An attempt to switch agent state when another switch operation is in progress.
const int rc_no_initial_substate
An attempt to change agent state to a new composite state which have no initial state defined.
const int rc_agent_has_no_cooperation
Agent is not bound to a cooperation.
event_handler_kind_t
Kind of an event handler.
current_thread_id_t query_current_thread_id()
Get the ID of the current thread.
const int rc_message_has_no_limit_defined
An attempt to create subscription to message without predefined limit for that message type.
outliving_reference_t< T > outliving_mutable(T &r)
Make outliving_reference wrapper for mutable reference.
const int rc_mpsc_mbox_expected
An instance of MPSC mbox is expected as custom direct mbox.
Type for case when agent has no user-provided name.
SO_5_FUNC std::array< char, c_string_size > make_c_string() const noexcept
Make a c-string with text representation of a value.
static constexpr std::string_view c_string_prefix
Prefix to be used for string representation.
static constexpr std::size_t c_string_size
const agent_t * m_pointer_value
Value.
static constexpr std::string_view c_string_suffix
Suffix to be used for string representation.
A description of event execution demand.
mbox_id_t m_mbox_id
ID of mbox.
void call_handler(current_thread_id_t thread_id)
Helper method to simplify demand execution.
demand_handler_pfn_t m_demand_handler
Demand handler.
agent_t * m_receiver
Receiver of demand.
message_ref_t m_message_ref
Event incident.
const message_limit::control_block_t * m_limit
Optional message limit for that message.
execution_demand_t(agent_t *receiver, const message_limit::control_block_t *limit, mbox_id_t mbox_id, std::type_index msg_type, message_ref_t message_ref, demand_handler_pfn_t demand_handler) noexcept
std::type_index m_msg_type
Type of the message.
A helper class for temporary setting and then dropping the ID of the current working thread.
working_thread_id_sentinel_t(so_5::current_thread_id_t &id_var, so_5::current_thread_id_t value_to_set)
Information about event_handler and its properties.
thread_safety_t m_thread_safety
Is event handler thread safe or not.
event_handler_method_t m_method
Method for handling event.
event_handler_kind_t m_kind
Kind of this event handler.
Helper for marking initial substate of composite state.
A control block for one message limit.
static const control_block_t * none()
A special indicator about absence of control_block.
static void decrement(const control_block_t *limit)
time_limit_t(duration_t limit, const state_t &state_to_switch)
void set_up_limit_for_agent(agent_t &agent, const state_t ¤t_state) noexcept
const state_t & m_state_to_switch
void drop_limit_for_agent(agent_t &agent, const state_t ¤t_state) noexcept
Helper for marking a substate of composite state.