Mir

Merge lp:~albaguirre/mir/fix-1421255 into lp:mir

Proposed by Alberto Aguirre
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 2335
Proposed branch: lp:~albaguirre/mir/fix-1421255
Merge into: lp:mir
Diff against target: 1283 lines (+368/-132)
23 files modified
include/server/mir/time/timer.h (+28/-4)
src/include/server/mir/compositor/frame_dropping_policy_factory.h (+22/-5)
src/include/server/mir/glib_main_loop.h (+11/-6)
src/include/server/mir/glib_main_loop_sources.h (+3/-1)
src/server/compositor/buffer_queue.cpp (+28/-13)
src/server/compositor/buffer_queue.h (+12/-4)
src/server/compositor/timeout_frame_dropping_policy_factory.cpp (+17/-9)
src/server/compositor/timeout_frame_dropping_policy_factory.h (+6/-2)
src/server/glib_main_loop.cpp (+23/-6)
src/server/glib_main_loop_sources.cpp (+15/-3)
tests/include/mir_test_doubles/mock_frame_dropping_policy_factory.h (+23/-4)
tests/include/mir_test_doubles/mock_main_loop.h (+14/-6)
tests/include/mir_test_doubles/mock_timer.h (+7/-5)
tests/include/mir_test_doubles/stub_frame_dropping_policy_factory.h (+7/-3)
tests/include/mir_test_doubles/stub_timer.h (+3/-3)
tests/include/mir_test_doubles/triggered_main_loop.h (+1/-1)
tests/mir_test_doubles/mock_frame_dropping_policy_factory.cpp (+12/-4)
tests/mir_test_doubles/mock_timer.cpp (+38/-15)
tests/mir_test_doubles/triggered_main_loop.cpp (+3/-2)
tests/unit-tests/compositor/test_buffer_queue.cpp (+10/-1)
tests/unit-tests/compositor/test_timeout_frame_dropping_policy.cpp (+36/-9)
tests/unit-tests/test_glib_main_loop.cpp (+29/-26)
tests/unit-tests/test_raii.cpp (+20/-0)
To merge this branch: bzr merge lp:~albaguirre/mir/fix-1421255
Reviewer Review Type Date Requested Status
Kevin DuBois (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Approve
Review via email: mp+250182@code.launchpad.net

Commit message

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.

Description of the change

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.

The alternatives include:
- Avoid holding a lock while dispatching callback
--- Lifetime of objects gets tricky when trying to destroy the underlying TimerGSource and releated resources.
- Make async versions of the current alarm APIs (reschedule APIs have an implicit cancel operation)
--- Needs some sort of garbage collector of GSourceHandles (to keep existing implementation)
--- or rework of TimerGSource and md::add_timer_gsource to be able to handle an async cancel call with all the object lifetime issues it opens up.

This approach was chosen because:
- Solves the actual root cause - lock ordering
- It's a bit easier to reason about than the alternatives; Object lifetimes concerns are already addressed by existing code

To post a comment you must log in.
Revision history for this message
Kevin DuBois (kdub) wrote :

211 + [this] { guard_lock = std::move(std::unique_lock<decltype(guard)>{guard}); },
212 + []{});
It seems strange that if I were to call:
lock();
unlock();
lock()
The second lock call would block, because we haven't called the callback, which is what will end up releasing the lock.

594 + CallerAutoLock caller_lock{ctx.lock, ctx.unlock};
Could mir/raii.h help reduce diff? (and don't need CallerAutoLock)

99 + virtual std::unique_ptr<FrameDroppingPolicy> create_policy(std::function<void()> const& drop_frame) const = 0;
119 + virtual std::unique_ptr<FrameDroppingPolicy> create_policy(
120 + std::function<void()> const& drop_frame,
121 + std::function<void()> const& lock,
122 + std::function<void()> const& unlock) const = 0;
I guess I'd rather just keep one function (the latter), and 3 parameters in create_policy seem like they're becoming an interface that meets the requirements of BasicLockable.

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

The mir-mediumtests-runner-mako job failed due to a failed device. I've restarted the mir-ci job.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

A simpler and guaranteed more reliable solution would be to move away from a pure callback approach (which we use in many places)...

Instead, if we replaced such logic:
   call callback(args)
with:
   signal event(args)
then there is zero risk of deadlocks.

Receivers could then wait for an event, multiple events, or even join a thread pool that turns events into callbacks if they want to work that way. But the important point is even in the callback case then, the thread making the callback has no risk of causing deadlocks. Because it's dedicated just to making unlocked callbacks and nothing else. But of course, it's more efficient to not need additional threads too.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> A simpler and guaranteed more reliable solution would be to move away from a
> pure callback approach (which we use in many places)...
>
> Instead, if we replaced such logic:
> call callback(args)
> with:
> signal event(args)
> then there is zero risk of deadlocks.
>

How would that be simpler? I guess simpler in which respect? Development, maintenance, usage?

A high level event-hub concept cannot guarantee zero deadlocks however, that's an implementation detail.

Maybe such an event hub could just post and dispatch events through the main loop to save a thread.

In any case, that's probably a much bigger re-factoring than what is proposed here.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> 211 + [this] { guard_lock =
> std::move(std::unique_lock<decltype(guard)>{guard}); },
> 212 + []{});
> It seems strange that if I were to call:
> lock();
> unlock();
> lock()
> The second lock call would block, because we haven't called the callback,
> which is what will end up releasing the lock.

OK, I suppose I can change BufferQueue private methods to take a unique_lock reference instead
of value, so I don't have to move the instance and consequently I can use it in the "unlock" lambda.

> 594 + CallerAutoLock caller_lock{ctx.lock, ctx.unlock};
> Could mir/raii.h help reduce diff? (and don't need CallerAutoLock)

I tried, but couldn't figure out why paired_call did not like std::function. I'll try harder I suppose :)

> 99 + virtual std::unique_ptr<FrameDroppingPolicy>
> create_policy(std::function<void()> const& drop_frame) const = 0;
> 119 + virtual std::unique_ptr<FrameDroppingPolicy> create_policy(
> 120 + std::function<void()> const& drop_frame,
> 121 + std::function<void()> const& lock,
> 122 + std::function<void()> const& unlock) const = 0;
>
> I guess I'd rather just keep one function (the latter), and 3 parameters in
> create_policy seem like they're becoming an interface that meets the
> requirements of BasicLockable.

OK. Maybe a LockableCallable?

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Ran out of time trying to understand. Will look again tomorrow if it doesn't land meanwhile.

review: Abstain
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

This seems elaborate and easy to make mistakes using but I don't have a better suggestion (yet).

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> This seems elaborate and easy to make mistakes using but I don't have a better
> suggestion (yet).

Yeah but no different that what we currently have (i.e. easy to make mistakes too).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

