1 /*
2 * SObjectizer-5
3 */
4
5 /*!
6 * \since
7 * v.5.4.0
8 *
9 * \file
10 * \brief Helpers for handling unhandled exceptions from agent's event handlers.
11 */
12
13 #include <so_5/impl/process_unhandled_exception.hpp>
14
15 #include <so_5/environment.hpp>
16
17 #include <so_5/details/abort_on_fatal_error.hpp>
18 #include <so_5/details/suppress_exceptions.hpp>
19
20 namespace so_5 {
21
22 namespace impl {
23
24 namespace {
25
26 /*!
27 * \since
28 * v.5.4.0
29 *
30 * \brief Switch agent to special state and deregister its cooperation.
31 *
32 * Calls abort() if an exception is raised during work.
33 */
34 void
switch_agent_to_special_state_and_deregister_coop(so_5::agent_t & a_exception_producer)35 switch_agent_to_special_state_and_deregister_coop(
36 //! Agent who is the producer of the exception.
37 so_5::agent_t & a_exception_producer ) noexcept
38 {
39 const coop_handle_t coop = a_exception_producer.so_coop();
40 try
41 {
42 a_exception_producer.so_switch_to_awaiting_deregistration_state();
43 a_exception_producer.so_environment().deregister_coop(
44 coop,
45 so_5::dereg_reason::unhandled_exception );
46 }
47 catch( const std::exception & x )
48 {
49 so_5::details::abort_on_fatal_error( [&] {
50 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
51 {
52 log_stream << "An exception '" << x.what()
53 << "' during deregistring cooperation "
54 << coop << " on unhandled exception"
55 "processing. Application will be aborted.";
56 }
57 } );
58 }
59 }
60
61 /*!
62 * \since
63 * v.5.4.0
64 *
65 * \brief Switch agent to special state and initiate stopping
66 * of SObjectizer Environment.
67 *
68 * Calls abort() if an exception is raised during work.
69 */
70 void
switch_agent_to_special_state_and_shutdown_sobjectizer(agent_t & a_exception_producer)71 switch_agent_to_special_state_and_shutdown_sobjectizer(
72 //! Agent who is the producer of the exception.
73 agent_t & a_exception_producer ) noexcept
74 {
75 try
76 {
77 a_exception_producer.so_switch_to_awaiting_deregistration_state();
78 a_exception_producer.so_environment().stop();
79 }
80 catch( const std::exception & x )
81 {
82 so_5::details::abort_on_fatal_error( [&] {
83 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
84 {
85 log_stream << "An exception '" << x.what()
86 << "' during shutting down SObjectizer on unhandled "
87 "exception processing. Application will be aborted.";
88 }
89 } );
90 }
91 }
92
93 /*!
94 * \since
95 * v.5.4.0
96 *
97 * \brief Log unhandled exception from cooperation.
98 *
99 * \note
100 * This function is noexcept since v.5.6.0.
101 */
102 void
log_unhandled_exception(const std::exception & ex_to_log,agent_t & a_exception_producer)103 log_unhandled_exception(
104 //! Raised and caught exception.
105 const std::exception & ex_to_log,
106 //! Agent who is the producer of the exception.
107 agent_t & a_exception_producer ) noexcept
108 {
109 a_exception_producer.so_environment().call_exception_logger(
110 ex_to_log,
111 a_exception_producer.so_coop() );
112 }
113
114 } /* namespace anonymous */
115
116 //
117 // process_unhandled_exception
118 //
119 void
process_unhandled_exception(current_thread_id_t working_thread_id,const std::exception & ex,agent_t & a_exception_producer)120 process_unhandled_exception(
121 current_thread_id_t working_thread_id,
122 const std::exception & ex,
123 agent_t & a_exception_producer ) noexcept
124 {
125 log_unhandled_exception( ex, a_exception_producer );
126
127 auto reaction = a_exception_producer.so_exception_reaction();
128 if( working_thread_id == null_current_thread_id() &&
129 ignore_exception != reaction &&
130 abort_on_exception != reaction )
131 {
132 so_5::details::abort_on_fatal_error( [&] {
133 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
134 {
135 log_stream << "Illegal exception_reaction code "
136 "for the multithreadded agent: "
137 << static_cast< int >(reaction) << ". "
138 "The only allowed exception_reaction for "
139 "such kind of agents are ignore_exception or "
140 "abort_on_exception. "
141 "Application will be aborted. "
142 "Unhandled exception '" << ex.what()
143 << "' from cooperation "
144 << a_exception_producer.so_coop();
145 }
146 } );
147 }
148
149 if( abort_on_exception == reaction )
150 {
151 so_5::details::abort_on_fatal_error( [&] {
152 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
153 {
154 log_stream << "Application will be aborted due to unhandled "
155 "exception '" << ex.what() << "' from cooperation "
156 << a_exception_producer.so_coop();
157 }
158 } );
159 }
160 else if( shutdown_sobjectizer_on_exception == reaction )
161 {
162 // Since v.5.6.2 all logging-related exceptions are suppressed here.
163 so_5::details::suppress_exceptions( [&] {
164 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
165 {
166 log_stream << "SObjectizer will be shutted down due to "
167 "unhandled exception '" << ex.what()
168 << "' from cooperation "
169 << a_exception_producer.so_coop();
170 }
171 } );
172
173 switch_agent_to_special_state_and_shutdown_sobjectizer(
174 a_exception_producer );
175 }
176 else if( deregister_coop_on_exception == reaction )
177 {
178 // Since v.5.6.2 all logging-related exceptions are suppressed here.
179 so_5::details::suppress_exceptions( [&] {
180 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
181 {
182 log_stream << "Cooperation "
183 << a_exception_producer.so_coop()
184 << " will be deregistered due to unhandled exception '"
185 << ex.what() << "'";
186 }
187 } );
188
189 switch_agent_to_special_state_and_deregister_coop(
190 a_exception_producer );
191 }
192 else if( ignore_exception == reaction )
193 {
194 // Since v.5.6.2 all logging-related exceptions are suppressed here.
195 so_5::details::suppress_exceptions( [&] {
196 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
197 {
198 log_stream << "Ignore unhandled exception '"
199 << ex.what() << "' from cooperation "
200 << a_exception_producer.so_coop();
201 }
202 } );
203 }
204 else
205 {
206 so_5::details::abort_on_fatal_error( [&] {
207 SO_5_LOG_ERROR( a_exception_producer.so_environment(), log_stream )
208 {
209 log_stream << "Unknown exception_reaction code: "
210 << static_cast< int >(reaction)
211 << ". Application will be aborted. Unhandled exception '"
212 << ex.what() << "' from cooperation "
213 << a_exception_producer.so_coop();
214 }
215 } );
216 }
217 }
218
219 void
process_unhandled_unknown_exception(current_thread_id_t working_thread_id,agent_t & a_exception_producer)220 process_unhandled_unknown_exception(
221 current_thread_id_t working_thread_id,
222 agent_t & a_exception_producer ) noexcept
223 {
224 // Just call process_unhandled_exception with dummy exception object.
225 exception_t dummy{
226 "an exception of unknown type is caught",
227 rc_unknown_exception_type
228 };
229
230 process_unhandled_exception(
231 working_thread_id,
232 dummy,
233 a_exception_producer );
234 }
235
236 } /* namespace impl */
237
238 } /* namespace so_5 */
239
240