SObjectizer  5.8
Loading...
Searching...
No Matches
mbox_core.cpp
Go to the documentation of this file.
1/*
2 SObjectizer 5.
3*/
4
5#include <so_5/impl/mbox_core.hpp>
6
7#include <so_5/exception.hpp>
8
9#include <so_5/impl/local_mbox.hpp>
10#include <so_5/impl/named_local_mbox.hpp>
11#include <so_5/impl/mpsc_mbox.hpp>
12#include <so_5/impl/mchain_details.hpp>
13#include <so_5/impl/make_mchain.hpp>
14
15#include <algorithm>
16
17namespace so_5
18{
19
20namespace impl
21{
22
23//
24// mbox_core_t
25//
26
27mbox_core_t::mbox_core_t(
28 outliving_reference_t< so_5::msg_tracing::holder_t > msg_tracing_stuff )
31{
32}
33
34mbox_t
35mbox_core_t::create_mbox(
36 environment_t & env )
37{
38 auto id = ++m_mbox_id_counter;
39 if( !m_msg_tracing_stuff.get().is_msg_tracing_enabled() )
40 return mbox_t{ new local_mbox_without_tracing{ id, env } };
41 else
42 return mbox_t{ new local_mbox_with_tracing{ id, env, m_msg_tracing_stuff } };
43}
44
45mbox_t
46mbox_core_t::create_mbox(
47 environment_t & env,
48 nonempty_name_t mbox_name )
49{
50 mbox_t result; // Will be created later,
51
53 default_global_mbox_namespace(),
54 mbox_name.giveout_value()
55 };
56 // NOTE: mbox_name can't be used anymore!
57
58 std::lock_guard< std::mutex > lock( m_dictionary_lock );
59
60 named_mboxes_dictionary_t::iterator it =
61 m_named_mboxes_dictionary.find( key );
62
63 if( m_named_mboxes_dictionary.end() != it )
64 {
65 // For strong exception safety create a new instance
66 // of named_local_mbox first...
67 result = mbox_t{
68 new named_local_mbox_t( key, it->second.m_mbox, *this )
69 };
70
71 // ... now the count of references can be incremented safely
72 // (exceptions is no more expected).
73 ++(it->second.m_external_ref_count);
74 }
75 else
76 {
77 // There is no mbox with such name. New mbox should be created.
78 // NOTE: it's safe to call create_mbox(env) when mbox_core is
79 // locked because create_mbox(env) doesn't to lock the mbox_core.
80 mbox_t mbox_ref = create_mbox( env );
81
82 // For strong exception safety create a new instance
83 // of named_local_mbox first...
84 result = mbox_t{
85 new named_local_mbox_t( key, mbox_ref, *this )
86 };
87
88 // ...now we can update the dictionary. If there will be an exception
89 // then all new object will be destroyed automatically.
90 m_named_mboxes_dictionary.emplace(
91 key,
92 named_mbox_info_t( mbox_ref ) );
93 }
94
95 return result;
96}
97
98namespace {
99
100template< typename M1, typename M2, typename... A >
104 A &&... args )
105 {
106 std::unique_ptr< abstract_message_box_t > result;
107
108 if( !msg_tracing_stuff.get().is_msg_tracing_enabled() )
109 result.reset( new M1{ std::forward<A>(args)... } );
110 else
111 result.reset(
112 new M2{ std::forward<A>(args)..., msg_tracing_stuff } );
113
114 return result;
115 }
116
117} /* namespace anonymous */
118
119mbox_t
121 environment_t & env,
122 agent_t & owner )
123{
124 const auto id = ++m_mbox_id_counter;
125
126 std::unique_ptr< abstract_message_box_t > actual_mbox =
127 make_actual_mbox<
128 ordinary_mpsc_mbox_without_tracing_t,
129 ordinary_mpsc_mbox_with_tracing_t >(
130 m_msg_tracing_stuff,
131 id,
132 env,
133 outliving_mutable( owner ) );
134
135 return mbox_t{ actual_mbox.release() };
136}
137
138mbox_t
140 environment_t & env,
141 agent_t & owner )
142{
143 const auto id = ++m_mbox_id_counter;
144
145 std::unique_ptr< abstract_message_box_t > actual_mbox =
146 make_actual_mbox<
147 limitless_mpsc_mbox_without_tracing_t,
148 limitless_mpsc_mbox_with_tracing_t >(
149 m_msg_tracing_stuff,
150 id,
151 env,
152 outliving_mutable( owner ) );
153
154 return mbox_t{ actual_mbox.release() };
155}
156
157void
158mbox_core_t::destroy_mbox(
159 const full_named_mbox_id_t & name ) noexcept
160{
161 std::lock_guard< std::mutex > lock( m_dictionary_lock );
162
163 named_mboxes_dictionary_t::iterator it =
164 m_named_mboxes_dictionary.find( name );
165
166 if( m_named_mboxes_dictionary.end() != it )
167 {
168 const unsigned int ref_count = --(it->second.m_external_ref_count);
169 if( 0 == ref_count )
170 m_named_mboxes_dictionary.erase( it );
171 }
172}
173
174mbox_t
176 environment_t & env,
178{
179 const auto id = ++m_mbox_id_counter;
180 return creator.create(
181 mbox_creation_data_t{
182 outliving_mutable(env),
183 id,
184 m_msg_tracing_stuff
185 } );
186}
187
188mbox_t
190 mbox_namespace_name_t mbox_namespace,
191 nonempty_name_t mbox_name,
192 const std::function< mbox_t() > & mbox_factory )
193{
194 mbox_t result;
195
197 std::string{ mbox_namespace.query_name() },
198 mbox_name.giveout_value()
199 };
200 // NOTE: mbox_name can't be used anymore!
201
202 // Step 1. Check the presense of this mbox.
203 // It's important to do that step on locked object.
204 {
205 std::lock_guard< std::mutex > lock( m_dictionary_lock );
206
207 named_mboxes_dictionary_t::iterator it =
208 m_named_mboxes_dictionary.find( key );
209
210 if( m_named_mboxes_dictionary.end() != it )
211 {
212 // For strong exception safety create a new instance
213 // of named_local_mbox first...
214 result = mbox_t{
215 new named_local_mbox_t( key, it->second.m_mbox, *this )
216 };
217
218 // ... now the count of references can be incremented safely
219 // (exceptions is no more expected).
220 ++(it->second.m_external_ref_count);
221 }
222 }
223
224 if( !result )
225 {
226 // Step 2. Create a new instance on mbox.
227 // It's important to call mbox_factory when mbox_core isn't locked.
228 auto fresh_mbox = mbox_factory();
229 if( !fresh_mbox )
231 rc_nullptr_as_result_of_user_mbox_factory,
232 "user-provided mbox_factory returns nullptr" );
233
234 // Step 3. Try to register the fresh_mbox.
235 // It has to be done on locked object.
236 {
237 std::lock_guard< std::mutex > lock( m_dictionary_lock );
238
239 // Another search. This is necessary because the name may have been
240 // created while mbox_factory() was running.
241 named_mboxes_dictionary_t::iterator it =
242 m_named_mboxes_dictionary.find( key );
243
244 if( m_named_mboxes_dictionary.end() != it )
245 {
246 // Yes, the name has been created while we were inside
247 // mbox_factory() call. The fresh_mbox has to be discarded.
248 //
249 // For strong exception safety create a new instance
250 // of named_local_mbox first...
251 result = mbox_t{
252 new named_local_mbox_t( key, it->second.m_mbox, *this )
253 };
254
255 // ... now the count of references can be incremented safely
256 // (exceptions is no more expected).
257 ++(it->second.m_external_ref_count);
258 }
259 else
260 {
261 // For strong exception safety create a new instance
262 // of named_local_mbox first...
263 result = mbox_t{
264 new named_local_mbox_t( key, fresh_mbox, *this )
265 };
266
267 // ...now we can update the dictionary. If there will be an
268 // exception then all new object will be destroyed automatically.
269 m_named_mboxes_dictionary.emplace(
270 key,
271 named_mbox_info_t( fresh_mbox ) );
272 }
273 }
274 }
275
276 return result;
277}
278
279mchain_t
280mbox_core_t::create_mchain(
281 environment_t & env,
282 const mchain_params_t & params )
283{
284 using namespace so_5::mchain_props;
285 using namespace so_5::mchain_props::details;
286
287 auto id = ++m_mbox_id_counter;
288
289 if( params.capacity().unlimited() )
290 return make_mchain< unlimited_demand_queue >(
291 m_msg_tracing_stuff, params, env, id );
292 else if( memory_usage_t::dynamic == params.capacity().memory_usage() )
293 return make_mchain< limited_dynamic_demand_queue >(
294 m_msg_tracing_stuff, params, env, id );
295 else
296 return make_mchain< limited_preallocated_demand_queue >(
297 m_msg_tracing_stuff, params, env, id );
298}
299
301mbox_core_t::query_stats()
302{
303 std::lock_guard< std::mutex > lock{ m_dictionary_lock };
304
305 return mbox_core_stats_t{ m_named_mboxes_dictionary.size() };
306}
307
308[[nodiscard]] mbox_id_t
309mbox_core_t::allocate_mbox_id() noexcept
310{
311 return ++m_mbox_id_counter;
312}
313
314} /* namespace impl */
315
316} /* namespace so_5 */
A base class for agents.
Definition agent.hpp:673
Interface for creator of new mbox in OOP style.
SObjectizer Environment.
mbox_t create_ordinary_mpsc_mbox(environment_t &env, agent_t &owner)
Create mpsc_mbox that handles message limits.
mbox_t create_limitless_mpsc_mbox(environment_t &env, agent_t &owner)
Create mpsc_mbox that ignores message limits.
mbox_t introduce_named_mbox(mbox_namespace_name_t mbox_namespace, nonempty_name_t mbox_name, const std::function< mbox_t() > &mbox_factory)
Introduce named mbox with user-provided factory.
mbox_core_t(outliving_reference_t< so_5::msg_tracing::holder_t > msg_tracing_stuff)
Definition mbox_core.cpp:27
mbox_t create_custom_mbox(environment_t &env, ::so_5::custom_mbox_details::creator_iface_t &creator)
Create a custom mbox.
void destroy_mbox(const full_named_mbox_id_t &name) noexcept
Remove a reference to the named mbox.
mchain_t create_mchain(environment_t &env, const mchain_params_t &params)
Create message chain.
mbox_t create_mbox(environment_t &env)
Create local anonymous mbox.
Definition mbox_core.cpp:35
mbox_t create_mbox(environment_t &env, nonempty_name_t mbox_name)
Create local named mbox.
Definition mbox_core.cpp:46
mbox_id_t allocate_mbox_id() noexcept
Allocate an ID for a new custom mbox or mchain.
mbox_core_stats_t query_stats()
Get statistics for run-time monitoring.
A class for the name of mbox_namespace.
Parameters for message chain.
Definition mchain.hpp:741
Interface of holder of message tracer and message trace filter objects.
A class for the name which cannot be empty.
Helper class for indication of long-lived reference via its type.
Definition outliving.hpp:98
#define SO_5_THROW_EXCEPTION(error_code, desc)
Definition exception.hpp:74
std::unique_ptr< abstract_message_box_t > make_actual_mbox(outliving_reference_t< so_5::msg_tracing::holder_t > msg_tracing_stuff, A &&... args)
Details of SObjectizer run-time implementations.
Definition agent.cpp:905
Implementation details.
Definition mchain.hpp:37
Various properties and parameters of message chains.
Definition mchain.hpp:28
Public part of message delivery tracing mechanism.
Private part of message limit implementation.
Definition agent.cpp:33
Full name for a named mbox.
Definition mbox_core.hpp:69
Statistics from mbox_core for run-time monitoring.
Definition mbox_core.hpp:49