Merge lp:~mir-team/mir/wayland-fix-keymaps-re-attempt into lp:mir
- wayland-fix-keymaps-re-attempt
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 4284 |
Proposed branch: | lp:~mir-team/mir/wayland-fix-keymaps-re-attempt |
Merge into: | lp:mir |
Prerequisite: | lp:~raof/mir/fixish-wayland-keyboard |
Diff against target: |
599 lines (+302/-27) 12 files modified
include/core/mir/optional_value.h (+5/-0) include/server/mir/server_action_queue.h (+10/-0) src/include/server/mir/glib_main_loop.h (+5/-0) src/server/frontend/wayland/wayland_connector.cpp (+130/-18) src/server/frontend/wayland/wayland_connector.h (+5/-1) src/server/frontend/wayland/wayland_default_configuration.cpp (+1/-0) src/server/glib_main_loop.cpp (+55/-1) src/server/input/default_input_device_hub.cpp (+8/-7) tests/include/mir/test/doubles/triggered_main_loop.h (+1/-0) tests/mir_test_doubles/triggered_main_loop.cpp (+6/-0) tests/unit-tests/scene/test_mediating_display_changer.cpp (+6/-0) tests/unit-tests/test_glib_main_loop.cpp (+70/-0) |
To merge this branch: | bzr merge lp:~mir-team/mir/wayland-fix-keymaps-re-attempt |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Approve | ||
Mir CI Bot | continuous-integration | Approve | |
Review via email: mp+331793@code.launchpad.net |
Commit message
Wayland: Handle keymaps vaguely appropriately.
This will work for the common case of one system-wide keymap and no per-surface keymaps.
It does not handle having multiple keyboards with different keymaps, or per-surface keymaps. This is left as an exercise for the reader.
Description of the change
Re proposing https:/
Since it didnt want to update its diffs or anything.
Wayland: Handle keymaps vaguely appropriately.
This will work for the common case of one system-wide keymap and no per-surface keymaps.
It does not handle having multiple keyboards with different keymaps, or per-surface keymaps. This is left as an exercise for the reader.
Mir CI Bot (mir-ci-bot) wrote : | # |
MichaĆ Sawicz (saviq) wrote : | # |
I'm afraid CI is quite insistent on the test failures :/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:4292
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
ABORTED: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:4292
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4292
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : | # |
Nit:
+ void device_added (std::shared_
+ void device_changed (std::shared_
+ void device_removed (std::shared_
+ void changes_complete () override;
We don't leave a space before function call parentheses.
Otherwise looks plausible and works for me
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:4283
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'include/core/mir/optional_value.h' |
2 | --- include/core/mir/optional_value.h 2017-07-28 17:00:43 +0000 |
3 | +++ include/core/mir/optional_value.h 2017-10-09 17:50:36 +0000 |
4 | @@ -59,6 +59,11 @@ |
5 | return std::move(value_); |
6 | } |
7 | |
8 | + operator bool() const |
9 | + { |
10 | + return is_set(); |
11 | + } |
12 | + |
13 | private: |
14 | void die_if_unset() const |
15 | { |
16 | |
17 | === modified file 'include/server/mir/server_action_queue.h' |
18 | --- include/server/mir/server_action_queue.h 2017-07-28 17:00:43 +0000 |
19 | +++ include/server/mir/server_action_queue.h 2017-10-09 17:50:36 +0000 |
20 | @@ -32,6 +32,16 @@ |
21 | virtual ~ServerActionQueue() = default; |
22 | |
23 | virtual void enqueue(void const* owner, ServerAction const& action) = 0; |
24 | + /** |
25 | + * Enqueue an action to be run, guaranteeing that it *will* be run. |
26 | + * |
27 | + * The action will be run even if the queue is not normally being drained |
28 | + * (for example, if the main loop is suspended). If running on the queue is |
29 | + * not possible, the action will be run on the caller's thread. |
30 | + * |
31 | + * \param [in] action Functor to invoke. |
32 | + */ |
33 | + virtual void enqueue_with_guaranteed_execution(ServerAction const& action) = 0; |
34 | virtual void pause_processing_for(void const* owner) = 0; |
35 | virtual void resume_processing_for(void const* owner) = 0; |
36 | |
37 | |
38 | === modified file 'src/include/server/mir/glib_main_loop.h' |
39 | --- src/include/server/mir/glib_main_loop.h 2017-07-28 17:00:43 +0000 |
40 | +++ src/include/server/mir/glib_main_loop.h 2017-10-09 17:50:36 +0000 |
41 | @@ -28,6 +28,7 @@ |
42 | #include <exception> |
43 | |
44 | #include <glib.h> |
45 | +#include <deque> |
46 | |
47 | namespace mir |
48 | { |
49 | @@ -76,6 +77,8 @@ |
50 | void unregister_fd_handler(void const* owner) override; |
51 | |
52 | void enqueue(void const* owner, ServerAction const& action) override; |
53 | + void enqueue_with_guaranteed_execution(ServerAction const& action) override; |
54 | + |
55 | void pause_processing_for(void const* owner) override; |
56 | void resume_processing_for(void const* owner) override; |
57 | |
58 | @@ -100,6 +103,8 @@ |
59 | detail::SignalSources signal_sources; |
60 | std::mutex do_not_process_mutex; |
61 | std::vector<void const*> do_not_process; |
62 | + std::mutex run_on_halt_mutex; |
63 | + std::deque<ServerAction> run_on_halt_queue; |
64 | std::function<void()> before_iteration_hook; |
65 | std::exception_ptr main_loop_exception; |
66 | }; |
67 | |
68 | === modified file 'src/server/frontend/wayland/wayland_connector.cpp' |
69 | --- src/server/frontend/wayland/wayland_connector.cpp 2017-10-08 02:12:58 +0000 |
70 | +++ src/server/frontend/wayland/wayland_connector.cpp 2017-10-09 17:50:36 +0000 |
71 | @@ -43,6 +43,11 @@ |
72 | |
73 | #include "mir/client/event.h" |
74 | |
75 | +#include "mir/input/device.h" |
76 | +#include "mir/input/mir_keyboard_config.h" |
77 | +#include "mir/input/input_device_hub.h" |
78 | +#include "mir/input/input_device_observer.h" |
79 | + |
80 | #include <system_error> |
81 | #include <sys/eventfd.h> |
82 | #include <wayland-server-core.h> |
83 | @@ -75,6 +80,7 @@ |
84 | namespace ms = mir::scene; |
85 | namespace geom = mir::geometry; |
86 | namespace mcl = mir::client; |
87 | +namespace mi = mir::input; |
88 | |
89 | namespace mir |
90 | { |
91 | @@ -798,6 +804,7 @@ |
92 | wl_client* client, |
93 | wl_resource* parent, |
94 | uint32_t id, |
95 | + mir::input::Keymap const& initial_keymap, |
96 | std::function<void(WlKeyboard*)> const& on_destroy, |
97 | std::shared_ptr<mir::Executor> const& executor) |
98 | : Keyboard(client, parent, id), |
99 | @@ -811,19 +818,14 @@ |
100 | // TODO: We should really grab the keymap for the focused surface when |
101 | // we receive focus. |
102 | |
103 | - xkb_rule_names default_rules; |
104 | - memset(&default_rules, 0, sizeof(default_rules)); |
105 | - |
106 | - keymap = decltype(keymap){ |
107 | - xkb_keymap_new_from_names( |
108 | - context.get(), |
109 | - &default_rules, |
110 | - XKB_KEYMAP_COMPILE_NO_FLAGS), |
111 | - &xkb_keymap_unref}; |
112 | - |
113 | - state = decltype(state){ |
114 | - xkb_state_new(keymap.get()), |
115 | - &xkb_state_unref}; |
116 | + // TODO: Maintain per-device keymaps, and send the appropriate map before |
117 | + // sending an event from a keyboard with a different map. |
118 | + |
119 | + /* The wayland::Keyboard constructor has already run, creating the keyboard |
120 | + * resource. It is thus safe to send a keymap event to it; the client will receive |
121 | + * the keyboard object before this event. |
122 | + */ |
123 | + set_keymap(initial_keymap); |
124 | } |
125 | |
126 | ~WlKeyboard() |
127 | @@ -966,6 +968,38 @@ |
128 | state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref); |
129 | } |
130 | |
131 | + void set_keymap(mir::input::Keymap const& new_keymap) |
132 | + { |
133 | + xkb_rule_names const names = { |
134 | + "evdev", |
135 | + new_keymap.model.c_str(), |
136 | + new_keymap.layout.c_str(), |
137 | + new_keymap.variant.c_str(), |
138 | + new_keymap.options.c_str() |
139 | + }; |
140 | + keymap = decltype(keymap){ |
141 | + xkb_keymap_new_from_names( |
142 | + context.get(), |
143 | + &names, |
144 | + XKB_KEYMAP_COMPILE_NO_FLAGS), |
145 | + &xkb_keymap_unref}; |
146 | + |
147 | + // TODO: We might need to copy across the existing depressed keys? |
148 | + state = decltype(state)(xkb_state_new(keymap.get()), &xkb_state_unref); |
149 | + |
150 | + auto buffer = xkb_keymap_get_as_string(keymap.get(), XKB_KEYMAP_FORMAT_TEXT_V1); |
151 | + auto length = strlen(buffer); |
152 | + |
153 | + mir::AnonymousShmFile shm_buffer{length}; |
154 | + memcpy(shm_buffer.base_ptr(), buffer, length); |
155 | + |
156 | + wl_keyboard_send_keymap( |
157 | + resource, |
158 | + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, |
159 | + shm_buffer.fd(), |
160 | + length); |
161 | + } |
162 | + |
163 | private: |
164 | std::unique_ptr<xkb_keymap, decltype(&xkb_keymap_unref)> keymap; |
165 | std::unique_ptr<xkb_state, decltype(&xkb_state_unref)> state; |
166 | @@ -1320,8 +1354,20 @@ |
167 | class WlSeat |
168 | { |
169 | public: |
170 | - WlSeat(wl_display* display, std::shared_ptr<mir::Executor> const& executor) |
171 | - : executor{executor}, |
172 | + WlSeat( |
173 | + wl_display* display, |
174 | + std::shared_ptr<mi::InputDeviceHub> const& input_hub, |
175 | + std::shared_ptr<mir::Executor> const& executor) |
176 | + : config_observer{ |
177 | + std::make_shared<ConfigObserver>( |
178 | + keymap, |
179 | + [this](mir::input::Keymap const& new_keymap) |
180 | + { |
181 | + keymap = new_keymap; |
182 | + |
183 | + })}, |
184 | + input_hub{input_hub}, |
185 | + executor{executor}, |
186 | global{wl_global_create( |
187 | display, |
188 | &wl_seat_interface, |
189 | @@ -1333,10 +1379,12 @@ |
190 | { |
191 | BOOST_THROW_EXCEPTION(std::runtime_error("Failed to export wl_seat interface")); |
192 | } |
193 | + input_hub->add_observer(config_observer); |
194 | } |
195 | |
196 | ~WlSeat() |
197 | { |
198 | + input_hub->remove_observer(config_observer); |
199 | wl_global_destroy(global); |
200 | } |
201 | |
202 | @@ -1350,9 +1398,38 @@ |
203 | } |
204 | |
205 | private: |
206 | + class ConfigObserver : public mi::InputDeviceObserver |
207 | + { |
208 | + public: |
209 | + ConfigObserver( |
210 | + mir::input::Keymap const& keymap, |
211 | + std::function<void(mir::input::Keymap const&)> const& on_keymap_commit) |
212 | + : current_keymap{keymap}, |
213 | + on_keymap_commit{on_keymap_commit} |
214 | + { |
215 | + } |
216 | + |
217 | + void device_added(std::shared_ptr<input::Device> const& device) override; |
218 | + void device_changed(std::shared_ptr<input::Device> const& device) override; |
219 | + void device_removed(std::shared_ptr<input::Device> const& device) override; |
220 | + void changes_complete() override; |
221 | + |
222 | + private: |
223 | + mir::input::Keymap const& current_keymap; |
224 | + mir::input::Keymap pending_keymap; |
225 | + std::function<void(mir::input::Keymap const&)> const on_keymap_commit; |
226 | + }; |
227 | + |
228 | + mir::input::Keymap keymap; |
229 | + std::shared_ptr<ConfigObserver> const config_observer; |
230 | + |
231 | std::unordered_map<wl_client*, InputCtx<WlPointer>> mutable pointer; |
232 | std::unordered_map<wl_client*, InputCtx<WlKeyboard>> mutable keyboard; |
233 | std::unordered_map<wl_client*, InputCtx<WlTouch>> mutable touch; |
234 | + |
235 | + std::shared_ptr<mi::InputDeviceHub> const input_hub; |
236 | + |
237 | + |
238 | std::shared_ptr<mir::Executor> const executor; |
239 | |
240 | static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id) |
241 | @@ -1413,6 +1490,7 @@ |
242 | client, |
243 | resource, |
244 | id, |
245 | + me->keymap, |
246 | [&input_ctx](WlKeyboard* listener) |
247 | { |
248 | input_ctx.unregister_listener(listener); |
249 | @@ -1435,8 +1513,10 @@ |
250 | }, |
251 | me->executor}); |
252 | } |
253 | - static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {} |
254 | - |
255 | + static void release(struct wl_client* /*client*/, struct wl_resource* us) |
256 | + { |
257 | + wl_resource_destroy(us); |
258 | + } |
259 | |
260 | wl_global* const global; |
261 | static struct wl_seat_interface const vtable; |
262 | @@ -1464,6 +1544,37 @@ |
263 | return touch[client]; |
264 | } |
265 | |
266 | +void WlSeat::ConfigObserver::device_added(std::shared_ptr<input::Device> const& device) |
267 | +{ |
268 | + if (auto keyboard_config = device->keyboard_configuration()) |
269 | + { |
270 | + if (current_keymap != keyboard_config.value().device_keymap()) |
271 | + { |
272 | + pending_keymap = keyboard_config.value().device_keymap(); |
273 | + } |
274 | + } |
275 | +} |
276 | + |
277 | +void WlSeat::ConfigObserver::device_changed(std::shared_ptr<input::Device> const& device) |
278 | +{ |
279 | + if (auto keyboard_config = device->keyboard_configuration()) |
280 | + { |
281 | + if (current_keymap != keyboard_config.value().device_keymap()) |
282 | + { |
283 | + pending_keymap = keyboard_config.value().device_keymap(); |
284 | + } |
285 | + } |
286 | +} |
287 | + |
288 | +void WlSeat::ConfigObserver::device_removed(std::shared_ptr<input::Device> const& /*device*/) |
289 | +{ |
290 | +} |
291 | + |
292 | +void WlSeat::ConfigObserver::changes_complete() |
293 | +{ |
294 | + on_keymap_commit(pending_keymap); |
295 | +} |
296 | + |
297 | void WaylandEventSink::send_buffer(BufferStreamId /*id*/, graphics::Buffer& /*buffer*/, graphics::BufferIpcMsgType) |
298 | { |
299 | } |
300 | @@ -2055,6 +2166,7 @@ |
301 | optional_value<std::string> const& display_name, |
302 | std::shared_ptr<mf::Shell> const& shell, |
303 | DisplayChanger& display_config, |
304 | + std::shared_ptr<mi::InputDeviceHub> const& input_hub, |
305 | std::shared_ptr<mg::GraphicBufferAllocator> const& allocator, |
306 | bool arw_socket) |
307 | : display{wl_display_create(), &cleanup_display}, |
308 | @@ -2089,7 +2201,7 @@ |
309 | display.get(), |
310 | executor, |
311 | this->allocator); |
312 | - seat_global = std::make_unique<mf::WlSeat>(display.get(), executor); |
313 | + seat_global = std::make_unique<mf::WlSeat>(display.get(), input_hub, executor); |
314 | output_manager = std::make_unique<mf::OutputManager>( |
315 | display.get(), |
316 | display_config); |
317 | |
318 | === modified file 'src/server/frontend/wayland/wayland_connector.h' |
319 | --- src/server/frontend/wayland/wayland_connector.h 2017-09-15 16:34:13 +0000 |
320 | +++ src/server/frontend/wayland/wayland_connector.h 2017-10-09 17:50:36 +0000 |
321 | @@ -29,7 +29,10 @@ |
322 | namespace mir |
323 | { |
324 | |
325 | - |
326 | +namespace input |
327 | +{ |
328 | +class InputDeviceHub; |
329 | +} |
330 | namespace graphics |
331 | { |
332 | class GraphicBufferAllocator; |
333 | @@ -54,6 +57,7 @@ |
334 | optional_value<std::string> const& display_name, |
335 | std::shared_ptr<Shell> const& shell, |
336 | DisplayChanger& display_config, |
337 | + std::shared_ptr<input::InputDeviceHub> const& input_hub, |
338 | std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator, |
339 | bool arw_socket); |
340 | |
341 | |
342 | === modified file 'src/server/frontend/wayland/wayland_default_configuration.cpp' |
343 | --- src/server/frontend/wayland/wayland_default_configuration.cpp 2017-09-15 16:34:13 +0000 |
344 | +++ src/server/frontend/wayland/wayland_default_configuration.cpp 2017-10-09 17:50:36 +0000 |
345 | @@ -42,6 +42,7 @@ |
346 | display_name, |
347 | the_frontend_shell(), |
348 | *the_frontend_display_changer(), |
349 | + the_input_device_hub(), |
350 | the_buffer_allocator(), |
351 | arw_socket); |
352 | }); |
353 | |
354 | === modified file 'src/server/glib_main_loop.cpp' |
355 | --- src/server/glib_main_loop.cpp 2017-07-28 17:00:43 +0000 |
356 | +++ src/server/glib_main_loop.cpp 2017-10-09 17:50:36 +0000 |
357 | @@ -154,7 +154,19 @@ |
358 | detail::add_idle_gsource(main_context, G_PRIORITY_HIGH, |
359 | [this] |
360 | { |
361 | - running = false; |
362 | + { |
363 | + std::lock_guard<std::mutex> lock{run_on_halt_mutex}; |
364 | + running = false; |
365 | + } |
366 | + // We know any other thread sees running == false here, so don't need |
367 | + // to lock run_on_halt_queue. |
368 | + for (auto& action : run_on_halt_queue) |
369 | + { |
370 | + try { action(); } |
371 | + catch (...) { handle_exception(std::current_exception()); } |
372 | + } |
373 | + run_on_halt_queue.clear(); |
374 | + |
375 | g_main_context_wakeup(main_context); |
376 | }); |
377 | } |
378 | @@ -246,6 +258,48 @@ |
379 | }); |
380 | } |
381 | |
382 | + |
383 | +void mir::GLibMainLoop::enqueue_with_guaranteed_execution(mir::ServerAction const& action) |
384 | +{ |
385 | + auto const action_with_exception_handling = |
386 | + [this] |
387 | + { |
388 | + try |
389 | + { |
390 | + mir::ServerAction action; |
391 | + { |
392 | + std::lock_guard<std::mutex> lock{run_on_halt_mutex}; |
393 | + action = run_on_halt_queue.front(); |
394 | + run_on_halt_queue.pop_front(); |
395 | + } |
396 | + action(); |
397 | + } |
398 | + catch (...) |
399 | + { |
400 | + handle_exception(std::current_exception()); |
401 | + } |
402 | + }; |
403 | + |
404 | + { |
405 | + std::lock_guard<std::mutex> lock{run_on_halt_mutex}; |
406 | + |
407 | + if (!running) |
408 | + { |
409 | + action(); |
410 | + return; |
411 | + } |
412 | + else |
413 | + { |
414 | + run_on_halt_queue.push_back(action); |
415 | + } |
416 | + } |
417 | + |
418 | + detail::add_idle_gsource( |
419 | + main_context, |
420 | + G_PRIORITY_DEFAULT, |
421 | + action_with_exception_handling); |
422 | +} |
423 | + |
424 | void mir::GLibMainLoop::pause_processing_for(void const* owner) |
425 | { |
426 | std::lock_guard<std::mutex> lock{do_not_process_mutex}; |
427 | |
428 | === modified file 'src/server/input/default_input_device_hub.cpp' |
429 | --- src/server/input/default_input_device_hub.cpp 2017-07-28 17:00:43 +0000 |
430 | +++ src/server/input/default_input_device_hub.cpp 2017-10-09 17:50:36 +0000 |
431 | @@ -88,25 +88,26 @@ |
432 | auto observer = obs.lock(); |
433 | if (observer) |
434 | { |
435 | - std::mutex mutex; |
436 | std::condition_variable cv; |
437 | - std::unique_lock<decltype(mutex)> lock{mutex}; |
438 | - bool removed{false}; |
439 | + std::atomic<bool> removed{false}; |
440 | |
441 | - data->observer_queue->enqueue( |
442 | - data.get(), |
443 | + data->observer_queue->enqueue_with_guaranteed_execution( |
444 | [&,this] |
445 | { |
446 | // Unless remove() is on the same thread as add() external synchronization would be needed |
447 | data->observers.remove(observer); |
448 | |
449 | - std::lock_guard<decltype(mutex)> lock{mutex}; |
450 | + // We do *not* take a lock and instead rely on removed being atomic, |
451 | + // as enqueue_with_guaranteed_execution may run on our stack. |
452 | removed = true; |
453 | cv.notify_one(); |
454 | }); |
455 | |
456 | + std::mutex mutex; |
457 | + std::unique_lock<decltype(mutex)> lock{mutex}; |
458 | + |
459 | // Before returning wait for the remove - otherwise notifications can still happen |
460 | - cv.wait(lock, [&] { return removed; }); |
461 | + cv.wait(lock, [&] { return removed.load(); }); |
462 | } |
463 | } |
464 | |
465 | |
466 | === modified file 'tests/include/mir/test/doubles/triggered_main_loop.h' |
467 | --- tests/include/mir/test/doubles/triggered_main_loop.h 2017-07-28 17:00:43 +0000 |
468 | +++ tests/include/mir/test/doubles/triggered_main_loop.h 2017-10-09 17:50:36 +0000 |
469 | @@ -41,6 +41,7 @@ |
470 | void unregister_fd_handler(void const* owner) override; |
471 | std::unique_ptr<mir::time::Alarm> create_alarm(callback const& call) override; |
472 | void enqueue(void const* owner, ServerAction const& action) override; |
473 | + void enqueue_with_guaranteed_execution(ServerAction const& action) override; |
474 | |
475 | void spawn(std::function<void()>&& work) override; |
476 | |
477 | |
478 | === modified file 'tests/mir_test_doubles/triggered_main_loop.cpp' |
479 | --- tests/mir_test_doubles/triggered_main_loop.cpp 2017-07-28 17:00:43 +0000 |
480 | +++ tests/mir_test_doubles/triggered_main_loop.cpp 2017-10-09 17:50:36 +0000 |
481 | @@ -81,6 +81,12 @@ |
482 | actions.push_back(action); |
483 | } |
484 | |
485 | +void mtd::TriggeredMainLoop::enqueue_with_guaranteed_execution(ServerAction const& action) |
486 | +{ |
487 | + base::enqueue(nullptr, action); |
488 | + actions.push_back(action); |
489 | +} |
490 | + |
491 | void mtd::TriggeredMainLoop::trigger_server_actions() |
492 | { |
493 | for (auto const& action : actions) |
494 | |
495 | === modified file 'tests/unit-tests/scene/test_mediating_display_changer.cpp' |
496 | --- tests/unit-tests/scene/test_mediating_display_changer.cpp 2017-08-09 11:30:59 +0000 |
497 | +++ tests/unit-tests/scene/test_mediating_display_changer.cpp 2017-10-09 17:50:36 +0000 |
498 | @@ -100,6 +100,10 @@ |
499 | { |
500 | action(); |
501 | } |
502 | + void enqueue_with_guaranteed_execution(mir::ServerAction const& action) override |
503 | + { |
504 | + action(); |
505 | + } |
506 | |
507 | void pause_processing_for(void const* /*owner*/) override {} |
508 | void resume_processing_for(void const* /*owner*/) override {} |
509 | @@ -110,8 +114,10 @@ |
510 | MockServerActionQueue() |
511 | { |
512 | ON_CALL(*this, enqueue(_, _)).WillByDefault(InvokeArgument<1>()); |
513 | + ON_CALL(*this, enqueue_with_guaranteed_execution(_)).WillByDefault(InvokeArgument<0>()); |
514 | } |
515 | MOCK_METHOD2(enqueue, void(void const*, mir::ServerAction const&)); |
516 | + MOCK_METHOD1(enqueue_with_guaranteed_execution, void(mir::ServerAction const&)); |
517 | MOCK_METHOD1(pause_processing_for, void(void const*)); |
518 | MOCK_METHOD1(resume_processing_for, void(void const*)); |
519 | }; |
520 | |
521 | === modified file 'tests/unit-tests/test_glib_main_loop.cpp' |
522 | --- tests/unit-tests/test_glib_main_loop.cpp 2017-07-28 17:00:43 +0000 |
523 | +++ tests/unit-tests/test_glib_main_loop.cpp 2017-10-09 17:50:36 +0000 |
524 | @@ -833,6 +833,76 @@ |
525 | destroy_glib_main_loop); |
526 | } |
527 | |
528 | +TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_before_run) |
529 | +{ |
530 | + using namespace testing; |
531 | + |
532 | + int num_actions{0}; |
533 | + |
534 | + ml.enqueue_with_guaranteed_execution( |
535 | + [&num_actions] |
536 | + { |
537 | + ++num_actions; |
538 | + }); |
539 | + |
540 | + EXPECT_THAT(num_actions, Eq(1)); |
541 | +} |
542 | + |
543 | +TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_after_stop) |
544 | +{ |
545 | + using namespace testing; |
546 | + |
547 | + int num_actions{0}; |
548 | + |
549 | + ml.enqueue( |
550 | + nullptr, |
551 | + [this]() |
552 | + { |
553 | + ml.stop(); |
554 | + }); |
555 | + |
556 | + ml.run(); |
557 | + |
558 | + ml.enqueue_with_guaranteed_execution( |
559 | + [&num_actions] |
560 | + { |
561 | + ++num_actions; |
562 | + }); |
563 | + |
564 | + EXPECT_THAT(num_actions, Eq(1)); |
565 | +} |
566 | + |
567 | +TEST_F(GLibMainLoopTest, enqueue_with_guaranteed_execution_executes_on_mainloop) |
568 | +{ |
569 | + using namespace testing; |
570 | + |
571 | + mt::Signal loop_running; |
572 | + mt::Signal loop_finished; |
573 | + |
574 | + ml.enqueue( |
575 | + nullptr, |
576 | + [&loop_running]() { loop_running.raise(); }); |
577 | + |
578 | + mt::AutoJoinThread t{ |
579 | + [&] |
580 | + { |
581 | + ml.run(); |
582 | + loop_finished.raise(); |
583 | + }}; |
584 | + |
585 | + ASSERT_TRUE(loop_running.wait_for(std::chrono::seconds{5})); |
586 | + |
587 | + ml.enqueue_with_guaranteed_execution( |
588 | + [main_thread = std::this_thread::get_id()]() |
589 | + { |
590 | + EXPECT_THAT(std::this_thread::get_id(), Ne(main_thread)); |
591 | + }); |
592 | + |
593 | + ml.stop(); |
594 | + |
595 | + EXPECT_TRUE(loop_finished.wait_for(std::chrono::seconds{30})); |
596 | +} |
597 | + |
598 | namespace |
599 | { |
600 |
FAILED: Continuous integration, rev:4292 /mir-jenkins. ubuntu. com/job/ mir-ci/ 3714/ /mir-jenkins. ubuntu. com/job/ build-mir/ 5095/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/5333 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= artful/ 5320 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial/ 5320 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= zesty/5320 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= artful/ 5139/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= zesty/5139/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= artful/ 5139/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial/ 5139/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= zesty/5139/ console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= artful/ 5139 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= artful/ 5139/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= zesty/5139 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= mesa,release= zesty/5139/ artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial/ 5139/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 3714/rebuild
https:/