Mir

Merge lp:~robertcarr/mir/fix-surface-stack-input-locking into lp:~mir-team/mir/trunk

Proposed by Robert Carr
Status: Merged
Approved by: Alexandros Frantzis
Approved revision: no longer in the source branch.
Merged at revision: 716
Proposed branch: lp:~robertcarr/mir/fix-surface-stack-input-locking
Merge into: lp:~mir-team/mir/trunk
Diff against target: 38 lines (+8/-3)
1 file modified
src/server/surfaces/surface_stack.cpp (+8/-3)
To merge this branch: bzr merge lp:~robertcarr/mir/fix-surface-stack-input-locking
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve
Alan Griffiths Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+166852@code.launchpad.net

Commit message

Fix locking around SurfaceStack::for_each(InputTargets)

Description of the change

Obviouly, ms::SurfaceStack::for_each (From the InputTargets) interface requires a lock. Now we must be wary of deadlock

In particular note the changes to ms::SurfaceStack::destroy_surface. The dead locking scenario fixed shows up moving the cursor over the stress test: InputDispatcher begins processing picking motion event target in response to cursor motion(taking lock). While the InputDispatcher is procesing this event but BEFORE it calls ms::Surfacetack::for_each through the target enumerator, the surface is destroyed. In ms::SurfaceStack::destroy_surface we take the surface stack lock, and call input_registrar->input_surface_closed. This attempts to call InputDispatcher::unregisterInputChannel, blocking on the lock from the in-procgress event targeting! However the event targeting can never finish as it will next have to call ms::SurfaceStack::lock (held by the blocked call to input_surface_closed).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

The point of the change to SurfaceStack::destroy_surface() is to re-order the input_registrar->input_surface_closed() and erase() calls?

Isn't that clearer with:

void ms::SurfaceStack::destroy_surface(std::weak_ptr<ms::Surface> const& surface)
{
    {
        std::lock_guard<std::mutex> lg(guard);

        auto const p = std::find(surfaces.begin(), surfaces.end(), surface.lock());

        if (p != surfaces.end())
        {
            auto keep_alive = *p;
            surfaces.erase(p);
            input_registrar->input_surface_closed(keep_alive);
        }
        // else; TODO error logging
    }

    emit_change_notification();
}

review: Approve
Revision history for this message
Robert Carr (robertcarr) wrote :

Not just to reorder. The call to the input registrar needs to be made outside of the surface stack lock.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good. Perhaps a comment in ms::SurfaceStack::for_each(), that we are not allowed to directly or indirectly access the SurfaceStack in the callback.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/surfaces/surface_stack.cpp'
2--- src/server/surfaces/surface_stack.cpp 2013-05-23 18:03:04 +0000
3+++ src/server/surfaces/surface_stack.cpp 2013-05-31 16:42:24 +0000
4@@ -96,6 +96,7 @@
5
6 void ms::SurfaceStack::destroy_surface(std::weak_ptr<ms::Surface> const& surface)
7 {
8+ auto keep_alive = surface.lock();
9 {
10 std::lock_guard<std::mutex> lg(guard);
11
12@@ -103,12 +104,15 @@
13
14 if (p != surfaces.end())
15 {
16- input_registrar->input_surface_closed(*p);
17 surfaces.erase(p);
18 }
19- // else; TODO error logging
20+ else
21+ {
22+ // else; TODO error logging
23+ return;
24+ }
25 }
26-
27+ input_registrar->input_surface_closed(keep_alive);
28 emit_change_notification();
29 }
30
31@@ -120,6 +124,7 @@
32
33 void ms::SurfaceStack::for_each(std::function<void(std::shared_ptr<mi::SurfaceTarget> const&)> const& callback)
34 {
35+ std::lock_guard<std::mutex> lg(guard);
36 for (auto it = surfaces.rbegin(); it != surfaces.rend(); ++it)
37 callback(*it);
38 }

Subscribers

People subscribed via source and target branches