seems the issues were addressed, so okay by me. This buffer queue code has gotten hard to understand again, but thats a pre-existing issue.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/server/mir/time/timer.h'
--- include/server/mir/time/timer.h 2015-01-21 07:34:50 +0000
+++ include/server/mir/time/timer.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
1920
@@ -47,7 +48,7 @@
47 * \return A handle to an Alarm that will fire after delay ms.48 * \return A handle to an Alarm that will fire after delay ms.
48 */49 */
49 virtual std::unique_ptr<Alarm> notify_in(std::chrono::milliseconds delay,50 virtual std::unique_ptr<Alarm> notify_in(std::chrono::milliseconds delay,
50 std::function<void()> callback) = 0;51 std::function<void()> const& callback) = 0;
51 /**52 /**
52 * \brief Create an Alarm that calls the callback at the specified time53 * \brief Create an Alarm that calls the callback at the specified time
53 *54 *
@@ -57,7 +58,7 @@
57 * \return A handle to an Alarm that will fire after delay ms.58 * \return A handle to an Alarm that will fire after delay ms.
58 */59 */
59 virtual std::unique_ptr<Alarm> notify_at(Timestamp time_point,60 virtual std::unique_ptr<Alarm> notify_at(Timestamp time_point,
60 std::function<void()> callback) = 0;61 std::function<void()> const& callback) = 0;
61 /**62 /**
62 * \brief Create an Alarm that will not fire until scheduled63 * \brief Create an Alarm that will not fire until scheduled
63 *64 *
@@ -65,7 +66,30 @@
65 *66 *
66 * \return A handle to an Alarm that can later be scheduled67 * \return A handle to an Alarm that can later be scheduled
67 */68 */
68 virtual std::unique_ptr<Alarm> create_alarm(std::function<void()> callback) = 0;69 virtual std::unique_ptr<Alarm> create_alarm(std::function<void()> const& callback) = 0;
70
71 /**
72 * \brief Create an Alarm that will not fire until scheduled
73 *
74 * The lock/unlock functions allow the user to preserve lock ordering
75 * in situations where Alarm methods need to be called under external lock
76 * and the callback implementation needs to run code protected by the same
77 * lock. An alarm implementation may have internal locks of its own, which
78 * maybe acquired during callback dispatching; to preserve lock ordering
79 * the given lock function will be invoked during callback dispatch before
80 * any internal locks are acquired.
81 *
82 * \param callback Function to call when the Alarm signals
83 * \param lock Function called within callback dispatching context
84 * before the alarm implementation acquires any internal
85 * lock
86 * \param unlock Function called within callback dispatching context after
87 * the alarm implementation releases any internal lock
88 *
89 * \return A handle to an Alarm that can later be scheduled
90 */
91 virtual std::unique_ptr<Alarm> create_alarm(std::function<void()> const& callback,
92 std::function<void()> const& lock, std::function<void()> const& unlock) = 0;
6993
70 Timer(Timer const&) = delete;94 Timer(Timer const&) = delete;
71 Timer& operator=(Timer const&) = delete;95 Timer& operator=(Timer const&) = delete;
7296
=== modified file 'src/include/server/mir/compositor/frame_dropping_policy_factory.h'
--- src/include/server/mir/compositor/frame_dropping_policy_factory.h 2015-01-21 07:34:50 +0000
+++ src/include/server/mir/compositor/frame_dropping_policy_factory.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#ifndef MIR_COMPOSITOR_FRAME_DROPPING_POLICY_FACTORY_H_20#ifndef MIR_COMPOSITOR_FRAME_DROPPING_POLICY_FACTORY_H_
@@ -44,11 +45,27 @@
44 FrameDroppingPolicyFactory& operator=(FrameDroppingPolicyFactory const&) = delete;45 FrameDroppingPolicyFactory& operator=(FrameDroppingPolicyFactory const&) = delete;
4546
46 /**47 /**
47 * \brief Create a FrameDroppingPolicy that will call \a drop_frame when it decides to drop a frame48 * \brief Create a FrameDroppingPolicy that will call \a drop_frame when it
48 * \param drop_frame Function to call when a frame needs to be dropped49 * decides to drop a frame
49 * \return The policy object.50 *
51 * The lock/unlock functions allow the user to preserve lock ordering
52 * in situations where FrameDroppingPolicy methods need to be called under
53 * external lock and the callback implementation needs to run code protected
54 * by the same lock. A FrameDroppingPolicy implementation may have internal
55 * locks of its own, which maybe acquired during callback dispatching;
56 * to preserve lock ordering the given lock function will be invoked during
57 * callback dispatch before any internal locks are acquired.
58 *
59 * \param drop_frame Function to call when a frame needs to be dropped
60 * \param lock Function called within the callback dispatcher context
61 * before any internal locks are acquired.
62 * \param unlock Function called within the callback dispatcher context
63 * after any internal locks are released.
50 */64 */
51 virtual std::unique_ptr<FrameDroppingPolicy> create_policy(std::function<void(void)> drop_frame) const = 0;65 virtual std::unique_ptr<FrameDroppingPolicy> create_policy(
66 std::function<void()> const& drop_frame,
67 std::function<void()> const& lock,
68 std::function<void()> const& unlock) const = 0;
52};69};
5370
54}71}
5572
=== modified file 'src/include/server/mir/glib_main_loop.h'
--- src/include/server/mir/glib_main_loop.h 2015-01-21 07:34:50 +0000
+++ src/include/server/mir/glib_main_loop.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -72,14 +72,19 @@
7272
73 std::unique_ptr<mir::time::Alarm> notify_in(73 std::unique_ptr<mir::time::Alarm> notify_in(
74 std::chrono::milliseconds delay,74 std::chrono::milliseconds delay,
75 std::function<void()> callback) override;75 std::function<void()> const& callback) override;
7676
77 std::unique_ptr<mir::time::Alarm> notify_at(77 std::unique_ptr<mir::time::Alarm> notify_at(
78 mir::time::Timestamp t,78 mir::time::Timestamp t,
79 std::function<void()> callback) override;79 std::function<void()> const& callback) override;
8080
81 std::unique_ptr<mir::time::Alarm> create_alarm(81 std::unique_ptr<mir::time::Alarm> create_alarm(
82 std::function<void()> callback) override;82 std::function<void()> const& callback) override;
83
84 std::unique_ptr<mir::time::Alarm> create_alarm(
85 std::function<void()> const& callback,
86 std::function<void()> const& lock,
87 std::function<void()> const& unlock) override;
8388
84 void reprocess_all_sources();89 void reprocess_all_sources();
8590
8691
=== modified file 'src/include/server/mir/glib_main_loop_sources.h'
--- src/include/server/mir/glib_main_loop_sources.h 2015-02-13 06:12:34 +0000
+++ src/include/server/mir/glib_main_loop_sources.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -74,6 +74,8 @@
74 GMainContext* main_context,74 GMainContext* main_context,
75 std::shared_ptr<time::Clock> const& clock,75 std::shared_ptr<time::Clock> const& clock,
76 std::function<void()> const& handler,76 std::function<void()> const& handler,
77 std::function<void()> const& lock,
78 std::function<void()> const& unlock,
77 time::Timestamp target_time);79 time::Timestamp target_time);
7880
79class FdSources81class FdSources
8082
=== modified file 'src/server/compositor/buffer_queue.cpp'
--- src/server/compositor/buffer_queue.cpp 2015-02-17 06:38:35 +0000
+++ src/server/compositor/buffer_queue.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -132,11 +132,18 @@
132 if (nbuffers == 1)132 if (nbuffers == 1)
133 free_buffers.push_back(current_compositor_buffer);133 free_buffers.push_back(current_compositor_buffer);
134134
135 // A lock_guard will be created by the policy dispatcher invoking the given "lock" lambda
136 // before it acquires any internal locks of its own.
135 framedrop_policy = policy_provider.create_policy([this]137 framedrop_policy = policy_provider.create_policy([this]
136 {138 {
137 std::unique_lock<decltype(guard)> lock{guard};139 // We ignore any ongoing snapshotting as it could lead to deadlock.
138 drop_frame(std::move(lock));140 // In order to wait the guard_lock needs to be released; a BufferQueue::release
139 });141 // call can sneak in at that time from a different thread which
142 // can invoke framedrop_policy methods
143 drop_frame(guard_lock, ignore_snapshot);
144 },
145 [this] { guard_lock = std::move(std::unique_lock<decltype(guard)>{guard}); },
146 [this] { if (guard_lock.owns_lock()) guard_lock.unlock(); });
140}147}
141148
142void mc::BufferQueue::client_acquire(mc::BufferQueue::Callback complete)149void mc::BufferQueue::client_acquire(mc::BufferQueue::Callback complete)
@@ -149,7 +156,7 @@
149 {156 {
150 auto const buffer = free_buffers.back();157 auto const buffer = free_buffers.back();
151 free_buffers.pop_back();158 free_buffers.pop_back();
152 give_buffer_to_client(buffer, std::move(lock));159 give_buffer_to_client(buffer, lock);
153 return;160 return;
154 }161 }
155162
@@ -162,14 +169,14 @@
162 {169 {
163 auto const& buffer = gralloc->alloc_buffer(the_properties);170 auto const& buffer = gralloc->alloc_buffer(the_properties);
164 buffers.push_back(buffer);171 buffers.push_back(buffer);
165 give_buffer_to_client(buffer.get(), std::move(lock));172 give_buffer_to_client(buffer.get(), lock);
166 return;173 return;
167 }174 }
168175
169 /* Last resort, drop oldest buffer from the ready queue */176 /* Last resort, drop oldest buffer from the ready queue */
170 if (frame_dropping_enabled)177 if (frame_dropping_enabled)
171 {178 {
172 drop_frame(std::move(lock));179 drop_frame(lock, wait_for_snapshot);
173 return;180 return;
174 }181 }
175182
@@ -323,7 +330,7 @@
323 {330 {
324 free_buffers.push_back(pop(ready_to_composite_queue));331 free_buffers.push_back(pop(ready_to_composite_queue));
325 }332 }
326 give_buffer_to_client(buffer, std::move(lock));333 give_buffer_to_client(buffer, lock, ignore_snapshot);
327 }334 }
328}335}
329336
@@ -363,7 +370,15 @@
363370
364void mc::BufferQueue::give_buffer_to_client(371void mc::BufferQueue::give_buffer_to_client(
365 mg::Buffer* buffer,372 mg::Buffer* buffer,
366 std::unique_lock<std::mutex> lock)373 std::unique_lock<std::mutex>& lock)
374{
375 give_buffer_to_client(buffer, lock, wait_for_snapshot);
376}
377
378void mc::BufferQueue::give_buffer_to_client(
379 mg::Buffer* buffer,
380 std::unique_lock<std::mutex>& lock,
381 SnapshotWait wait_type)
367{382{
368 /* Clears callback */383 /* Clears callback */
369 auto give_to_client_cb = std::move(pending_client_notifications.front());384 auto give_to_client_cb = std::move(pending_client_notifications.front());
@@ -383,7 +398,7 @@
383 }398 }
384399
385 /* Don't give to the client just yet if there's a pending snapshot */400 /* Don't give to the client just yet if there's a pending snapshot */
386 if (!resize_buffer && contains(buffer, pending_snapshots))401 if (wait_type == wait_for_snapshot && !resize_buffer && contains(buffer, pending_snapshots))
387 {402 {
388 snapshot_released.wait(lock,403 snapshot_released.wait(lock,
389 [&]{ return !contains(buffer, pending_snapshots); });404 [&]{ return !contains(buffer, pending_snapshots); });
@@ -420,7 +435,7 @@
420 if (!pending_client_notifications.empty())435 if (!pending_client_notifications.empty())
421 {436 {
422 framedrop_policy->swap_unblocked();437 framedrop_policy->swap_unblocked();
423 give_buffer_to_client(buffer, std::move(lock));438 give_buffer_to_client(buffer, lock);
424 }439 }
425 else if (!frame_dropping_enabled && buffers.size() > size_t(nbuffers))440 else if (!frame_dropping_enabled && buffers.size() > size_t(nbuffers))
426 {441 {
@@ -446,7 +461,7 @@
446 free_buffers.push_back(buffer);461 free_buffers.push_back(buffer);
447}462}
448463
449void mc::BufferQueue::drop_frame(std::unique_lock<std::mutex> lock)464void mc::BufferQueue::drop_frame(std::unique_lock<std::mutex>& lock, SnapshotWait wait_type)
450{465{
451 // Make sure there is a client waiting for the frame before we drop it.466 // Make sure there is a client waiting for the frame before we drop it.
452 // If not, then there's nothing to do.467 // If not, then there's nothing to do.
@@ -498,7 +513,7 @@
498 buffer_to_give = buffer.get();513 buffer_to_give = buffer.get();
499 }514 }
500 515
501 give_buffer_to_client(buffer_to_give, std::move(lock));516 give_buffer_to_client(buffer_to_give, lock, wait_type);
502}517}
503518
504void mc::BufferQueue::drop_old_buffers()519void mc::BufferQueue::drop_old_buffers()
505520
=== modified file 'src/server/compositor/buffer_queue.h'
--- src/server/compositor/buffer_queue.h 2015-01-21 08:53:28 +0000
+++ src/server/compositor/buffer_queue.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -66,13 +66,21 @@
66 void drop_client_requests() override;66 void drop_client_requests() override;
6767
68private:68private:
69 void give_buffer_to_client(graphics::Buffer* buffer,69 enum SnapshotWait
70 std::unique_lock<std::mutex> lock);70 {
71 wait_for_snapshot,
72 ignore_snapshot
73 };
74 void give_buffer_to_client(graphics::Buffer* buffer,
75 std::unique_lock<std::mutex>& lock);
76 void give_buffer_to_client(graphics::Buffer* buffer,
77 std::unique_lock<std::mutex>& lock, SnapshotWait wait_type);
71 void release(graphics::Buffer* buffer,78 void release(graphics::Buffer* buffer,
72 std::unique_lock<std::mutex> lock);79 std::unique_lock<std::mutex> lock);
73 void drop_frame(std::unique_lock<std::mutex> lock);80 void drop_frame(std::unique_lock<std::mutex>& lock, SnapshotWait wait_type);
7481
75 mutable std::mutex guard;82 mutable std::mutex guard;
83 std::unique_lock<decltype(guard)> guard_lock;
7684
77 std::vector<std::shared_ptr<graphics::Buffer>> buffers;85 std::vector<std::shared_ptr<graphics::Buffer>> buffers;
78 std::deque<graphics::Buffer*> ready_to_composite_queue;86 std::deque<graphics::Buffer*> ready_to_composite_queue;
7987
=== modified file 'src/server/compositor/timeout_frame_dropping_policy_factory.cpp'
--- src/server/compositor/timeout_frame_dropping_policy_factory.cpp 2015-02-17 11:58:56 +0000
+++ src/server/compositor/timeout_frame_dropping_policy_factory.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "mir/compositor/frame_dropping_policy.h"20#include "mir/compositor/frame_dropping_policy.h"
@@ -34,7 +35,9 @@
34public:35public:
35 TimeoutFrameDroppingPolicy(std::shared_ptr<mir::time::Timer> const& timer,36 TimeoutFrameDroppingPolicy(std::shared_ptr<mir::time::Timer> const& timer,
36 std::chrono::milliseconds timeout,37 std::chrono::milliseconds timeout,
37 std::function<void(void)> drop_frame);38 std::function<void()> const& drop_frame,
39 std::function<void()> const& lock,
40 std::function<void()> const& unlock);
3841
39 void swap_now_blocking() override;42 void swap_now_blocking() override;
40 void swap_unblocked() override;43 void swap_unblocked() override;
@@ -50,7 +53,9 @@
5053
51TimeoutFrameDroppingPolicy::TimeoutFrameDroppingPolicy(std::shared_ptr<mir::time::Timer> const& timer,54TimeoutFrameDroppingPolicy::TimeoutFrameDroppingPolicy(std::shared_ptr<mir::time::Timer> const& timer,
52 std::chrono::milliseconds timeout,55 std::chrono::milliseconds timeout,
53 std::function<void(void)> drop_frame)56 std::function<void()> const& drop_frame,
57 std::function<void()> const& lock,
58 std::function<void()> const& unlock)
54 : timeout{timeout},59 : timeout{timeout},
55 pending_swaps{0},60 pending_swaps{0},
56 alarm{timer->create_alarm([this, drop_frame]61 alarm{timer->create_alarm([this, drop_frame]
@@ -59,7 +64,7 @@
59 drop_frame();64 drop_frame();
60 if (--pending_swaps > 0)65 if (--pending_swaps > 0)
61 alarm->reschedule_in(this->timeout);66 alarm->reschedule_in(this->timeout);
62 })}67 }, lock, unlock)}
63{68{
64}69}
6570
@@ -81,15 +86,18 @@
81}86}
82}87}
8388
84mc::TimeoutFrameDroppingPolicyFactory::TimeoutFrameDroppingPolicyFactory(std::shared_ptr<mir::time::Timer> const& timer,89mc::TimeoutFrameDroppingPolicyFactory::TimeoutFrameDroppingPolicyFactory(
85 std::chrono::milliseconds timeout)90 std::shared_ptr<mir::time::Timer> const& timer,
91 std::chrono::milliseconds timeout)
86 : timer{timer},92 : timer{timer},
87 timeout{timeout}93 timeout{timeout}
88{94{
89}95}
9096
9197std::unique_ptr<mc::FrameDroppingPolicy>
92std::unique_ptr<mc::FrameDroppingPolicy> mc::TimeoutFrameDroppingPolicyFactory::create_policy(std::function<void ()> drop_frame) const98mc::TimeoutFrameDroppingPolicyFactory::create_policy(std::function<void()> const& drop_frame,
99 std::function<void()> const& lock,
100 std::function<void()> const& unlock) const
93{101{
94 return std::make_unique<TimeoutFrameDroppingPolicy>(timer, timeout, drop_frame);102 return std::make_unique<TimeoutFrameDroppingPolicy>(timer, timeout, drop_frame, lock, unlock);
95}103}
96104
=== modified file 'src/server/compositor/timeout_frame_dropping_policy_factory.h'
--- src/server/compositor/timeout_frame_dropping_policy_factory.h 2014-05-22 20:48:20 +0000
+++ src/server/compositor/timeout_frame_dropping_policy_factory.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
1920
@@ -44,7 +45,10 @@
44 TimeoutFrameDroppingPolicyFactory(std::shared_ptr<mir::time::Timer> const& timer,45 TimeoutFrameDroppingPolicyFactory(std::shared_ptr<mir::time::Timer> const& timer,
45 std::chrono::milliseconds timeout);46 std::chrono::milliseconds timeout);
4647
47 std::unique_ptr<FrameDroppingPolicy> create_policy(std::function<void(void)> drop_frame) const override;48 std::unique_ptr<FrameDroppingPolicy> create_policy(
49 std::function<void()> const& drop_frame,
50 std::function<void()> const& lock,
51 std::function<void()> const& unlock) const override;
48private:52private:
49 std::shared_ptr<mir::time::Timer> const timer;53 std::shared_ptr<mir::time::Timer> const timer;
50 std::chrono::milliseconds timeout;54 std::chrono::milliseconds timeout;
5155
=== modified file 'src/server/glib_main_loop.cpp'
--- src/server/glib_main_loop.cpp 2015-02-17 11:58:56 +0000
+++ src/server/glib_main_loop.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "mir/glib_main_loop.h"20#include "mir/glib_main_loop.h"
@@ -33,10 +34,14 @@
33 AlarmImpl(34 AlarmImpl(
34 GMainContext* main_context,35 GMainContext* main_context,
35 std::shared_ptr<mir::time::Clock> const& clock,36 std::shared_ptr<mir::time::Clock> const& clock,
36 std::function<void()> const& callback)37 std::function<void()> const& callback,
38 std::function<void()> const& lock,
39 std::function<void()> const& unlock)
37 : main_context{main_context},40 : main_context{main_context},
38 clock{clock},41 clock{clock},
39 callback{callback},42 callback{callback},
43 ext_lock{lock},
44 ext_unlock{unlock},
40 state_{State::cancelled}45 state_{State::cancelled}
41 {46 {
42 }47 }
@@ -70,6 +75,8 @@
70 main_context,75 main_context,
71 clock,76 clock,
72 [&] { state_ = State::triggered; callback(); },77 [&] { state_ = State::triggered; callback(); },
78 ext_lock,
79 ext_unlock,
73 time_point);80 time_point);
7481
75 return true;82 return true;
@@ -80,6 +87,8 @@
80 GMainContext* main_context;87 GMainContext* main_context;
81 std::shared_ptr<mir::time::Clock> const clock;88 std::shared_ptr<mir::time::Clock> const clock;
82 std::function<void()> const callback;89 std::function<void()> const callback;
90 std::function<void()> const ext_lock;
91 std::function<void()> const ext_unlock;
83 State state_;92 State state_;
84 mir::detail::GSourceHandle gsource;93 mir::detail::GSourceHandle gsource;
85};94};
@@ -223,7 +232,7 @@
223232
224std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_in(233std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_in(
225 std::chrono::milliseconds delay,234 std::chrono::milliseconds delay,
226 std::function<void()> callback)235 std::function<void()> const& callback)
227{236{
228 auto alarm = create_alarm(callback);237 auto alarm = create_alarm(callback);
229238
@@ -234,7 +243,7 @@
234243
235std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_at(244std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::notify_at(
236 mir::time::Timestamp t,245 mir::time::Timestamp t,
237 std::function<void()> callback)246 std::function<void()> const& callback)
238{247{
239 auto alarm = create_alarm(callback);248 auto alarm = create_alarm(callback);
240249
@@ -244,7 +253,15 @@
244}253}
245254
246std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::create_alarm(255std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::create_alarm(
247 std::function<void()> callback)256 std::function<void()> const& callback)
257{
258 return create_alarm(callback, []{}, []{});
259}
260
261std::unique_ptr<mir::time::Alarm> mir::GLibMainLoop::create_alarm(
262 std::function<void()> const& callback,
263 std::function<void()> const& lock,
264 std::function<void()> const& unlock)
248{265{
249 auto const callback_with_exception_handling =266 auto const callback_with_exception_handling =
250 [this, callback]267 [this, callback]
@@ -254,7 +271,7 @@
254 };271 };
255272
256 return std::make_unique<AlarmImpl>(273 return std::make_unique<AlarmImpl>(
257 main_context, clock, callback_with_exception_handling);274 main_context, clock, callback_with_exception_handling, lock, unlock);
258}275}
259276
260void mir::GLibMainLoop::reprocess_all_sources()277void mir::GLibMainLoop::reprocess_all_sources()
261278
=== modified file 'src/server/glib_main_loop_sources.cpp'
--- src/server/glib_main_loop_sources.cpp 2015-02-13 06:12:34 +0000
+++ src/server/glib_main_loop_sources.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,11 +14,13 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "mir/glib_main_loop_sources.h"20#include "mir/glib_main_loop_sources.h"
20#include "mir/recursive_read_write_mutex.h"21#include "mir/recursive_read_write_mutex.h"
21#include "mir/thread_safe_list.h"22#include "mir/thread_safe_list.h"
23#include "mir/raii.h"
2224
23#include <algorithm>25#include <algorithm>
24#include <atomic>26#include <atomic>
@@ -233,18 +235,25 @@
233 GMainContext* main_context,235 GMainContext* main_context,
234 std::shared_ptr<time::Clock> const& clock,236 std::shared_ptr<time::Clock> const& clock,
235 std::function<void()> const& handler,237 std::function<void()> const& handler,
238 std::function<void()> const& lock,
239 std::function<void()> const& unlock,
236 time::Timestamp target_time)240 time::Timestamp target_time)
237{241{
238 struct TimerContext242 struct TimerContext
239 {243 {
240 TimerContext(std::shared_ptr<time::Clock> const& clock,244 TimerContext(std::shared_ptr<time::Clock> const& clock,
241 std::function<void()> const& handler,245 std::function<void()> const& handler,
246 std::function<void()> const& lock,
247 std::function<void()> const& unlock,
242 time::Timestamp target_time)248 time::Timestamp target_time)
243 : clock{clock}, handler{handler}, target_time{target_time}, enabled{true}249 : clock{clock}, handler{handler}, lock{lock}, unlock{unlock},
250 target_time{target_time}, enabled{true}
244 {251 {
245 }252 }
246 std::shared_ptr<time::Clock> clock;253 std::shared_ptr<time::Clock> clock;
247 std::function<void()> handler;254 std::function<void()> handler;
255 std::function<void()> lock;
256 std::function<void()> unlock;
248 time::Timestamp target_time;257 time::Timestamp target_time;
249 bool enabled;258 bool enabled;
250 mir::RecursiveReadWriteMutex mutex;259 mir::RecursiveReadWriteMutex mutex;
@@ -284,6 +293,9 @@
284 {293 {
285 auto& ctx = reinterpret_cast<TimerGSource*>(source)->ctx;294 auto& ctx = reinterpret_cast<TimerGSource*>(source)->ctx;
286295
296 // Caller may pass std::function objects to preserve locking
297 // order during callback dispatching, so aquire them first.
298 auto caller_lock = mir::raii::paired_calls(std::ref(ctx.lock), std::ref(ctx.unlock));
287 RecursiveReadLock lock{ctx.mutex};299 RecursiveReadLock lock{ctx.mutex};
288 if (ctx.enabled)300 if (ctx.enabled)
289 ctx.handler();301 ctx.handler();
@@ -321,7 +333,7 @@
321 auto const timer_gsource = reinterpret_cast<TimerGSource*>(static_cast<GSource*>(gsource));333 auto const timer_gsource = reinterpret_cast<TimerGSource*>(static_cast<GSource*>(gsource));
322334
323 timer_gsource->ctx_constructed = false;335 timer_gsource->ctx_constructed = false;
324 new (&timer_gsource->ctx) TimerContext{clock, handler, target_time};336 new (&timer_gsource->ctx) TimerContext{clock, handler, lock, unlock, target_time};
325 timer_gsource->ctx_constructed = true;337 timer_gsource->ctx_constructed = true;
326338
327 g_source_attach(gsource, main_context);339 g_source_attach(gsource, main_context);
328340
=== modified file 'tests/include/mir_test_doubles/mock_frame_dropping_policy_factory.h'
--- tests/include/mir_test_doubles/mock_frame_dropping_policy_factory.h 2014-05-22 20:48:20 +0000
+++ tests/include/mir_test_doubles/mock_frame_dropping_policy_factory.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
1920
@@ -23,6 +24,8 @@
23#include "mir/compositor/frame_dropping_policy_factory.h"24#include "mir/compositor/frame_dropping_policy_factory.h"
24#include "mir/compositor/frame_dropping_policy.h"25#include "mir/compositor/frame_dropping_policy.h"
2526
27#include "mir_test/gmock_fixes.h"
28
26#include <unordered_set>29#include <unordered_set>
27#include <functional>30#include <functional>
2831
@@ -42,7 +45,9 @@
42class MockFrameDroppingPolicy : public mc::FrameDroppingPolicy45class MockFrameDroppingPolicy : public mc::FrameDroppingPolicy
43{46{
44public:47public:
45 MockFrameDroppingPolicy(std::function<void(void)> callback,48 MockFrameDroppingPolicy(std::function<void()> const& callback,
49 std::function<void()> const& lock,
50 std::function<void()> const& unlock,
46 MockFrameDroppingPolicyFactory const* parent);51 MockFrameDroppingPolicyFactory const* parent);
47 ~MockFrameDroppingPolicy();52 ~MockFrameDroppingPolicy();
4853
@@ -55,14 +60,19 @@
55 friend class MockFrameDroppingPolicyFactory;60 friend class MockFrameDroppingPolicyFactory;
56 void parent_destroyed();61 void parent_destroyed();
5762
58 std::function<void(void)> callback;63 std::function<void()> callback;
64 std::function<void()> lock;
65 std::function<void()> unlock;
59 MockFrameDroppingPolicyFactory const* parent;66 MockFrameDroppingPolicyFactory const* parent;
60};67};
6168
62class MockFrameDroppingPolicyFactory : public mc::FrameDroppingPolicyFactory69class MockFrameDroppingPolicyFactory : public mc::FrameDroppingPolicyFactory
63{70{
64public:71public:
65 std::unique_ptr<mc::FrameDroppingPolicy> create_policy(std::function<void(void)> drop_frame) const override;72 std::unique_ptr<mc::FrameDroppingPolicy> create_policy(
73 std::function<void()> const& drop_frame,
74 std::function<void()> const& lock,
75 std::function<void()> const& unlock) const override;
6676
67 ~MockFrameDroppingPolicyFactory();77 ~MockFrameDroppingPolicyFactory();
6878
@@ -75,6 +85,15 @@
75 mutable std::unordered_set<MockFrameDroppingPolicy*> policies;85 mutable std::unordered_set<MockFrameDroppingPolicy*> policies;
76};86};
7787
88class FrameDroppingPolicyFactoryMock : public mc::FrameDroppingPolicyFactory
89{
90public:
91 MOCK_CONST_METHOD3(create_policy, std::unique_ptr<mc::FrameDroppingPolicy>(
92 std::function<void()> const&,
93 std::function<void()> const&,
94 std::function<void()> const&));
95};
96
78}97}
79}98}
80}99}
81100
=== modified file 'tests/include/mir_test_doubles/mock_main_loop.h'
--- tests/include/mir_test_doubles/mock_main_loop.h 2014-06-24 14:12:25 +0000
+++ tests/include/mir_test_doubles/mock_main_loop.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as5 * it under the terms of the GNU General Public License version 3 as
@@ -52,11 +52,19 @@
52 MOCK_METHOD1(pause_processing_for,void (void const*));52 MOCK_METHOD1(pause_processing_for,void (void const*));
53 MOCK_METHOD1(resume_processing_for,void (void const*));53 MOCK_METHOD1(resume_processing_for,void (void const*));
5454
55 MOCK_METHOD2(notify_in, std::unique_ptr<time::Alarm>(std::chrono::milliseconds delay,55 MOCK_METHOD2(notify_in,
56 std::function<void(void)> callback));56 std::unique_ptr<time::Alarm>(std::chrono::milliseconds delay,
57 MOCK_METHOD2(notify_at, std::unique_ptr<time::Alarm>(time::Timestamp time_point,57 std::function<void()> const& callback));
58 std::function<void(void)> callback));58 MOCK_METHOD2(notify_at,
59 MOCK_METHOD1(create_alarm, std::unique_ptr<time::Alarm>(std::function<void ()> callback));59 std::unique_ptr<time::Alarm>(time::Timestamp time_point,
60 std::function<void()> const& callback));
61 MOCK_METHOD1(create_alarm, std::unique_ptr<time::Alarm>(std::function<void()> const& callback));
62 MOCK_METHOD3(create_alarm,
63 std::unique_ptr<time::Alarm>(
64 std::function<void()> const& callback,
65 std::function<void()> const& lock,
66 std::function<void()> const& unlock));
67
60};68};
6169
62}70}
6371
=== modified file 'tests/include/mir_test_doubles/mock_timer.h'
--- tests/include/mir_test_doubles/mock_timer.h 2014-05-22 20:48:20 +0000
+++ tests/include/mir_test_doubles/mock_timer.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#ifndef MIR_TEST_DOUBLES_MOCK_TIMER_H_20#ifndef MIR_TEST_DOUBLES_MOCK_TIMER_H_
@@ -36,11 +37,12 @@
36 FakeTimer(std::shared_ptr<FakeClock> const& clock);37 FakeTimer(std::shared_ptr<FakeClock> const& clock);
3738
38 std::unique_ptr<time::Alarm> notify_in(std::chrono::milliseconds delay,39 std::unique_ptr<time::Alarm> notify_in(std::chrono::milliseconds delay,
39 std::function<void(void)> callback) override;40 std::function<void()> const& callback) override;
40 std::unique_ptr<time::Alarm> notify_at(time::Timestamp time_point,41 std::unique_ptr<time::Alarm> notify_at(time::Timestamp time_point,
41 std::function<void(void)> callback) override;42 std::function<void()> const& callback) override;
42 std::unique_ptr<time::Alarm> create_alarm(std::function<void ()> callback) override;43 std::unique_ptr<time::Alarm> create_alarm(std::function<void()> const& callback) override;
4344 std::unique_ptr<time::Alarm> create_alarm(std::function<void()> const& callback,
45 std::function<void()> const& lock, std::function<void()> const& unlock) override;
44private:46private:
45 std::shared_ptr<FakeClock> const clock;47 std::shared_ptr<FakeClock> const clock;
46};48};
4749
=== modified file 'tests/include/mir_test_doubles/stub_frame_dropping_policy_factory.h'
--- tests/include/mir_test_doubles/stub_frame_dropping_policy_factory.h 2014-05-22 20:48:20 +0000
+++ tests/include/mir_test_doubles/stub_frame_dropping_policy_factory.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
1920
@@ -46,9 +47,12 @@
46class StubFrameDroppingPolicyFactory : public mc::FrameDroppingPolicyFactory47class StubFrameDroppingPolicyFactory : public mc::FrameDroppingPolicyFactory
47{48{
48public:49public:
49 std::unique_ptr<mc::FrameDroppingPolicy> create_policy(std::function<void(void)>) const override50 std::unique_ptr<mc::FrameDroppingPolicy> create_policy(
51 std::function<void()> const&,
52 std::function<void()> const&,
53 std::function<void()> const& ) const override
50 {54 {
51 return std::unique_ptr<mc::FrameDroppingPolicy>{new StubFrameDroppingPolicy};55 return std::unique_ptr<mc::FrameDroppingPolicy>{new StubFrameDroppingPolicy};
52 }56 }
53};57};
5458
5559
=== modified file 'tests/include/mir_test_doubles/stub_timer.h'
--- tests/include/mir_test_doubles/stub_timer.h 2015-01-21 07:34:50 +0000
+++ tests/include/mir_test_doubles/stub_timer.h 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -51,12 +51,12 @@
5151
52class StubTimer : public mir::time::Timer52class StubTimer : public mir::time::Timer
53{53{
54 std::unique_ptr<mir::time::Alarm> notify_in(std::chrono::milliseconds, std::function<void(void)>) override54 std::unique_ptr<mir::time::Alarm> notify_in(std::chrono::milliseconds, std::function<void()> const&) override
55 {55 {
56 return std::unique_ptr<mir::time::Alarm>{new StubAlarm};56 return std::unique_ptr<mir::time::Alarm>{new StubAlarm};
57 }57 }
5858
59 std::unique_ptr<mir::time::Alarm> notify_at(mir::time::Timestamp, std::function<void(void)>) override59 std::unique_ptr<mir::time::Alarm> notify_at(mir::time::Timestamp, std::function<void()> const&) override
60 {60 {
61 return std::unique_ptr<mir::time::Alarm>{new StubAlarm};61 return std::unique_ptr<mir::time::Alarm>{new StubAlarm};
62 }62 }
6363
=== modified file 'tests/include/mir_test_doubles/triggered_main_loop.h'
--- tests/include/mir_test_doubles/triggered_main_loop.h 2015-01-27 11:47:52 +0000
+++ tests/include/mir_test_doubles/triggered_main_loop.h 2015-02-20 17:57:50 +0000
@@ -39,7 +39,7 @@
3939
40 void register_fd_handler(std::initializer_list<int> fds, void const* owner, fd_callback const& handler) override;40 void register_fd_handler(std::initializer_list<int> fds, void const* owner, fd_callback const& handler) override;
41 void unregister_fd_handler(void const* owner) override;41 void unregister_fd_handler(void const* owner) override;
42 std::unique_ptr<mir::time::Alarm> notify_in(std::chrono::milliseconds delay, callback call) override;42 std::unique_ptr<mir::time::Alarm> notify_in(std::chrono::milliseconds delay, callback const& call) override;
43 void enqueue(void const* owner, ServerAction const& action) override;43 void enqueue(void const* owner, ServerAction const& action) override;
4444
45 void trigger_pending_fds();45 void trigger_pending_fds();
4646
=== modified file 'tests/mir_test_doubles/mock_frame_dropping_policy_factory.cpp'
--- tests/mir_test_doubles/mock_frame_dropping_policy_factory.cpp 2014-05-22 20:48:20 +0000
+++ tests/mir_test_doubles/mock_frame_dropping_policy_factory.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "mir_test_doubles/mock_frame_dropping_policy_factory.h"20#include "mir_test_doubles/mock_frame_dropping_policy_factory.h"
@@ -21,9 +22,13 @@
21namespace mc = mir::compositor;22namespace mc = mir::compositor;
22namespace mtd = mir::test::doubles;23namespace mtd = mir::test::doubles;
2324
24mtd::MockFrameDroppingPolicy::MockFrameDroppingPolicy(std::function<void(void)> callback,25mtd::MockFrameDroppingPolicy::MockFrameDroppingPolicy(std::function<void()> const& callback,
26 std::function<void()> const& lock,
27 std::function<void()> const& unlock,
25 MockFrameDroppingPolicyFactory const* parent)28 MockFrameDroppingPolicyFactory const* parent)
26 : callback{callback},29 : callback{callback},
30 lock{lock},
31 unlock{unlock},
27 parent{parent}32 parent{parent}
28{33{
29}34}
@@ -36,7 +41,9 @@
3641
37void mtd::MockFrameDroppingPolicy::trigger()42void mtd::MockFrameDroppingPolicy::trigger()
38{43{
44 lock();
39 callback();45 callback();
46 unlock();
40}47}
4148
42void mtd::MockFrameDroppingPolicy::parent_destroyed()49void mtd::MockFrameDroppingPolicy::parent_destroyed()
@@ -45,9 +52,10 @@
45}52}
4653
47std::unique_ptr<mc::FrameDroppingPolicy>54std::unique_ptr<mc::FrameDroppingPolicy>
48mtd::MockFrameDroppingPolicyFactory::create_policy(std::function<void(void)> drop_frame) const55mtd::MockFrameDroppingPolicyFactory::create_policy(std::function<void()> const& drop_frame,
56 std::function<void()> const& lock, std::function<void()> const& unlock) const
49{57{
50 auto policy = new ::testing::NiceMock<MockFrameDroppingPolicy>{drop_frame, this};58 auto policy = new ::testing::NiceMock<MockFrameDroppingPolicy>{drop_frame, lock, unlock, this};
51 policies.insert(policy);59 policies.insert(policy);
52 return std::unique_ptr<mc::FrameDroppingPolicy>{policy};60 return std::unique_ptr<mc::FrameDroppingPolicy>{policy};
53}61}
5462
=== modified file 'tests/mir_test_doubles/mock_timer.cpp'
--- tests/mir_test_doubles/mock_timer.cpp 2015-01-21 07:34:50 +0000
+++ tests/mir_test_doubles/mock_timer.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "mir_test_doubles/mock_timer.h"20#include "mir_test_doubles/mock_timer.h"
@@ -27,7 +28,10 @@
27class FakeAlarm : public mir::time::Alarm28class FakeAlarm : public mir::time::Alarm
28{29{
29public:30public:
30 FakeAlarm(std::function<void(void)> callback, std::shared_ptr<mt::FakeClock> const& clock);31 FakeAlarm(std::function<void()> const& callback,
32 std::function<void()> const& lock,
33 std::function<void()> const& unlock,
34 std::shared_ptr<mt::FakeClock> const& clock);
31 ~FakeAlarm() override;35 ~FakeAlarm() override;
3236
3337
@@ -39,9 +43,13 @@
39private: 43private:
40 struct InternalState44 struct InternalState
41 {45 {
42 explicit InternalState(std::function<void(void)> callback);46 explicit InternalState(std::function<void()> const& callback,
47 std::function<void()> const& lock,
48 std::function<void()> const& unlock);
43 State state;49 State state;
44 std::function<void(void)> const callback;50 std::function<void()> const callback;
51 std::function<void()> const lock;
52 std::function<void()> const unlock;
45 mt::FakeClock::time_point threshold;53 mt::FakeClock::time_point threshold;
46 };54 };
4755
@@ -51,13 +59,20 @@
51 std::shared_ptr<mt::FakeClock> const clock;59 std::shared_ptr<mt::FakeClock> const clock;
52};60};
5361
54FakeAlarm::InternalState::InternalState(std::function<void(void)> callback)62FakeAlarm::InternalState::InternalState(
55 : state{mir::time::Alarm::pending}, callback{callback}63 std::function<void()> const& callback,
64 std::function<void()> const& lock,
65 std::function<void()> const& unlock)
66 : state{mir::time::Alarm::pending}, callback{callback}, lock{lock}, unlock{unlock}
56{67{
57}68}
5869
59FakeAlarm::FakeAlarm(std::function<void(void)> callback, std::shared_ptr<mt::FakeClock> const& clock)70FakeAlarm::FakeAlarm(
60 : internal_state{std::make_shared<InternalState>(callback)}, clock{clock}71 std::function<void()> const& callback,
72 std::function<void()> const& lock,
73 std::function<void()> const& unlock,
74 std::shared_ptr<mt::FakeClock> const& clock)
75 : internal_state{std::make_shared<InternalState>(callback, lock, unlock)}, clock{clock}
61{76{
62}77}
6378
@@ -88,7 +103,9 @@
88 if (now > state.threshold)103 if (now > state.threshold)
89 {104 {
90 state.state = triggered;105 state.state = triggered;
106 state.lock();
91 state.callback();107 state.callback();
108 state.unlock();
92 return false;109 return false;
93 }110 }
94 return true;111 return true;
@@ -128,22 +145,28 @@
128}145}
129146
130std::unique_ptr<mir::time::Alarm> mtd::FakeTimer::notify_in(std::chrono::milliseconds delay,147std::unique_ptr<mir::time::Alarm> mtd::FakeTimer::notify_in(std::chrono::milliseconds delay,
131 std::function<void(void)> callback)148 std::function<void()> const& callback)
132{149{
133 auto alarm = std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, clock}};150 auto alarm = std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, []{}, []{}, clock}};
134 alarm->reschedule_in(delay);151 alarm->reschedule_in(delay);
135 return std::move(alarm);152 return std::move(alarm);
136}153}
137154
138std::unique_ptr<mir::time::Alarm> mtd::FakeTimer::notify_at(time::Timestamp time_point,155std::unique_ptr<mir::time::Alarm> mtd::FakeTimer::notify_at(time::Timestamp time_point,
139 std::function<void(void)> callback)156 std::function<void()> const& callback)
140{157{
141 auto alarm = std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, clock}};158 auto alarm = std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, []{}, []{}, clock}};
142 alarm->reschedule_for(time_point);159 alarm->reschedule_for(time_point);
143 return std::move(alarm);160 return std::move(alarm);
144}161}
145162
146std::unique_ptr<mir::time::Alarm> mir::test::doubles::FakeTimer::create_alarm(std::function<void(void)> callback)163std::unique_ptr<mir::time::Alarm> mir::test::doubles::FakeTimer::create_alarm(std::function<void()> const& callback)
147{164{
148 return std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, clock}};165 return std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, []{}, []{}, clock}};
166}
167
168std::unique_ptr<mir::time::Alarm> mir::test::doubles::FakeTimer::create_alarm(std::function<void()> const& callback,
169 std::function<void()> const& lock, std::function<void()> const& unlock)
170{
171 return std::unique_ptr<mir::time::Alarm>{new FakeAlarm{callback, lock, unlock, clock}};
149}172}
150173
=== modified file 'tests/mir_test_doubles/triggered_main_loop.cpp'
--- tests/mir_test_doubles/triggered_main_loop.cpp 2015-01-27 11:47:52 +0000
+++ tests/mir_test_doubles/triggered_main_loop.cpp 2015-02-20 17:57:50 +0000
@@ -85,8 +85,9 @@
85 action();85 action();
86}86}
8787
88std::unique_ptr<mir::time::Alarm> mtd::TriggeredMainLoop::notify_in(std::chrono::milliseconds delay,88std::unique_ptr<mir::time::Alarm>
89 callback call)89mtd::TriggeredMainLoop::notify_in(std::chrono::milliseconds delay,
90 callback const& call)
90{91{
91 base::notify_in(delay, call);92 base::notify_in(delay, call);
92 timeout_callbacks.push_back(call);93 timeout_callbacks.push_back(call);
9394
=== modified file 'tests/unit-tests/compositor/test_buffer_queue.cpp'
--- tests/unit-tests/compositor/test_buffer_queue.cpp 2015-02-17 06:38:35 +0000
+++ tests/unit-tests/compositor/test_buffer_queue.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2013-2014 Canonical Ltd.2 * Copyright © 2013-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as5 * it under the terms of the GNU General Public License version 3 as
@@ -1740,3 +1740,12 @@
1740 auto comp2 = q.compositor_acquire(new_compositor_id);1740 auto comp2 = q.compositor_acquire(new_compositor_id);
1741 ASSERT_THAT(comp2->id(), Eq(handle2->id()));1741 ASSERT_THAT(comp2->id(), Eq(handle2->id()));
1742}1742}
1743
1744TEST_F(BufferQueueTest, creates_policy_with_lock_unlock_functions)
1745{
1746 int const nbuffers = 3;
1747
1748 mtd::FrameDroppingPolicyFactoryMock mock_policy_factory;
1749 EXPECT_CALL(mock_policy_factory, create_policy(_, _, _));
1750 mc::BufferQueue q(nbuffers, allocator, basic_properties, mock_policy_factory);
1751}
17431752
=== modified file 'tests/unit-tests/compositor/test_timeout_frame_dropping_policy.cpp'
--- tests/unit-tests/compositor/test_timeout_frame_dropping_policy.cpp 2014-05-22 20:48:20 +0000
+++ tests/unit-tests/compositor/test_timeout_frame_dropping_policy.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -14,16 +14,18 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>16 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "src/server/compositor/timeout_frame_dropping_policy_factory.h"20#include "src/server/compositor/timeout_frame_dropping_policy_factory.h"
20#include "mir/compositor/frame_dropping_policy.h"21#include "mir/compositor/frame_dropping_policy.h"
2122
22#include "mir_test_doubles/mock_timer.h"23#include "mir_test_doubles/mock_timer.h"
2324#include "mir_test/auto_unblock_thread.h"
24#include "mir_test/gmock_fixes.h"25#include "mir_test/gmock_fixes.h"
2526
26#include <stdexcept>27#include <stdexcept>
28#include <mutex>
2729
28#include <gtest/gtest.h>30#include <gtest/gtest.h>
29#include <gmock/gmock.h>31#include <gmock/gmock.h>
@@ -40,7 +42,7 @@
40 bool frame_dropped{false};42 bool frame_dropped{false};
4143
42 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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; }, []{}, []{});
4446
45 clock->advance_time(timeout + std::chrono::milliseconds{1});47 clock->advance_time(timeout + std::chrono::milliseconds{1});
46 EXPECT_FALSE(frame_dropped);48 EXPECT_FALSE(frame_dropped);
@@ -54,7 +56,7 @@
54 bool frame_dropped{false};56 bool frame_dropped{false};
5557
56 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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 policy->swap_now_blocking();60 policy->swap_now_blocking();
5961
60 clock->advance_time(timeout - std::chrono::milliseconds{1});62 clock->advance_time(timeout - std::chrono::milliseconds{1});
@@ -71,7 +73,7 @@
7173
72 bool frame_dropped{false};74 bool frame_dropped{false};
73 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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; }, []{}, []{});
7577
76 policy->swap_now_blocking();78 policy->swap_now_blocking();
77 policy->swap_unblocked();79 policy->swap_unblocked();
@@ -89,7 +91,7 @@
8991
90 bool frame_dropped{false};92 bool frame_dropped{false};
91 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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; }, []{}, []{});
9395
94 policy->swap_now_blocking();96 policy->swap_now_blocking();
95 policy->swap_now_blocking();97 policy->swap_now_blocking();
@@ -119,7 +121,7 @@
119121
120 bool frame_dropped{false};122 bool frame_dropped{false};
121 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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; }, []{}, []{});
123125
124 policy->swap_now_blocking();126 policy->swap_now_blocking();
125 policy->swap_now_blocking();127 policy->swap_now_blocking();
@@ -142,7 +144,7 @@
142144
143 bool frame_dropped{false};145 bool frame_dropped{false};
144 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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; }, []{}, []{});
146148
147 policy->swap_now_blocking();149 policy->swap_now_blocking();
148 clock->advance_time(timeout - std::chrono::milliseconds{1});150 clock->advance_time(timeout - std::chrono::milliseconds{1});
@@ -160,7 +162,7 @@
160162
161 bool frame_dropped{false};163 bool frame_dropped{false};
162 mc::TimeoutFrameDroppingPolicyFactory factory{timer, timeout};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; }, []{}, []{});
164166
165 policy->swap_now_blocking();167 policy->swap_now_blocking();
166 policy->swap_now_blocking();168 policy->swap_now_blocking();
@@ -184,3 +186,28 @@
184 clock->advance_time(timeout + std::chrono::milliseconds{1});186 clock->advance_time(timeout + std::chrono::milliseconds{1});
185 EXPECT_FALSE(frame_dropped);187 EXPECT_FALSE(frame_dropped);
186}188}
189
190TEST(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}
187214
=== modified file 'tests/unit-tests/test_glib_main_loop.cpp'
--- tests/unit-tests/test_glib_main_loop.cpp 2015-02-03 15:07:44 +0000
+++ tests/unit-tests/test_glib_main_loop.cpp 2015-02-20 17:57:50 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2014 Canonical Ltd.2 * Copyright © 2014-2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as5 * it under the terms of the GNU General Public License version 3 as
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *15 *
16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>16 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
17 * Alberto Aguirre <alberto.aguirre@canonical.com>
17 */18 */
1819
19#include "mir/glib_main_loop.h"20#include "mir/glib_main_loop.h"
@@ -960,43 +961,45 @@
960}961}
961962
962TEST_F(GLibMainLoopAlarmTest, alarm_callback_cannot_deadlock)963TEST_F(GLibMainLoopAlarmTest, alarm_callback_cannot_deadlock)
963{ // Regression test for deadlock bug LP: #1339700964{
964 std::timed_mutex m;965 using namespace testing;
965 std::atomic_bool failed(false);966
967 std::mutex m;
968 std::unique_lock<std::mutex> handler_guard{m, std::defer_lock};
969 std::atomic_bool exit{false};
966 int i = 0;970 int i = 0;
967 int const loops = 5;971 int const loops = 5;
968972
969 auto alarm = ml.notify_in(std::chrono::milliseconds{0}, [&]()973 auto alarm = ml.create_alarm([&]()
970 {974 {
971 // From this angle, ensure we can lock m (alarm should be unlocked)975 //In this handler context, the alarm dispatcher should have
972 failed = !m.try_lock_for(std::chrono::seconds{5});976 //acquired the handler guard
973 ASSERT_FALSE(failed);977 EXPECT_THAT(handler_guard.owns_lock(), Eq(true));
974 ++i;978 ++i;
975 m.unlock();979 },
980 [&] { handler_guard.lock(); },
981 [&] { handler_guard.unlock(); });
982
983 mt::AutoUnblockThread t([&]{ exit = true; }, [&]()
984 {
985 std::unique_lock<std::mutex> guard{m};
986 while (i < loops && !exit)
987 {
988 // It's safe to call cancel now because lock ordering is enforced
989 // by passing the lock/unlock lambdas to alarm above
990 alarm->cancel();
991 guard.unlock();
992 std::this_thread::yield();
993 guard.lock();
994 }
976 });995 });
977996
978 std::thread t([&]()
979 {
980 m.lock();
981 while (i < loops && !failed)
982 {
983 // From this angle, ensure we can lock alarm while holding m
984 (void)alarm->state();
985 m.unlock();
986 std::this_thread::yield();
987 m.lock();
988 }
989 m.unlock();
990 });
991
992 UnblockMainLoop unblocker(ml);997 UnblockMainLoop unblocker(ml);
993 for (int j = 0; j < loops; ++j)998 for (int j = 0; j < loops; ++j)
994 {999 {
1000 alarm->reschedule_in(std::chrono::milliseconds{10});
995 clock->advance_by(std::chrono::milliseconds{11}, ml);1001 clock->advance_by(std::chrono::milliseconds{11}, ml);
996 alarm->reschedule_in(std::chrono::milliseconds{10});
997 }1002 }
998
999 t.join();
1000}1003}
10011004
1002TEST_F(GLibMainLoopAlarmTest, alarm_fires_at_correct_time_point)1005TEST_F(GLibMainLoopAlarmTest, alarm_fires_at_correct_time_point)
10031006
=== modified file 'tests/unit-tests/test_raii.cpp'
--- tests/unit-tests/test_raii.cpp 2013-10-21 14:21:00 +0000
+++ tests/unit-tests/test_raii.cpp 2015-02-20 17:57:50 +0000
@@ -179,3 +179,23 @@
179179
180 EXPECT_EQ(this, raii.get());180 EXPECT_EQ(this, raii.get());
181}181}
182
183TEST_F(RaiiTest, paired_call_takes_std_function_refs)
184{
185 int creator_call_count = 0;
186 int deleter_call_count = 0;
187 int const expected_calls = 2;
188
189 std::function<void()> creator = [&creator_call_count] { creator_call_count++; };
190 std::function<void()> deleter = [&deleter_call_count] { deleter_call_count++; };
191
192 for (int i = 0; i < expected_calls; i++)
193 {
194 auto const raii = mir::raii::paired_calls(
195 std::ref(creator),
196 std::ref(deleter));
197 }
198
199 EXPECT_THAT(creator_call_count, Eq(expected_calls));
200 EXPECT_THAT(deleter_call_count, Eq(expected_calls));
201}

Subscribers

People subscribed via source and target branches