Mir

Merge lp:~andreas-pokorny/mir/wait-for-input-config-before-emitting-input-state into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Merged at revision: 4112
Proposed branch: lp:~andreas-pokorny/mir/wait-for-input-config-before-emitting-input-state
Merge into: lp:mir
Diff against target: 118 lines (+43/-29)
2 files modified
src/server/graphics/nested/input_platform.cpp (+41/-29)
src/server/graphics/nested/input_platform.h (+2/-0)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/wait-for-input-config-before-emitting-input-state
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Needs Information
Mir CI Bot continuous-integration Approve
Review via email: mp+319328@code.launchpad.net

Commit message

Wait for the arrival of the input config message before attempting to propagate input device state events

The former informs the nested server about the available devices, the latter is supposed to synchronize the host server input state with the focused client (here the nested server).

When launching the nested server there is a potential race between the initial input device state event and the input config. This problem is most visible when vt switching. Since the per-surface input fds have been removed, and all events are sent to the connection this race is harder to notice. Still the two messages may be sent by different threads in the server. This should be the last cause for the two prominent CI failures mentioned.

Description of the change

This race was found while working on the issue with stuck alt keys.

There are two messages involved. One indicates which input devices are available in the system. The one is treated as an Event the InputDeviceStateEvent, which provides the current input status like cursor position, pointer buttons, modifier state and pressed keys.

In the past a reordering of that was easy to trigger because it involved separate fds, now it requires a specific scheduling on the server, which happens frequently when trying to simulate pause/resume behavior.

Maybe the attached bugs have already been fixed or are just more rare due to other changes:
* removal of the per-surface fds
* updated surface input dispatcher logic in mir::input::SurfaceInputDispatcher::for_each)

Nonetheless the change here is related to the two linked problems.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4069
https://mir-jenkins.ubuntu.com/job/mir-ci/3114/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4177
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4264
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/4254
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4254
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4254
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4204
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4204/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4204
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4204/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4204
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4204/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4204
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/4204/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4204
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/4204/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4204
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4204/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3114/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

The root cause of this issue is that the server-client information exchange does not enforce the required order. It would be preferable if we fixed the out of order issue in the server, rather than implementing what is essentially a workaround in the client. Is this feasible?

Also, is there the possibility of this race occurring after we already have some input devices (i.e. a devices is added after startup and the state event reaches the client before the input-config event)? If so, the workaround is not enough, since it is only applied when devices.empty() == true.

review: Needs Information
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

> The root cause of this issue is that the server-client information exchange
> does not enforce the required order. It would be preferable if we fixed the
> out of order issue in the server, rather than implementing what is essentially
> a workaround in the client. Is this feasible?

The MP here seemed like the easy fix to get the follow up parts working.

> Also, is there the possibility of this race occurring after we already have
> some input devices (i.e. a devices is added after startup and the state event
> reaches the client before the input-config event)? If so, the workaround is
> not enough, since it is only applied when devices.empty() == true.

Sounds right..

I will try to change the way the input device changes are handled in the server... currently through an observer in the main thread .. vs the input thread..

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

