~andreas-pokorny/mir/server_module_type_detection

« back to all changes in this revision

Viewing changes to tests/unit-tests/compositor/test_timeout_frame_dropping_policy.cpp

  • Committer: Tarmac
  • Author(s): Alberto Aguirre
  • Date: 2015-02-23 11:36:36 UTC
  • mfrom: (2323.3.9 fix-1421255)
  • Revision ID: tarmac-20150223113636-nx30z7716o43xyo6
Fix deadlock caused by lock ordering issues.

The framedropping policy acquires an internal lock while invoking the user callback. BufferQueue calls framedrop policy methods while holding its own lock; the callback implementation given to the policy also acquires the same lock which results in a classic lock ordering deadlock issue.

To avoid such lock order issues, the framedrop policy and alarm factory interfaces expose an additional API to allow users to pass in lock/unlock functions, which can then be used by the callback dispatching context to preserve lock ordering. Fixes: https://bugs.launchpad.net/bugs/1421255.

Approved by Kevin DuBois, PS Jenkins bot, Alan Griffiths.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright © 2014 Canonical Ltd.
 
2
 * Copyright © 2014-2015 Canonical Ltd.
3
3
 *
4
4
 * This program is free software: you can redistribute it and/or modify it
5
5
 * under the terms of the GNU General Public License version 3,
14
14
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15
15
 *
16
16
 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
 
17
 *              Alberto Aguirre <alberto.aguirre@canonical.com>
17
18
 */
18
19
 
19
20
#include "src/server/compositor/timeout_frame_dropping_policy_factory.h"
20
21
#include "mir/compositor/frame_dropping_policy.h"
21
22
 
22
23
#include "mir_test_doubles/mock_timer.h"
23
 
 
 
24
#include "mir_test/auto_unblock_thread.h"
24
25
#include "mir_test/gmock_fixes.h"
25
26
 
26
27
#include <stdexcept>
 
28
#include <mutex>
27
29
 
28
30
#include <gtest/gtest.h>
29
31
#include <gmock/gmock.h>
40
42
    bool frame_dropped{false};
41
43
 
42
44
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
43
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
45
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
44
46
 
45
47
    clock->advance_time(timeout + std::chrono::milliseconds{1});
46
48
    EXPECT_FALSE(frame_dropped);
54
56
    bool frame_dropped{false};
55
57
 
56
58
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
57
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
59
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
58
60
    policy->swap_now_blocking();
59
61
 
60
62
    clock->advance_time(timeout - std::chrono::milliseconds{1});
71
73
 
72
74
    bool frame_dropped{false};
73
75
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
74
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
76
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
75
77
 
76
78
    policy->swap_now_blocking();
77
79
    policy->swap_unblocked();
89
91
 
90
92
    bool frame_dropped{false};
91
93
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
92
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
94
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
93
95
 
94
96
    policy->swap_now_blocking();
95
97
    policy->swap_now_blocking();
119
121
 
120
122
    bool frame_dropped{false};
121
123
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
122
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
124
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
123
125
 
124
126
    policy->swap_now_blocking();
125
127
    policy->swap_now_blocking();
142
144
 
143
145
    bool frame_dropped{false};
144
146
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
145
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
147
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
146
148
 
147
149
    policy->swap_now_blocking();
148
150
    clock->advance_time(timeout - std::chrono::milliseconds{1});
160
162
 
161
163
    bool frame_dropped{false};
162
164
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
163
 
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; });
 
165
    auto policy = factory.create_policy([&frame_dropped]{ frame_dropped = true; }, []{}, []{});
164
166
 
165
167
    policy->swap_now_blocking();
166
168
    policy->swap_now_blocking();
184
186
    clock->advance_time(timeout + std::chrono::milliseconds{1});
185
187
    EXPECT_FALSE(frame_dropped);
186
188
}
 
189
 
 
190
TEST(TimeoutFrameDroppingPolicy, policy_calls_lock_unlock_functions)
 
191
{
 
192
    using namespace testing;
 
193
 
 
194
    auto clock = std::make_shared<mt::FakeClock>();
 
195
    auto timer = std::make_shared<mtd::FakeTimer>(clock);
 
196
    std::chrono::milliseconds const timeout{1000};
 
197
 
 
198
    mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};
 
199
 
 
200
    std::mutex m;
 
201
    std::unique_lock<std::mutex> handler_guard{m, std::defer_lock};
 
202
 
 
203
    auto policy = factory.create_policy([&]
 
204
    {
 
205
        EXPECT_THAT(handler_guard.owns_lock(), Eq(true));
 
206
    },
 
207
    [&] { handler_guard.lock(); },
 
208
    [&] { handler_guard.unlock(); });
 
209
 
 
210
 
 
211
    policy->swap_now_blocking();
 
212
    clock->advance_time(timeout + std::chrono::milliseconds{1});
 
213
}