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
1=== modified file 'src/server/graphics/nested/input_platform.cpp'
2--- src/server/graphics/nested/input_platform.cpp 2017-03-03 07:08:58 +0000
3+++ src/server/graphics/nested/input_platform.cpp 2017-03-08 15:05:26 +0000
4@@ -338,34 +338,9 @@
5 {
6 std::lock_guard<std::mutex> lock(devices_guard);
7 if (!devices.empty())
8- {
9- auto const* device_state = mir_event_get_input_device_state_event(&event);
10- for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state);
11- index != end_index; ++index)
12- {
13- auto it = devices.find(mir_input_device_state_event_device_id(device_state, index));
14- if (it != end(devices) && it->second->destination)
15- {
16- auto dest = it->second->destination;
17- auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
18- std::vector<uint32_t> scan_codes;
19- for (uint32_t i = 0; i < key_count; i++)
20- {
21- scan_codes.push_back(mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i));
22- }
23-
24- dest->key_state(scan_codes);
25- dest->pointer_state(
26- mir_input_device_state_event_device_pointer_buttons(device_state, index));
27- }
28- }
29-
30- auto& front = begin(devices)->second;
31- auto device_state_event = front->builder->device_state_event(
32- mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x),
33- mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y));
34- front->destination->handle_input(*device_state_event);
35- }
36+ handle_device_state(event);
37+ else
38+ early_device_states.push_back(mir::events::clone_event(event));
39 }
40 });
41 }
42@@ -421,7 +396,13 @@
43 for (auto new_dev : new_devs)
44 {
45 input_device_registry->add_device(new_dev.first);
46-
47+ }
48+ for (auto const& event : early_device_states)
49+ {
50+ handle_device_state(*event);
51+ }
52+ for (auto new_dev : new_devs)
53+ {
54 auto early_event_queue = unknown_device_events.find(new_dev.second);
55 if (early_event_queue != end(unknown_device_events))
56 {
57@@ -433,6 +414,7 @@
58 }
59 }
60 unknown_device_events.clear();
61+ early_device_states.clear();
62 }
63
64 void mgn::InputPlatform::config_changed()
65@@ -461,3 +443,33 @@
66 }
67 state = started;
68 }
69+
70+void mgn::InputPlatform::handle_device_state(MirEvent const& event)
71+{
72+ auto const* device_state = mir_event_get_input_device_state_event(&event);
73+ for (size_t index = 0, end_index = mir_input_device_state_event_device_count(device_state);
74+ index != end_index; ++index)
75+ {
76+ auto it = devices.find(mir_input_device_state_event_device_id(device_state, index));
77+ if (it != end(devices) && it->second->destination)
78+ {
79+ auto dest = it->second->destination;
80+ auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index);
81+ std::vector<uint32_t> scan_codes;
82+ for (uint32_t i = 0; i < key_count; i++)
83+ {
84+ scan_codes.push_back(mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i));
85+ }
86+
87+ dest->key_state(scan_codes);
88+ dest->pointer_state(
89+ mir_input_device_state_event_device_pointer_buttons(device_state, index));
90+ }
91+ }
92+
93+ auto& front = begin(devices)->second;
94+ auto device_state_event = front->builder->device_state_event(
95+ mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x),
96+ mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y));
97+ front->destination->handle_input(*device_state_event);
98+}
99
100=== modified file 'src/server/graphics/nested/input_platform.h'
101--- src/server/graphics/nested/input_platform.h 2017-02-15 07:38:33 +0000
102+++ src/server/graphics/nested/input_platform.h 2017-03-08 15:05:26 +0000
103@@ -58,6 +58,7 @@
104 void config_changed();
105 void update_devices();
106 void update_devices_locked();
107+ void handle_device_state(MirEvent const& event);
108 struct InputDevice;
109 std::shared_ptr<HostConnection> const connection;
110 std::shared_ptr<input::InputDeviceRegistry> const input_device_registry;
111@@ -70,6 +71,7 @@
112 std::unordered_map<MirInputDeviceId, std::shared_ptr<InputDevice>> devices;
113 std::unordered_map<MirInputDeviceId, std::vector<std::pair<EventUPtr, mir::geometry::Rectangle>>>
114 unknown_device_events;
115+ std::vector<EventUPtr> early_device_states;
116 enum State
117 {
118 started, stopped, paused

Subscribers

People subscribed via source and target branches