Merge lp:~alan-griffiths/mir/fatal-error into lp:mir
- fatal-error
- Merge into development-branch
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | kevin gunn | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 1822 | ||||
Proposed branch: | lp:~alan-griffiths/mir/fatal-error | ||||
Merge into: | lp:mir | ||||
Diff against target: |
527 lines (+292/-39) 10 files modified
include/platform/mir/fatal.h (+76/-0) src/platform/CMakeLists.txt (+2/-0) src/platform/fatal/CMakeLists.txt (+3/-0) src/platform/fatal/fatal.cpp (+58/-0) src/platform/graphics/mesa/CMakeLists.txt (+1/-2) src/platform/graphics/mesa/display_buffer.cpp (+9/-8) src/platform/graphics/mesa/real_kms_output.cpp (+18/-29) tests/acceptance-tests/test_server_shutdown.cpp (+65/-0) tests/unit-tests/CMakeLists.txt (+1/-0) tests/unit-tests/test_fatal.cpp (+59/-0) |
||||
To merge this branch: | bzr merge lp:~alan-griffiths/mir/fatal-error | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Daniel van Vugt | Disapprove | ||
Robert Carr (community) | Approve | ||
Cemil Azizoglu (community) | Approve | ||
Kevin DuBois (community) | Approve | ||
Alexandros Frantzis (community) | Approve | ||
Review via email: mp+229086@code.launchpad.net |
Commit message
platform: provide support for customizing Mir's behavior when a fatal_error occurs.
Description of the change
platform: provide support for customizing Mir's behavior when a fatal_error occurs.
PS Jenkins bot (ps-jenkins) wrote : | # |
Alexandros Frantzis (afrantzis) wrote : | # |
Looks good.
Daniel van Vugt (vanvugt) wrote : | # |
(1) Author info for a few files is incorrect:
Author: Alan Griffiths <email address hidden>
Actually it was mostly copied from my branch, so please document as appropriate.
(2) The default action must be abort, not exceptions:
67 +void (*mir::
This is so that we can declare bug LP: #1316867 fixed and more importantly so that shell developers don't (by inaction) accidentally regress on it, preventing the creation of usable bug-reports. Catchable exceptions on unrecoverable errors must be an option at most, and never the default. Also keep in mind that we have upstart monitoring unity8 so it will restart cleanly either way. But only abort() gives you the extra bonus of usable bug-reports.
If abort() is not the default and not going to be always-on in usc and unity8 then there's no point in the proposal at all. It only gives you clean bug reports in debug builds and not in production (?!).
The good news is I have an alternative exceptions approach in mind that should make everyone happy. I'll prototype it when more important tasks are out the way.
Daniel van Vugt (vanvugt) wrote : | # |
P.S. The new approach I have in mind is to remove all the blanket catch() statements and ensure we only catch things in Mir that we have logic to recover from. Everything else that is unrecoverable should pass straight through as an uncaught exception (with cleaner stack and usable bug reports in theory). This idea will work so long as the shell itself is not insane enough to catch exceptions it doesn't know how to handle properly.
Alan Griffiths (alan-griffiths) wrote : | # |
2) For all the reasons stated at great length on your previous proposal abort should *not* be the default action and must be /explicitly requested/ by users of the library.
1) As you wrote less than half the code in those two files; and you disagree with the rest of the team on on (2) I assumed you'd prefer not to be credited. But I'm happy to change them.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1813
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
Seems like a reasonable compromise to me, if the user wants us to behave badly for the purpose of maximizing debug info, they can set us up to abort, otherwise, we'd use the exception mechanism.
Cemil Azizoglu (cemil-azizoglu) wrote : | # |
We can set up u-s-c and u8 to abort but as discussed previously mir should throw an exception by default.
Robert Carr (robertcarr) wrote : | # |
LGTM. Aborting in libraries can be a pain for users (see: libdbus).
Not convinced all actions are really fatal errors, i.e. failed to schedule page flip, it's not recoverable, but why could it not be intermittent?
Daniel van Vugt (vanvugt) wrote : | # |
(1) OK, yeah I don't approve of this new form so don't want to be listed as sole author. Although it's slightly inconsiderate considering the amount of code copied from my branch to list yourself first.
(2) Alright, you like exceptions and I like guaranteed post-mortem analysis. Let us agree to disagree.
So now I have an additional question: What does this branch solve or fix? Certainly not the bug I set out to fix in: https:/
Unless you explicitly turn "abort" on in downstream projects...
If abort isn't turned on by default then following simple logic, either:
(a) USC will want to turn it on always. So there's no reason to not make it the default in Mir for safety's sake, and go with my original proposal; or
(b) USC will not want to turn it on. This leads to no bugs being fixed. No improvement on the current situation. So why does this proposal exist at all?
I'm not trying to be negative. The reasoning doesn't seem add up. Is it (a) or (b), or am I foolish and you all know about an option (c) I'm not seeing?
Daniel van Vugt (vanvugt) wrote : | # |
An in case anyone thinks (c) is to turn abort on after a crash and retry, that's just silly. You can't go back and ask users to reproduce a bug they generally can't reproduce on demand. I know this from many years of joining projects where developers believed that and it was simply proven to be ineffective in every case. You have to catch crashes with a clean bug-report the first time. Because there typically either won't be a second time for any given user, or it will be so long in the future that you've left the bug in the wild for too long and they've given up on your product completely.
Serious bugs need to generate clean crash reports the first time with no special configuration or preparation by the user.
Daniel van Vugt (vanvugt) wrote : | # |
racarr: Absolutely everything should be recoverable (like failure to schedule a page flip). We just lack such logic at the moment. The "fatal-error" approach is a temporary solution until smarter recovery logic exists in the failing module(s). And an important one because it gives us vital feedback in the form of clean bug reports showing us how such an apparently impossible situation occurred.
Alan Griffiths (alan-griffiths) wrote : | # |
> (1) OK, yeah I don't approve of this new form so don't want to be listed as
> sole author. Although it's slightly inconsiderate considering the amount of
> code copied from my branch to list yourself first.
Fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1815
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === added file 'include/platform/mir/fatal.h' |
2 | --- include/platform/mir/fatal.h 1970-01-01 00:00:00 +0000 |
3 | +++ include/platform/mir/fatal.h 2014-08-05 11:38:58 +0000 |
4 | @@ -0,0 +1,76 @@ |
5 | +/* |
6 | + * Copyright © 2014 Canonical Ltd. |
7 | + * |
8 | + * This program is free software: you can redistribute it and/or modify |
9 | + * it under the terms of the GNU Lesser General Public License version 3 as |
10 | + * published by the Free Software Foundation. |
11 | + * |
12 | + * This program is distributed in the hope that it will be useful, |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | + * GNU Lesser General Public License for more details. |
16 | + * |
17 | + * You should have received a copy of the GNU Lesser General Public License |
18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | + * |
20 | + * --- |
21 | + * Fatal error handling - Fatal errors are situations we don't expect to ever |
22 | + * happen and don't have logic to gracefully recover from. The most useful |
23 | + * thing you can do in that situation is abort to get a clean core file and |
24 | + * stack trace to maximize the chances of it being readable. |
25 | + * |
26 | + * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> |
27 | + * Alan Griffiths <alan@octopull.co.uk> |
28 | + */ |
29 | + |
30 | +#ifndef MIR_FATAL_H_ |
31 | +#define MIR_FATAL_H_ |
32 | + |
33 | +namespace mir |
34 | +{ |
35 | +/** |
36 | + * fatal_error() is strictly for "this should never happen" situations that |
37 | + * you cannot recover from. By default it points at fatal_error_except(). |
38 | + * Note the reason parameter is a simple char* so its value is clearly visible |
39 | + * in stack trace output. |
40 | + * \param [in] reason A printf-style format string. |
41 | + */ |
42 | +extern void (*fatal_error)(char const* reason, ...); |
43 | + |
44 | +/** |
45 | + * Throws an exception that will typically kill the Mir server and propagate from |
46 | + * mir::run_mir. |
47 | + * \param [in] reason A printf-style format string. |
48 | + */ |
49 | +void fatal_error_except(char const* reason, ...); |
50 | + |
51 | +/** |
52 | + * An alternative to fatal_error_except() that kills the program and dump core |
53 | + * as cleanly as possible. |
54 | + * \param [in] reason A printf-style format string. |
55 | + */ |
56 | +void fatal_error_abort(char const* reason, ...); |
57 | + |
58 | +// Utility class to override & restore existing error handler |
59 | +class FatalErrorStrategy |
60 | +{ |
61 | +public: |
62 | + explicit FatalErrorStrategy(void (*fatal_error_handler)(char const* reason, ...)) : |
63 | + old_fatal_error_handler(fatal_error) |
64 | + { |
65 | + fatal_error = fatal_error_handler; |
66 | + } |
67 | + |
68 | + ~FatalErrorStrategy() |
69 | + { |
70 | + fatal_error = old_fatal_error_handler; |
71 | + } |
72 | + |
73 | +private: |
74 | + void (*old_fatal_error_handler)(char const* reason, ...); |
75 | + FatalErrorStrategy(FatalErrorStrategy const&) = delete; |
76 | + FatalErrorStrategy& operator=(FatalErrorStrategy const&) = delete; |
77 | +}; |
78 | +} // namespace mir |
79 | + |
80 | +#endif // MIR_FATAL_H_ |
81 | |
82 | === modified file 'src/platform/CMakeLists.txt' |
83 | --- src/platform/CMakeLists.txt 2014-07-24 13:44:09 +0000 |
84 | +++ src/platform/CMakeLists.txt 2014-08-05 11:38:58 +0000 |
85 | @@ -5,6 +5,7 @@ |
86 | shared_library_loader.cpp |
87 | $<TARGET_OBJECTS:mirplatformgraphicscommon> |
88 | $<TARGET_OBJECTS:miroptions> |
89 | + $<TARGET_OBJECTS:mirfatal> |
90 | ) |
91 | |
92 | target_link_libraries(mirplatform |
93 | @@ -17,3 +18,4 @@ |
94 | |
95 | add_subdirectory(graphics/) |
96 | add_subdirectory(options) |
97 | +add_subdirectory(fatal) |
98 | |
99 | === added directory 'src/platform/fatal' |
100 | === added file 'src/platform/fatal/CMakeLists.txt' |
101 | --- src/platform/fatal/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
102 | +++ src/platform/fatal/CMakeLists.txt 2014-08-05 11:38:58 +0000 |
103 | @@ -0,0 +1,3 @@ |
104 | +add_library(mirfatal OBJECT |
105 | + fatal.cpp |
106 | +) |
107 | |
108 | === added file 'src/platform/fatal/fatal.cpp' |
109 | --- src/platform/fatal/fatal.cpp 1970-01-01 00:00:00 +0000 |
110 | +++ src/platform/fatal/fatal.cpp 2014-08-05 11:38:58 +0000 |
111 | @@ -0,0 +1,58 @@ |
112 | +/* |
113 | + * Copyright © 2014 Canonical Ltd. |
114 | + * |
115 | + * This program is free software: you can redistribute it and/or modify it |
116 | + * under the terms of the GNU Lesser General Public License version 3, |
117 | + * as published by the Free Software Foundation. |
118 | + * |
119 | + * This program is distributed in the hope that it will be useful, |
120 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
121 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
122 | + * GNU Lesser General Public License for more details. |
123 | + * |
124 | + * You should have received a copy of the GNU Lesser General Public License |
125 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
126 | + * |
127 | + * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> |
128 | + * Alan Griffiths <alan@octopull.co.uk> |
129 | + */ |
130 | + |
131 | +#include "mir/fatal.h" |
132 | + |
133 | +#include <boost/throw_exception.hpp> |
134 | +#include <boost/exception/info.hpp> |
135 | + |
136 | +#include <stdexcept> |
137 | +#include <cstdlib> |
138 | +#include <cstdio> |
139 | +#include <cstdarg> |
140 | + |
141 | +void mir::fatal_error_abort(char const* reason, ...) |
142 | +{ |
143 | + va_list args; |
144 | + |
145 | + // Keep this as simple as possible, avoiding any object construction and |
146 | + // minimizing the potential for heap operations between the error location |
147 | + // and the abort(). |
148 | + va_start(args, reason); |
149 | + fprintf(stderr, "Mir fatal error: "); |
150 | + vfprintf(stderr, reason, args); |
151 | + fprintf(stderr, "\n"); |
152 | + va_end(args); |
153 | + |
154 | + std::abort(); |
155 | +} |
156 | + |
157 | +void mir::fatal_error_except(char const* reason, ...) |
158 | +{ |
159 | + char buffer[1024]; |
160 | + va_list args; |
161 | + |
162 | + va_start(args, reason); |
163 | + vsnprintf(buffer, sizeof buffer, reason, args); |
164 | + va_end(args); |
165 | + |
166 | + BOOST_THROW_EXCEPTION(std::runtime_error(buffer)); |
167 | +} |
168 | + |
169 | +void (*mir::fatal_error)(char const* reason, ...){&mir::fatal_error_except}; |
170 | |
171 | === modified file 'src/platform/graphics/mesa/CMakeLists.txt' |
172 | --- src/platform/graphics/mesa/CMakeLists.txt 2014-07-29 15:42:47 +0000 |
173 | +++ src/platform/graphics/mesa/CMakeLists.txt 2014-08-05 11:38:58 +0000 |
174 | @@ -46,8 +46,7 @@ |
175 | LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" |
176 | ) |
177 | |
178 | -target_link_libraries( |
179 | - mirplatformgraphicsmesa |
180 | +target_link_libraries(mirplatformgraphicsmesa |
181 | mirplatform |
182 | |
183 | ${Boost_PROGRAM_OPTIONS_LIBRARY} |
184 | |
185 | === modified file 'src/platform/graphics/mesa/display_buffer.cpp' |
186 | --- src/platform/graphics/mesa/display_buffer.cpp 2014-07-09 08:22:57 +0000 |
187 | +++ src/platform/graphics/mesa/display_buffer.cpp 2014-08-05 11:38:58 +0000 |
188 | @@ -22,6 +22,7 @@ |
189 | #include "mir/graphics/display_report.h" |
190 | #include "bypass.h" |
191 | #include "gbm_buffer.h" |
192 | +#include "mir/fatal.h" |
193 | |
194 | #include <boost/throw_exception.hpp> |
195 | #include <GLES2/gl2.h> |
196 | @@ -143,18 +144,18 @@ |
197 | glClear(GL_COLOR_BUFFER_BIT); |
198 | |
199 | if (!egl.swap_buffers()) |
200 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to perform initial surface buffer swap")); |
201 | + fatal_error("Failed to perform initial surface buffer swap"); |
202 | |
203 | listener->report_successful_egl_buffer_swap_on_construction(); |
204 | |
205 | scheduled_bufobj = get_front_buffer_object(); |
206 | if (!scheduled_bufobj) |
207 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to get frontbuffer")); |
208 | + fatal_error("Failed to get frontbuffer"); |
209 | |
210 | for (auto& output : outputs) |
211 | { |
212 | if (!output->set_crtc(scheduled_bufobj->get_drm_fb_id())) |
213 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to set DRM crtc")); |
214 | + fatal_error("Failed to set DRM crtc"); |
215 | } |
216 | |
217 | egl.release_current(); |
218 | @@ -256,7 +257,7 @@ |
219 | * corresponding to the front buffer. |
220 | */ |
221 | if (!bypass_buf && !egl.swap_buffers()) |
222 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to perform initial surface buffer swap")); |
223 | + fatal_error("Failed to perform initial surface buffer swap"); |
224 | |
225 | mgm::BufferObject *bufobj; |
226 | if (bypass_buf) |
227 | @@ -271,7 +272,7 @@ |
228 | } |
229 | |
230 | if (!bufobj) |
231 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to get front buffer object")); |
232 | + fatal_error("Failed to get front buffer object"); |
233 | |
234 | /* |
235 | * Schedule the current front buffer object for display, and wait |
236 | @@ -284,14 +285,14 @@ |
237 | { |
238 | if (!bypass_buf) |
239 | bufobj->release(); |
240 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to schedule page flip")); |
241 | + fatal_error("Failed to schedule page flip"); |
242 | } |
243 | else if (needs_set_crtc) |
244 | { |
245 | for (auto& output : outputs) |
246 | { |
247 | if (!output->set_crtc(bufobj->get_drm_fb_id())) |
248 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to set DRM crtc")); |
249 | + fatal_error("Failed to set DRM crtc"); |
250 | } |
251 | needs_set_crtc = false; |
252 | } |
253 | @@ -397,7 +398,7 @@ |
254 | { |
255 | if (!egl.make_current()) |
256 | { |
257 | - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to make EGL surface current")); |
258 | + fatal_error("Failed to make EGL surface current"); |
259 | } |
260 | } |
261 | |
262 | |
263 | === modified file 'src/platform/graphics/mesa/real_kms_output.cpp' |
264 | --- src/platform/graphics/mesa/real_kms_output.cpp 2014-07-09 10:48:47 +0000 |
265 | +++ src/platform/graphics/mesa/real_kms_output.cpp 2014-08-05 11:38:58 +0000 |
266 | @@ -18,11 +18,7 @@ |
267 | |
268 | #include "real_kms_output.h" |
269 | #include "page_flipper.h" |
270 | - |
271 | -#include <boost/throw_exception.hpp> |
272 | -#include <boost/exception/info.hpp> |
273 | - |
274 | -#include <stdexcept> |
275 | +#include "mir/fatal.h" |
276 | #include <vector> |
277 | #include <string.h> // strcmp |
278 | |
279 | @@ -166,7 +162,7 @@ |
280 | connector = resources.connector(connector_id); |
281 | |
282 | if (!connector) |
283 | - BOOST_THROW_EXCEPTION(std::runtime_error("No DRM connector found\n")); |
284 | + fatal_error("No DRM connector found"); |
285 | |
286 | // TODO: What if we can't locate the DPMS property? |
287 | for (int i = 0; i < connector->count_props; i++) |
288 | @@ -202,9 +198,10 @@ |
289 | bool mgm::RealKMSOutput::set_crtc(uint32_t fb_id) |
290 | { |
291 | if (!ensure_crtc()) |
292 | - BOOST_THROW_EXCEPTION(std::runtime_error("Output " + |
293 | - connector_name(connector.get()) + |
294 | - " has no associated CRTC to set a framebuffer on")); |
295 | + { |
296 | + fatal_error("Output %s has no associated CRTC to set a framebuffer on", |
297 | + connector_name(connector.get()).c_str()); |
298 | + } |
299 | |
300 | auto ret = drmModeSetCrtc(drm_fd, current_crtc->crtc_id, |
301 | fb_id, fb_offset.dx.as_int(), fb_offset.dy.as_int(), |
302 | @@ -235,12 +232,8 @@ |
303 | 0, 0, 0, nullptr, 0, nullptr); |
304 | if (result) |
305 | { |
306 | - std::string const msg = |
307 | - "Couldn't clear output " + connector_name(connector.get()); |
308 | - |
309 | - BOOST_THROW_EXCEPTION( |
310 | - ::boost::enable_error_info(std::runtime_error(msg)) |
311 | - << (boost::error_info<KMSOutput, decltype(result)>(result))); |
312 | + fatal_error("Couldn't clear output %s (drmModeSetCrtc = %d)", |
313 | + connector_name(connector.get()).c_str(), result); |
314 | } |
315 | |
316 | current_crtc = nullptr; |
317 | @@ -252,10 +245,10 @@ |
318 | if (power_mode != mir_power_mode_on) |
319 | return true; |
320 | if (!current_crtc) |
321 | - BOOST_THROW_EXCEPTION(std::runtime_error("Output " + |
322 | - connector_name(connector.get()) + |
323 | - " has no associated CRTC to schedule page flips on")); |
324 | - |
325 | + { |
326 | + fatal_error("Output %s has no associated CRTC to schedule page flips on", |
327 | + connector_name(connector.get()).c_str()); |
328 | + } |
329 | return page_flipper->schedule_flip(current_crtc->crtc_id, fb_id); |
330 | } |
331 | |
332 | @@ -265,10 +258,10 @@ |
333 | if (power_mode != mir_power_mode_on) |
334 | return; |
335 | if (!current_crtc) |
336 | - BOOST_THROW_EXCEPTION(std::runtime_error("Output " + |
337 | - connector_name(connector.get()) + |
338 | - " has no associated CRTC to wait on")); |
339 | - |
340 | + { |
341 | + fatal_error("Output %s has no associated CRTC to wait on", |
342 | + connector_name(connector.get()).c_str()); |
343 | + } |
344 | page_flipper->wait_for_flip(current_crtc->crtc_id); |
345 | } |
346 | |
347 | @@ -283,9 +276,7 @@ |
348 | gbm_bo_get_width(buffer), |
349 | gbm_bo_get_height(buffer))) |
350 | { |
351 | - BOOST_THROW_EXCEPTION( |
352 | - ::boost::enable_error_info(std::runtime_error("drmModeSetCursor() failed")) |
353 | - << (boost::error_info<KMSOutput, decltype(result)>(result))); |
354 | + fatal_error("drmModeSetCursor failed (returned %d)", result); |
355 | } |
356 | |
357 | has_cursor_ = true; |
358 | @@ -300,9 +291,7 @@ |
359 | destination.x.as_uint32_t(), |
360 | destination.y.as_uint32_t())) |
361 | { |
362 | - BOOST_THROW_EXCEPTION( |
363 | - ::boost::enable_error_info(std::runtime_error("drmModeMoveCursor() failed")) |
364 | - << (boost::error_info<KMSOutput, decltype(result)>(result))); |
365 | + fatal_error("drmModeMoveCursor failed (returned %d)", result); |
366 | } |
367 | } |
368 | } |
369 | |
370 | === modified file 'tests/acceptance-tests/test_server_shutdown.cpp' |
371 | --- tests/acceptance-tests/test_server_shutdown.cpp 2014-07-21 03:35:31 +0000 |
372 | +++ tests/acceptance-tests/test_server_shutdown.cpp 2014-08-05 11:38:58 +0000 |
373 | @@ -23,6 +23,7 @@ |
374 | #include "mir/compositor/display_buffer_compositor_factory.h" |
375 | #include "mir/input/composite_event_filter.h" |
376 | #include "mir/run_mir.h" |
377 | +#include "mir/fatal.h" |
378 | |
379 | #include "mir_test_framework/display_server_test_fixture.h" |
380 | #include "mir_test/fake_event_hub_input_configuration.h" |
381 | @@ -419,6 +420,70 @@ |
382 | }); |
383 | } |
384 | |
385 | +TEST_F(ServerShutdown, server_removes_endpoint_on_mir_fatal_error_abort) |
386 | +{ // Even fatal errors sometimes need to be caught for critical cleanup... |
387 | + struct ServerConfig : TestingServerConfiguration |
388 | + { |
389 | + void on_start() override |
390 | + { |
391 | + sync.wait_for_signal_ready_for(); |
392 | + mir::fatal_error("Bang"); |
393 | + } |
394 | + |
395 | + mir::FatalErrorStrategy on_error{mir::fatal_error_abort}; |
396 | + mtf::CrossProcessSync sync; |
397 | + }; |
398 | + |
399 | + ServerConfig server_config; |
400 | + launch_server_process(server_config); |
401 | + |
402 | + run_in_test_process([&] |
403 | + { |
404 | + ASSERT_TRUE(file_exists(server_config.the_socket_file())); |
405 | + |
406 | + server_config.sync.signal_ready(); |
407 | + |
408 | + auto result = wait_for_shutdown_server_process(); |
409 | + EXPECT_EQ(mtf::TerminationReason::child_terminated_by_signal, result.reason); |
410 | + // Under valgrind the server process is reported as being terminated |
411 | + // by SIGKILL because of multithreading madness. |
412 | + // TODO: Investigate if we can do better than this workaround |
413 | + EXPECT_TRUE(result.signal == SIGABRT || result.signal == SIGKILL); |
414 | + |
415 | + EXPECT_FALSE(file_exists(server_config.the_socket_file())); |
416 | + }); |
417 | +} |
418 | + |
419 | + |
420 | +TEST_F(ServerShutdown, server_removes_endpoint_on_mir_fatal_error_except) |
421 | +{ // Even fatal errors sometimes need to be caught for critical cleanup... |
422 | + struct ServerConfig : TestingServerConfiguration |
423 | + { |
424 | + void on_start() override |
425 | + { |
426 | + sync.wait_for_signal_ready_for(); |
427 | + mir::fatal_error("Bang"); |
428 | + } |
429 | + |
430 | + mtf::CrossProcessSync sync; |
431 | + }; |
432 | + |
433 | + ServerConfig server_config; |
434 | + launch_server_process(server_config); |
435 | + |
436 | + run_in_test_process([&] |
437 | + { |
438 | + ASSERT_TRUE(file_exists(server_config.the_socket_file())); |
439 | + |
440 | + server_config.sync.signal_ready(); |
441 | + |
442 | + auto result = wait_for_shutdown_server_process(); |
443 | + EXPECT_EQ(mtf::TerminationReason::child_terminated_normally, result.reason); |
444 | + |
445 | + EXPECT_FALSE(file_exists(server_config.the_socket_file())); |
446 | + }); |
447 | +} |
448 | + |
449 | struct OnSignal : ServerShutdown, ::testing::WithParamInterface<int> {}; |
450 | |
451 | TEST_P(OnSignal, removes_endpoint_on_signal) |
452 | |
453 | === modified file 'tests/unit-tests/CMakeLists.txt' |
454 | --- tests/unit-tests/CMakeLists.txt 2014-07-31 12:38:17 +0000 |
455 | +++ tests/unit-tests/CMakeLists.txt 2014-08-05 11:38:58 +0000 |
456 | @@ -19,6 +19,7 @@ |
457 | test_thread_name.cpp |
458 | test_default_emergency_cleanup.cpp |
459 | test_basic_observers.cpp |
460 | + test_fatal.cpp |
461 | test_fd.cpp |
462 | ) |
463 | |
464 | |
465 | === added file 'tests/unit-tests/test_fatal.cpp' |
466 | --- tests/unit-tests/test_fatal.cpp 1970-01-01 00:00:00 +0000 |
467 | +++ tests/unit-tests/test_fatal.cpp 2014-08-05 11:38:58 +0000 |
468 | @@ -0,0 +1,59 @@ |
469 | +/* |
470 | + * Copyright © 2014 Canonical Ltd. |
471 | + * |
472 | + * This program is free software: you can redistribute it and/or modify it |
473 | + * under the terms of the GNU General Public License version 3, |
474 | + * as published by the Free Software Foundation. |
475 | + * |
476 | + * This program is distributed in the hope that it will be useful, |
477 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
478 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
479 | + * GNU General Public License for more details. |
480 | + * |
481 | + * You should have received a copy of the GNU General Public License |
482 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
483 | + * |
484 | + * Author: Daniel van Vugt <daniel.van.vugt@canonical.com> |
485 | + * Alan Griffiths <alan@octopull.co.uk> |
486 | + */ |
487 | + |
488 | +#include "mir/fatal.h" |
489 | +#include <gtest/gtest.h> |
490 | +#include <gmock/gmock.h> |
491 | +#include <csignal> |
492 | + |
493 | +using namespace testing; |
494 | + |
495 | +TEST(FatalTest, abort_formats_message_to_stderr) |
496 | +{ |
497 | + mir::FatalErrorStrategy on_error{mir::fatal_error_abort}; |
498 | + |
499 | + EXPECT_DEATH({mir::fatal_error("%s had %d %s %s", "Mary", 1, "little", "lamb");}, |
500 | + "Mary had 1 little lamb"); |
501 | +} |
502 | + |
503 | +TEST(FatalTest, abort_raises_sigabrt) |
504 | +{ |
505 | + mir::FatalErrorStrategy on_error{mir::fatal_error_abort}; |
506 | + |
507 | + EXPECT_EXIT({mir::fatal_error("Hello world");}, |
508 | + KilledBySignal(SIGABRT), |
509 | + "Hello world"); |
510 | +} |
511 | + |
512 | +TEST(FatalTest, throw_formats_message_to_what) |
513 | +{ |
514 | + EXPECT_THROW( |
515 | + mir::fatal_error("%s had %d %s %s", "Mary", 1, "little", "lamb"), |
516 | + std::runtime_error); |
517 | + |
518 | + try |
519 | + { |
520 | + mir::fatal_error("%s had %d %s %s", "Mary", 1, "little", "lamb"); |
521 | + } |
522 | + catch (std::exception const& x) |
523 | + { |
524 | + EXPECT_THAT(x.what(), StrEq("Mary had 1 little lamb")); |
525 | + } |
526 | +} |
527 | + |
PASSED: Continuous integration, rev:1811 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- ci/2287/ jenkins. qa.ubuntu. com/job/ mir-android- utopic- i386-build/ 1165 jenkins. qa.ubuntu. com/job/ mir-clang- utopic- amd64-build/ 1171 jenkins. qa.ubuntu. com/job/ mir-mediumtests -utopic- touch/1153 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- amd64-ci/ 809 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- amd64-ci/ 809/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- armhf-ci/ 810 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- armhf-ci/ 810/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/88 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/88/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/2275 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 10839
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- team-mir- development- branch- ci/2287/ rebuild
http://