So should this be work in progress now?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/server/graphics/nested/input_platform.cpp'
--- src/server/graphics/nested/input_platform.cpp 2017-03-03 07:08:58 +0000
+++ src/server/graphics/nested/input_platform.cpp 2017-03-08 15:05:26 +0000
@@ -338,34 +338,9 @@
338 {338 {
339 std::lock_guard<std::mutex> lock(devices_guard);339 std::lock_guard<std::mutex> lock(devices_guard);
340 if (!devices.empty())340 if (!devices.empty())
341 {341 handle_device_state(event);
342 auto const* device_state = mir_event_get_input_device_state_event(&event);342 else
343 for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state);343 early_device_states.push_back(mir::events::clone_event(event));
344 index != end_index; ++index)
345 {
346 auto it = devices.find(mir_input_device_state_event_device_id(device_state, index));
347 if (it != end(devices) && it->second->destination)
348 {
349 auto dest = it->second->destination;
350 auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
351 std::vector<uint32_t> scan_codes;
352 for (uint32_t i = 0; i < key_count; i++)
353 {
354 scan_codes.push_back(mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i));
355 }
356
357 dest->key_state(scan_codes);
358 dest->pointer_state(
359 mir_input_device_state_event_device_pointer_buttons(device_state, index));
360 }
361 }
362
363 auto& front = begin(devices)->second;
364 auto device_state_event = front->builder->device_state_event(
365 mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x),
366 mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y));
367 front->destination->handle_input(*device_state_event);
368 }
369 }344 }
370 });345 });
371}346}
@@ -421,7 +396,13 @@
421 for (auto new_dev : new_devs)396 for (auto new_dev : new_devs)
422 {397 {
423 input_device_registry->add_device(new_dev.first);398 input_device_registry->add_device(new_dev.first);
424399 }
400 for (auto const& event : early_device_states)
401 {
402 handle_device_state(*event);
403 }
404 for (auto new_dev : new_devs)
405 {
425 auto early_event_queue = unknown_device_events.find(new_dev.second);406 auto early_event_queue = unknown_device_events.find(new_dev.second);
426 if (early_event_queue != end(unknown_device_events))407 if (early_event_queue != end(unknown_device_events))
427 {408 {
@@ -433,6 +414,7 @@
433 }414 }
434 }415 }
435 unknown_device_events.clear();416 unknown_device_events.clear();
417 early_device_states.clear();
436}418}
437419
438void mgn::InputPlatform::config_changed()420void mgn::InputPlatform::config_changed()
@@ -461,3 +443,33 @@
461 }443 }
462 state = started;444 state = started;
463}445}
446
447void mgn::InputPlatform::handle_device_state(MirEvent const& event)
448{
449 auto const* device_state = mir_event_get_input_device_state_event(&event);
450 for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state);
451 index != end_index; ++index)
452 {
453 auto it = devices.find(mir_input_device_state_event_device_id(device_state, index));
454 if (it != end(devices) && it->second->destination)
455 {
456 auto dest = it->second->destination;
457 auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
458 std::vector<uint32_t> scan_codes;
459 for (uint32_t i = 0; i < key_count; i++)
460 {
461 scan_codes.push_back(mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i));
462 }
463
464 dest->key_state(scan_codes);
465 dest->pointer_state(
466 mir_input_device_state_event_device_pointer_buttons(device_state, index));
467 }
468 }
469
470 auto& front = begin(devices)->second;
471 auto device_state_event = front->builder->device_state_event(
472 mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x),
473 mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y));
474 front->destination->handle_input(*device_state_event);
475}
464476
=== modified file 'src/server/graphics/nested/input_platform.h'
--- src/server/graphics/nested/input_platform.h 2017-02-15 07:38:33 +0000
+++ src/server/graphics/nested/input_platform.h 2017-03-08 15:05:26 +0000
@@ -58,6 +58,7 @@
58 void config_changed();58 void config_changed();
59 void update_devices();59 void update_devices();
60 void update_devices_locked();60 void update_devices_locked();
61 void handle_device_state(MirEvent const& event);
61 struct InputDevice;62 struct InputDevice;
62 std::shared_ptr<HostConnection> const connection;63 std::shared_ptr<HostConnection> const connection;
63 std::shared_ptr<input::InputDeviceRegistry> const input_device_registry;64 std::shared_ptr<input::InputDeviceRegistry> const input_device_registry;
@@ -70,6 +71,7 @@
70 std::unordered_map<MirInputDeviceId, std::shared_ptr<InputDevice>> devices;71 std::unordered_map<MirInputDeviceId, std::shared_ptr<InputDevice>> devices;
71 std::unordered_map<MirInputDeviceId, std::vector<std::pair<EventUPtr, mir::geometry::Rectangle>>>72 std::unordered_map<MirInputDeviceId, std::vector<std::pair<EventUPtr, mir::geometry::Rectangle>>>
72 unknown_device_events;73 unknown_device_events;
74 std::vector<EventUPtr> early_device_states;
73 enum State75 enum State
74 {76 {
75 started, stopped, paused77 started, stopped, paused

Subscribers

People subscribed via source and target branches