SObjectizer  5.8
Loading...
Searching...
No Matches
coop_repository_basis.cpp
Go to the documentation of this file.
1/*
2 SObjectizer 5.
3*/
4
5/*!
6 * \file
7 * \brief Basic part of coop_repository functionality.
8 *
9 * \since
10 * v.5.5.19
11 */
12#include <so_5/impl/coop_repository_basis.hpp>
13
14#include <so_5/environment.hpp>
15
16#include <so_5/details/rollback_on_exception.hpp>
17
18#include <cstdlib>
19#include <algorithm>
20
21namespace so_5
22{
23
24namespace impl
25{
26
27//
28// root_coop_t
29//
30/*!
31 * \brief A type of special coop that will be used as the root coop.
32 *
33 * \since
34 * v.5.6.0
35 */
36class coop_repository_basis_t::root_coop_t final : public coop_t
37 {
38 public :
40 coop_id_t id,
42 : coop_t{ id,
43 coop_handle_t{}, // No parent coop.
44 disp_binder_shptr_t{}, // No binder.
45 env }
46 {
47 // Automaticaly increment usage count to prevent
48 // deregistration when last child coop will be destroyed.
50
51 // Status of the coop should be changed because
52 // this coop is already "registered".
54 }
55
56 void
58 {
59 // List of children coop should be processed when
60 // the object is locked.
61 std::lock_guard< std::mutex > lock{ m_lock };
62
63 // Every child should be deregistered with 'shutdown' reason.
64 for_each_child( []( coop_t & child ) {
66 } );
67 }
68 };
69
72 coop_listener_unique_ptr_t coop_listener )
75 {
76 m_root_coop = std::make_shared< root_coop_t >(
77 ++m_coop_id_counter,
78 m_env );
79 }
80
81[[nodiscard]]
84 coop_handle_t parent,
85 disp_binder_shptr_t default_binder )
86 {
87 if( !parent )
88 parent = m_root_coop->handle();
89
90 return coop_private_iface_t::make_coop(
91 ++m_coop_id_counter,
92 std::move(parent),
93 std::move(default_binder),
94 m_env );
95 }
96
97[[nodiscard]]
100 coop_unique_holder_t coop_ptr )
101 {
102 // Phase 1: check the posibility of registration of new coop.
103 // This check should be performed on locked object.
104 {
105 std::lock_guard< std::mutex > lock{ m_lock };
106 if( status_t::normal != m_status )
108 rc_unable_to_register_coop_during_shutdown,
109 "a new coop can't be registered when shutdown "
110 "is in progress" );
111
112 // A counter of registration in progress should be incremented
113 // to prevent shutdown.
114 ++m_registrations_in_progress;
115 }
116
117 // Note: this code should be called only on locked object.
118 const auto handle_registrations_in_progress = [this]() noexcept {
119 // Decrement count of registration in progress to enable
120 // pending shutdown (if it is).
121 --m_registrations_in_progress;
122
123 // If it was the last registration and there is a pending
124 // shutdown then we should enable shutdown procedure.
125 if( 0u == m_registrations_in_progress &&
126 status_t::pending_shutdown == m_status )
127 {
128 m_shutdown_enabled_cond.notify_one();
129 }
130 };
131
132 // Phase 2: registration by itself.
133 coop_handle_t result;
134 try
135 {
136 // This values is necessary for updating stats if registration
137 // will be successful.
138 const auto coop_size = coop_ptr->size();
139
140 // Should be performed on unlocked object.
141 result = do_registration_specific_actions( std::move(coop_ptr) );
142
143 // Phase 3: finishing of registration.
144 // Those actions should be performed on locked objects.
145 details::invoke_noexcept_code( [&] {
146 std::lock_guard< std::mutex > lock{ m_lock };
147
148 // Statistics should be updated.
149 m_total_agents += coop_size;
150 m_total_coops += 1;
151
152 handle_registrations_in_progress();
153 } );
154 }
155 catch( ... )
156 {
157 // Pending shutdown should be handled even in the presence
158 // of an exception.
159 details::invoke_noexcept_code( [&] {
160 std::lock_guard< std::mutex > lock{ m_lock };
161
162 handle_registrations_in_progress();
163 } );
164
165 // Exception should be handled at some higher level.
166 throw;
167 }
168
169 return result;
170 }
171
174 coop_shptr_t coop ) noexcept
175 {
176 // Count of live agent and coops should be decremented.
177 {
178 std::lock_guard< std::mutex > lock{ m_lock };
179
180 m_total_agents -= coop->size();
181 --m_total_coops;
182 }
183
184 // Coop should perform its final actions.
185 coop_private_iface_t::do_final_deregistration_actions( *coop );
186
187 // Now the coop object should be released.
188 // But before that we should store some values from it
189 // to process dereg notifications.
190 const auto handle = coop->handle();
191 const auto dereg_reason =
192 coop_private_iface_t::dereg_reason( *coop );
193 const auto dereg_notificators =
194 coop_private_iface_t::giveout_dereg_notificators( *coop );
195
196 // Release the coop.
197 coop.reset();
198
199 // Coop's dereg notificators can be processed now.
200 if( dereg_notificators )
201 dereg_notificators->call_all(
202 m_env.get(),
203 handle,
204 dereg_reason );
205
206 // Coop's listener should be notified.
207 if( m_coop_listener )
208 m_coop_listener->on_deregistered(
209 m_env.get(),
210 handle,
211 dereg_reason );
212
213 // This additional lock is necessary because a new coop
214 // can be registered while final deregistration actions
215 // were in progress.
216 return [this] {
217 std::lock_guard< std::mutex > lock{ m_lock };
218
219 return final_deregistration_result_t{
220 // Coops those are in registration phase should also
221 // be counted as live.
222 0u != m_total_coops || 0 != m_registrations_in_progress,
223 status_t::shutdown == m_status && 0u == m_total_coops
224 };
225 }();
226 }
227
228void
230 {
231 // Phase 1: check that shutdown is not in progress now.
232 {
233 std::unique_lock< std::mutex > lock{ m_lock };
234
235 if( !m_registrations_in_progress )
236 {
238 // NOTE: there is no need to wait on m_shutdown_enabled_cond
239 // because there is no active registration procedures.
240 }
241 else
242 {
243 // There are active registration procedures.
244 // We should wait for their completion.
246 m_shutdown_enabled_cond.wait( lock,
247 [this] { return 0 == m_registrations_in_progress; } );
249 }
250 }
251
252 // Phase 2: deregistration of all coops.
253 m_root_coop->deregister_children_on_shutdown();
254 }
255
256[[nodiscard]]
259 {
260 std::lock_guard< std::mutex > lock{ m_lock };
261
263 {
266 }
267 else
269 }
270
273 {
274 return m_env.get();
275 }
276
279 {
280 std::lock_guard< std::mutex > lock{ m_lock };
281
282 return {
283 m_total_coops,
284 m_total_agents,
285 0u
286 };
287 }
288
289namespace
290{
291 /*!
292 * \since
293 * v.5.2.3
294 *
295 * \brief Special guard to increment and decrement cooperation
296 * usage counters.
297 */
314
315} /* namespace anonymous */
316
319 coop_unique_holder_t coop_ptr )
320{
321 // Cooperation object should life to the end of this routine.
322 coop_shptr_t coop{ coop_private_iface_t::make_from( std::move(coop_ptr) ) };
323
324 // This guard will guarantee, that reg_notificators for
325 // successfully registered coop will be called and completed before
326 // the dereg_notificators for that coop.
327 // Even if the coop will be deregitered while reg_notificators are
328 // still working.
329 coop_usage_counter_guard_t guard{ *coop };
330
331 coop_private_iface_t::do_registration_specific_actions( *coop );
332
333 auto result = coop->handle();
334
335 // We don't expect exceptions from the following actions.
336 so_5::details::invoke_noexcept_code( [&] {
337 // Coop's dereg notificators can be processed now.
338 auto reg_notificators =
339 coop_private_iface_t::giveout_reg_notificators( *coop );
340 if( reg_notificators )
341 reg_notificators->call_all( m_env.get(), result );
342
343 // Coop's listener should be notified.
344 if( m_coop_listener )
345 m_coop_listener->on_registered( m_env.get(), result );
346 } );
347
348 return result;
349}
350
351} /* namespace impl */
352
353} /* namespace so_5 */
Type of smart handle for a cooperation.
Agent cooperation.
Definition coop.hpp:389
registration_status_t m_registration_status
The registration status of cooperation.
Definition coop.hpp:1092
void deregister(int reason) noexcept
Deregister the cooperation with the specified reason.
Definition coop.hpp:907
registration_status_t
Registration status.
Definition coop.hpp:956
@ coop_registered
Cooperation is registered.
A special type that plays role of unique_ptr for coop.
Definition coop.hpp:1342
An interface for environment_infrastructure entity.
SObjectizer Environment.
Special guard to increment and decrement cooperation usage counters.
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
root_coop_t(coop_id_t id, outliving_reference_t< environment_t > env)
A basic part for various implementations of coop_repository.
environment_t & environment()
Access to SObjectizer Environment.
coop_unique_holder_t make_coop(coop_handle_t parent, disp_binder_shptr_t default_binder)
Create an instance of a new coop.
void deregister_all_coop() noexcept
Deregisted all cooperations.
coop_repository_basis_t(outliving_reference_t< environment_t > environment, coop_listener_unique_ptr_t coop_listener)
final_deregistration_result_t final_deregister_coop(coop_shptr_t coop) noexcept
Do final actions of the cooperation deregistration.
try_switch_to_shutdown_result_t
Result of attempt to switch to shutdown state.
coop_handle_t do_registration_specific_actions(coop_unique_holder_t coop_ptr)
An actual implementation of registration of a coop.
environment_infrastructure_t::coop_repository_stats_t query_stats()
Get the current statistic for run-time monitoring.
status_t
Enumeration of possible repository statuses.
try_switch_to_shutdown_result_t try_switch_to_shutdown() noexcept
Try to switch repository to shutdown state.
coop_handle_t register_coop(coop_unique_holder_t agent_coop)
Register cooperation.
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
Enumeration of cooperation deregistration reasons.
Definition coop.hpp:39
const int shutdown
Deregistration because SObjectizer Environment shutdown.
Definition coop.hpp:49
Some reusable and low-level classes/functions which can be used in public header files.
Details of SObjectizer run-time implementations.
Definition agent.cpp:905
Private part of message limit implementation.
Definition agent.cpp:33
Statistical data for run-time monitoring of coop repository content.