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'
46 std::array<
char, c_string_size> result;
48 c_string_prefix.begin(),
49 c_string_prefix.end(),
54 std::uintptr_t ptr_as_uint =
55 reinterpret_cast<std::uintptr_t>(m_pointer_value);
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;
72 it = std::copy( c_string_suffix.begin(), c_string_suffix.end(), it );
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() );
120 m_value.reset(
new char[ m_length ] );
123 other.m_value.get() + m_length,
153 swap( a.m_value, b.m_value );
162 std::string_view result;
164 result = std::string_view{ m_value.get(), m_length };
178
179
180
181
185 std::ostringstream ss;
186 ss <<
"<state:target=" << agent <<
":this=" << st <<
">";
212 const state_t & state_to_switch )
noexcept
226 const state_t & state_to_switch )
noexcept
229 m_state_to_switch = state_to_switch;
258 m_activation_data.reset();
271 const auto limit_exceeded_at = steady_clock::now() + m_limit;
272 m_activation_data.emplace(
273 so_5::send_periodic< msg_timeout >(
276 steady_clock::duration::zero() ),
291 m_activation_data.reset();
301 const steady_clock::time_point current_time )
const noexcept
303 if( m_activation_data.has_value() )
305 return m_activation_data->m_expiration_point <= current_time;
316 return m_state_to_switch.get();
338 steady_clock::time_point expiration_point )
364 std::string state_name,
366 std::size_t nested_level,
380 if( m_nested_level >= max_deep )
382 "max nesting deep for agent states is " +
383 std::to_string( max_deep ) );
405 std::string state_name )
411 std::string state_name,
423 std::string state_name )
429 std::string state_name,
438 if( m_parent_state->m_initial_substate )
440 "initial substate for state " + m_parent_state->query_name() +
441 " is already defined: " +
442 m_parent_state->m_initial_substate->query_name() );
454 std::string state_name )
460 std::string state_name,
494 return &state ==
this;
500 auto getter = [
this]() -> std::string {
501 if( m_state_name.empty() )
502 return create_anonymous_state_name( m_target_agent,
this );
508 return m_parent_state->query_name() +
"." + getter();
515#if defined(__clang__
)
516#pragma clang diagnostic push
517#pragma clang diagnostic ignored "-Wexit-time-destructors"
518#pragma clang diagnostic ignored "-Wglobal-constructors"
522
523
524
525
526
527
528
529
531 nullptr,
"<AWAITING_DEREGISTRATION_AFTER_UNHANDLED_EXCEPTION>" );
534
535
536
537
538
539
540
541
543 nullptr,
"<DEADLETTER_STATE>" );
545#if defined(__clang__
)
546#pragma clang diagnostic pop
571 const state_t & state_to_switch )
573 if( duration_t::zero() == timeout )
575 "zero can't be used as time limit for state: " +
587 m_time_limit = std::make_unique< time_limit_t >(
588 timeout, state_to_switch );
595 m_time_limit->deactivate();
596 m_time_limit->change( timeout, state_to_switch );
606 m_time_limit->activate(
607 m_target_agent->m_state_time_limit_handling_data );
610 m_time_limit.reset();
620 m_time_limit.reset();
639 "there is no initial substate for composite state: " +
672 m_time_limit->on_state_activation(
673 m_target_agent->m_state_time_limit_handling_data );
679 m_time_limit->on_state_deactivation();
694 return static_cast<
bool>(m_timeout_mbox);
699 mbox_t timeout_mbox )
701 m_timeout_mbox = std::move(timeout_mbox);
707 return m_timeout_mbox;
714
715
716
717
718
719
725 mbox_t standard_mbox )
727 mbox_t result{ std::move(standard_mbox) };
729 const auto & factory =
730 tuning_options.query_custom_direct_mbox_factory();
733 result = factory( agent_ptr, std::move(result) );
735 if( mbox_type_t::multi_producer_single_consumer
739 rc_mpsc_mbox_expected,
740 "MPSC mbox is expected as the direct mbox "
749
750
751
752
753
754
755
756
764 return tuning_options.query_subscription_storage_factory();
848 return current_path.end() != std::find(
849 current_path.begin(), current_path.end(), &state_to_check );
856 m_state_listener_controller.add(
857 impl::state_listener_controller_t::wrap_nondestroyable(
863 agent_state_listener_unique_ptr_t state_listener )
865 m_state_listener_controller.add(
866 impl::state_listener_controller_t::wrap_destroyable(
867 std::move( state_listener ) ) );
889 return m_direct_mbox;
895 return impl::internal_env_iface_t{ so_environment() }.create_ordinary_mpsc_mbox(
918 if( agent_t::agent_status_t::state_switch_in_progress
919 == agent.m_current_status )
921 rc_another_state_switch_in_progress,
922 "an attempt to switch agent state when another state "
923 "switch operation is in progress for the same agent" );
937 const state_t & new_state )
957 "so_drop_all_subscriptions_and_filters" );
967 so_5::query_current_thread_id() );
998 rc_agent_has_no_cooperation,
999 "agent_t::so_coop() can be completed because agent is not bound "
1000 "to any cooperation" );
1014 std::lock_guard< default_rw_spinlock_t > queue_lock{ m_event_queue_lock };
1021 actual_queue->push_evt_start(
1024 message_limit::control_block_t::none(),
1028 &agent_t::demand_handler_on_start ) );
1038 enum class demand_type_t {
1039 message, enveloped_msg, other
1045 const auto demand_type =
1046 (d.m_demand_handler == &agent_t::demand_handler_on_message ?
1047 demand_type_t::message :
1048 (d.m_demand_handler == &agent_t::demand_handler_on_enveloped_msg ?
1049 demand_type_t::enveloped_msg : demand_type_t::other));
1051 if( demand_type_t::other != demand_type )
1055 d
, "create_execution_hint" );
1056 if( demand_type_t::message == demand_type )
1059 return execution_hint_t(
1063 current_thread_id_t thread_id ) {
1067 handler->m_thread_safety,
1068 handler->m_method );
1079 return execution_hint_t(
1083 current_thread_id_t thread_id ) {
1084 process_enveloped_msg(
1099 return execution_hint_t(
1102 current_thread_id_t thread_id ) {
1103 demand.call_handler( thread_id );
1126 rc_agent_has_no_cooperation,
1127 "agent_t::so_this_coop_disp_binder() can be completed "
1128 "because agent is not bound to any cooperation" );
1136 if( m_name.has_value() )
1137 return { m_name.as_string_view() };
1146 m_subscriptions->drop_all_subscriptions();
1152 agent_ref_t agent_ref(
this );
1167 std::lock_guard< default_rw_spinlock_t > queue_lock{ m_event_queue_lock };
1183 m_event_queue->push_evt_finish(
1186 message_limit::control_block_t::none(),
1190 &agent_t::demand_handler_on_finish ) );
1201 log_stream <<
"Unexpected error: m_event_queue contains "
1202 "nullptr. Unable to push demand_handler_on_finish for "
1203 "the agent (" <<
this <<
"). Application will be aborted"
1222 const mbox_t & mbox_ref,
1223 std::type_index msg_type,
1224 const state_t & target_state,
1225 const event_handler_method_t & method,
1236 if( is_agent_deactivated() )
1238 so_5::rc_agent_deactivated,
1239 "new subscription can't made for deactivated agent" );
1241 m_subscriptions->create_event_subscription(
1244 detect_sink_for_message_type( msg_type ),
1253 const mbox_t & mbox,
1254 const std::type_index & msg_type,
1255 const event_handler_method_t & method,
1261 if( is_agent_deactivated() )
1263 so_5::rc_agent_deactivated,
1264 "new deadletter handler can't be set for deactivated agent" );
1266 m_subscriptions->create_event_subscription(
1269 detect_sink_for_message_type( msg_type ),
1273 event_handler_kind_t::final_handler );
1278 const mbox_t & mbox,
1279 const std::type_index & msg_type )
1287 m_subscriptions->drop_subscription( mbox, msg_type, deadletter_state );
1292 const std::type_index & msg_type )
1294 auto * result = m_message_sinks->find_or_create( msg_type );
1298 so_5::rc_message_has_no_limit_defined,
1299 std::string(
"message type without "
1300 "predefined limit for that type, type: " ) +
1308 const mbox_t & mbox,
1309 const std::type_index & msg_type,
1310 const state_t & target_state )
1318 m_subscriptions->drop_subscription( mbox, msg_type, target_state );
1323 const mbox_t & mbox,
1324 const std::type_index & msg_type )
1331 "do_drop_subscription_for_all_states" );
1333 m_subscriptions->drop_subscription_for_all_states( mbox, msg_type );
1338 const mbox_t & mbox,
1339 const std::type_index & msg_type,
1340 const state_t & target_state )
const noexcept
1342 return nullptr != m_subscriptions->find_handler(
1343 mbox->id(), msg_type, target_state );
1348 const mbox_t & mbox,
1349 const std::type_index & msg_type )
const noexcept
1351 return nullptr != m_subscriptions->find_handler(
1352 mbox->id(), msg_type, deadletter_state );
1358
1359
1360
1361
1362
1363
1364inline demand_handler_pfn_t
1367 const message_ref_t & msg )
1369 demand_handler_pfn_t result = &agent_t::demand_handler_on_message;
1372 switch( message_kind( *msg ) )
1380 case message_t::kind_t::enveloped_msg :
1381 result = &agent_t::demand_handler_on_enveloped_msg;
1388 log_stream <<
"message that has data and message_kind_t::signal!"
1389 "Signals can't have data. Application will be aborted!"
1406 const std::type_index & msg_type,
1407 const message_ref_t & message )
1414 m_event_queue->push(
1426 current_thread_id_t working_thread_id,
1432 d.m_receiver->m_working_thread_id,
1433 working_thread_id );
1439 catch(
const std::exception & x )
1441 impl::process_unhandled_exception(
1442 working_thread_id, x, *(d.m_receiver) );
1446 impl::process_unhandled_unknown_exception(
1447 working_thread_id, *(d.m_receiver) );
1457 std::lock_guard< std::mutex > binding_lock{ m_agent_coop->m_lock };
1463 return &agent_t::demand_handler_on_start;
1468 current_thread_id_t working_thread_id,
1475 d.m_receiver->m_working_thread_id,
1476 working_thread_id );
1482 catch(
const std::exception & x )
1484 impl::process_unhandled_exception(
1485 working_thread_id, x, *(d.m_receiver) );
1489 impl::process_unhandled_unknown_exception(
1490 working_thread_id, *(d.m_receiver) );
1505 return &agent_t::demand_handler_on_finish;
1510 current_thread_id_t working_thread_id,
1516 d
, "demand_handler_on_message" );
1521 handler->m_thread_safety,
1522 handler->m_method );
1528 return &agent_t::demand_handler_on_message;
1533 current_thread_id_t working_thread_id,
1539 d
, "demand_handler_on_enveloped_msg" );
1540 process_enveloped_msg( working_thread_id, d, handler );
1546 return &agent_t::demand_handler_on_enveloped_msg;
1551 current_thread_id_t working_thread_id,
1554 event_handler_method_t method )
1565 d.m_receiver->m_working_thread_id,
1569 so_5::thread_safe == thread_safety
1570 ? null_current_thread_id()
1576 method( d.m_message_ref );
1578 catch(
const std::exception & x )
1580 impl::process_unhandled_exception(
1581 working_thread_id, x, *(d.m_receiver) );
1585 impl::process_unhandled_unknown_exception(
1586 working_thread_id, *(d.m_receiver) );
1592 current_thread_id_t working_thread_id,
1617 handler_data->m_thread_safety,
1618 handler_data->m_method );
1625 auto & envelope = message_to_envelope( d.m_message_ref );
1631 envelope.access_hook(
1632 so_5::enveloped_msg::access_context_t::handler_found,
1640 const char * operation_name )
const
1642 if( so_5::query_current_thread_id() != m_working_thread_id )
1644 std::ostringstream s;
1647 <<
": operation is enabled only on agent's working thread; "
1648 <<
"working_thread_id: ";
1650 if( m_working_thread_id == null_current_thread_id() )
1653 s << m_working_thread_id;
1655 s <<
", current_thread_id: " << so_5::query_current_thread_id();
1658 so_5::rc_operation_enabled_only_on_agent_working_thread,
1666 if( m_delivery_filters )
1668 m_delivery_filters->drop_all();
1669 m_delivery_filters.reset();
1675 const mbox_t & mbox,
1676 const std::type_index & msg_type,
1677 delivery_filter_unique_ptr_t filter )
1682 if( is_agent_deactivated() )
1684 so_5::rc_agent_deactivated,
1685 "new delivery filter can't be set for deactivated agent" );
1689 auto & target_sink = detect_sink_for_message_type( msg_type );
1691 if( !m_delivery_filters )
1692 m_delivery_filters.reset(
new impl::delivery_filter_storage_t() );
1694 m_delivery_filters->set_delivery_filter(
1698 outliving_mutable( target_sink ) );
1703 const mbox_t & mbox,
1704 const std::type_index & msg_type )
noexcept
1708 if( m_delivery_filters )
1709 m_delivery_filters->drop_delivery_filter( mbox, msg_type );
1718 if( !search_result )
1722 return search_result;
1728 const char * context_marker )
1732 if( !search_result )
1745 return search_result;
1756 return search_result;
1767 search_result = d
.m_receiver->m_subscriptions->find_handler(
1772 if( !search_result )
1775 }
while( search_result ==
nullptr && s !=
nullptr );
1777 return search_result;
1784 return demand
.m_receiver->m_subscriptions->find_handler(
1792 const state_t & state_to_be_set )
1800 rc_agent_deactivated,
1801 "unable to switch agent to another state because the "
1802 "agent is already deactivated" );
1819 m_state_listener_controller.changed(
1821 *m_current_state_ptr );
1826 rc_agent_unknown_state,
1827 "unable to switch agent to alien state "
1828 "(the state that doesn't belong to this agent)" );
1833 const state_t & state_to_be_set )
noexcept
1835 state_t::path_t old_path;
1836 state_t::path_t new_path;
1842 current_st->fill_path( old_path );
1843 state_to_be_set.fill_path( new_path );
1846 std::size_t first_diff = 0;
1847 for(; first_diff < std::min(
1848 current_st->nested_level(),
1849 state_to_be_set.nested_level() );
1851 if( old_path[ first_diff ] != new_path[ first_diff ] )
1859 *
this, *current_st
);
1861 for( std::size_t i = current_st->nested_level();
1865 m_current_state_ptr = old_path[ i ];
1867 old_path[ i ]->call_on_exit();
1875 *
this, state_to_be_set
);
1877 for( std::size_t i = first_diff;
1878 i <= state_to_be_set.nested_level();
1882 m_current_state_ptr = new_path[ i ];
1885 new_path[ i ]->call_on_enter();
1897 if( !( st_default == so_current_state() ||
1898 is_agent_deactivated() ) )
1902 so_change_state( st_default );
1916 "state_t::time_limit" );
1922 if( !m_state_time_limit_handling_data.is_defined() )
1934 so_subscribe_deadletter_handler(
1936 &agent_t::evt_state_time_limit );
1939 m_state_time_limit_handling_data.make_defined(
1940 std::move(unique_mbox) );
1948 const auto now = state_t::time_limit_t::steady_clock::now();
1956 for(
const state_t * st : current_state_path )
1958 if( st->m_time_limit )
1960 if( st->m_time_limit->is_limit_exceeded( now ) )
1963 so_change_state( st->m_time_limit->state_to_switch() );
Interface for message sink.
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(const agent_t *pointer) noexcept
Initializing constructor for case when agent has no user specified name.
Interface of the agent state listener.
Type for holding information necessary for handling time limits for agent states.
~state_time_limit_handling_data_t()
bool is_defined() const noexcept
Is the data for handling time limits defined?
state_time_limit_handling_data_t()
mbox_t timeout_mbox() const noexcept
void make_defined(mbox_t timeout_mbox)
static demand_handler_pfn_t get_demand_handler_on_start_ptr() noexcept
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.
void evt_state_time_limit(mhood_t< so_5::details::msg_state_timeout >)
Special event handler to process state time limits.
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.
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.
@ shutdown_with_skipping_pending_demands
Agent was shutdown and all pending demands have to be skipped.
@ 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 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.
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.
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.
const demands_handling_on_dereg_t m_demands_handling_on_dereg
What to do with pending demands on deregistration.
void so_drop_all_subscriptions_and_filters()
Dropping all agents subscriptions and filters.
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 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.
const mbox_t & so_direct_mbox() const
Get the agent's direct mbox.
void so_destroy_deadletter_subscription(const mbox_t &mbox, const std::type_index &msg_type)
Destroy a subscription for a deadletter handler.
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.
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.
void define_state_time_limit_handling_data_if_needed()
Initialize data for handling time limit of agent's states.
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.
A collector for agent tuning options.
so_5::priority_t query_priority() const noexcept
Get priority value.
bool is_user_provided_subscription_storage_factory() const noexcept
Does a user provide a specific subscription_storage_factory?
demands_handling_on_dereg_t demands_handling_on_dereg() const noexcept
Type of smart handle for a cooperation.
exception_reaction_t exception_reaction() const noexcept
Get the current exception rection flag for that cooperation.
coop_handle_t handle() noexcept
Get handle for this coop.
An implementation of handler_invoker interface.
void deregister_coop(coop_handle_t coop, int reason) noexcept
Deregister the cooperation.
An interface of event queue for agent.
A hint for a dispatcher for execution of event for the concrete execution_demand.
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
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.
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.
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.
agent_t::agent_status_t m_previous_status
state_switch_guard_t(agent_t &agent)
A base class for agent messages.
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
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.
Scoped guard for shared locks.
Helper class for simplify iteration on state's path.
state_path_t(const state_t &state) noexcept
Initializing constructor.
Information of time_limit for a state.
void change(duration_t limit, const state_t &state_to_switch) noexcept
const state_t & state_to_switch() const noexcept
void on_state_activation(const agent_t::state_time_limit_handling_data_t &info) noexcept
bool is_limit_exceeded(const steady_clock::time_point current_time) const noexcept
std::optional< activation_data_t > m_activation_data
std::reference_wrapper< const state_t > m_state_to_switch
The target state to switch after the timeout.
void activate(const agent_t::state_time_limit_handling_data_t &info)
time_limit_t(duration_t limit, const state_t &state_to_switch) noexcept
Initializing constructor.
void on_state_deactivation() noexcept
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.
std::enable_if< details::is_agent_method_pointer< details::method_arity::nullary, Method_Pointer >::value, state_t & >::type on_enter(Method_Pointer pfn)
Set on enter handler.
state_t & drop_time_limit()
Drop time limit for the state if defined.
history_t m_state_history
Type of state history.
const state_t * parent_state() const noexcept
Get a parent state if exists.
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.
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 initializing constructor.
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)
bool operator!=(const state_t &state) const noexcept
agent_t *const m_target_agent
Owner of this state.
std::string query_name() const
Get textual name of the state.
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.
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.
An indentificator for the timer.
#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.
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.
All stuff related to message limits.
Private part of message limit implementation.
exception_reaction_t
A reaction of SObjectizer to an exception from agent event.
@ abort_on_exception
Execution of application must be aborted immediatelly.
demands_handling_on_dereg_t
How pending demands should be handled on deregistration.
@ skip
Pending demands have to be skipped.
const thread_safety_t not_thread_safe
Shorthand for thread unsafety indicator.
const thread_safety_t thread_safe
Shorthand for thread safety indicator.
thread_safety_t
Thread safety indicator.
@ user_type_message
Message is an user type message.
SO_5_FUNC void swap(name_for_agent_t &a, name_for_agent_t &b) noexcept
event_handler_kind_t
Kind of an event handler.
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.
A description of event execution demand.
mbox_id_t m_mbox_id
ID of mbox.
agent_t * m_receiver
Receiver of demand.
const message_limit::control_block_t * m_limit
Optional message limit for that message.
A helper class for temporary setting and then dropping the ID of the current working thread.
Information about event_handler and its properties.
thread_safety_t m_thread_safety
Is event handler thread safe or not.
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 void decrement(const control_block_t *limit)
activation_data_t(timer_id_t timer, steady_clock::time_point expiration_point)
steady_clock::time_point m_expiration_point
Timeout of timeout expiration.
timer_id_t m_timer
ID of delayed timeout signal.
Helper for marking a substate of composite state.