Mir

Merge lp:~albaguirre/mir/fix-1427976-take2 into lp:mir

Proposed by Alberto Aguirre on 2015-03-05
Status: Merged
Approved by: Alberto Aguirre on 2015-03-09
Approved revision: 2371
Merged at revision: 2379
Proposed branch: lp:~albaguirre/mir/fix-1427976-take2
Merge into: lp:mir
Diff against target: 232 lines (+41/-30)
4 files modified
src/server/frontend/session_mediator.cpp (+25/-26)
src/server/frontend/session_mediator.h (+2/-0)
src/server/frontend/surface_tracker.cpp (+8/-1)
src/server/frontend/surface_tracker.h (+6/-3)
To merge this branch: bzr merge lp:~albaguirre/mir/fix-1427976-take2
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve on 2015-03-09
PS Jenkins bot continuous-integration Approve on 2015-03-06
Alan Griffiths 2015-03-05 Approve on 2015-03-06
Review via email: mp+252031@code.launchpad.net

Commit Message

Avoid unlocking a mutex in a thread that does not own it.

SessionMediator unlocks its session_mutex before invoking rpc callbacks.
This becomes cumbersome when SessionMediator needs to call Surface::swap_buffers,
as the completion function may be executed in an entirely different thread.

The session_mutex should only be unlocked if the completion function is invoked during Surface::swap_buffers.

Description of the Change

Avoid unlocking a mutex in a thread that does not own it.

SessionMediator unlocks its session_mutex before invoking rpc callbacks.
This becomes cumbersome when SessionMediator needs to call Surface::swap_buffers,
as the completion function may be executed in an entirely different thread.

The session_mutex should only be unlocked if the completion function is invoked during Surface::swap_buffers.

To post a comment you must log in.
Alan Griffiths (alan-griffiths) wrote :

Ugly, but makes sense in the context of the way the code is currently.

So let's land this, but keep the technical debt around this area on the radar.

review: Approve
lp:~albaguirre/mir/fix-1427976-take2 updated on 2015-03-06
2371. By Alberto Aguirre on 2015-03-06

Make SurfaceTracker thread safe to avoid locking session_mutex.

Locking the session_mutex during the completion callback when executing on a separate
thread can cause lock ordering issues.

Alexandros Frantzis (afrantzis) wrote :

Looks good.

+1 for also fixing a potential race in mf::SessionMediator::exchange_buffer() (which previously called SurfaceTracker unlocked).

review: Approve
Kevin DuBois (kdub) wrote :

> Ugly, but makes sense in the context of the way the code is currently.
>
> So let's land this, but keep the technical debt around this area on the radar.

maybe put it on the backlog?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/frontend/session_mediator.cpp'
2--- src/server/frontend/session_mediator.cpp 2015-02-18 05:27:28 +0000
3+++ src/server/frontend/session_mediator.cpp 2015-03-06 15:31:16 +0000
4@@ -60,6 +60,7 @@
5 #include <boost/throw_exception.hpp>
6
7 #include <mutex>
8+#include <thread>
9 #include <functional>
10 #include <cstring>
11
12@@ -151,17 +152,27 @@
13 void mf::SessionMediator::advance_buffer(
14 SurfaceId surf_id,
15 Surface& surface,
16+ graphics::Buffer* old_buffer,
17+ std::unique_lock<std::mutex>& lock,
18 std::function<void(graphics::Buffer*, graphics::BufferIpcMsgType)> complete)
19 {
20- auto client_buffer = surface_tracker.last_buffer(surf_id);
21+ auto const tid = std::this_thread::get_id();
22+
23 surface.swap_buffers(
24- client_buffer,
25- [this, surf_id, complete](mg::Buffer* new_buffer)
26+ old_buffer,
27+ // Note: We assume that the lambda will be executed within swap_buffers
28+ // (in which case the lock reference is valid) or in a different thread
29+ // altogether (in which case the dangling reference is not accessed)
30+ [this, tid, &lock, surf_id, complete](mg::Buffer* new_buffer)
31 {
32+ if (tid == std::this_thread::get_id())
33+ lock.unlock();
34+
35 if (surface_tracker.track_buffer(surf_id, new_buffer))
36 complete(new_buffer, mg::BufferIpcMsgType::update_msg);
37 else
38 complete(new_buffer, mg::BufferIpcMsgType::full_msg);
39+
40 });
41 }
42
43@@ -172,7 +183,7 @@
44 google::protobuf::Closure* done)
45 {
46
47- auto const lock = std::make_shared<std::unique_lock<std::mutex>>(session_mutex);
48+ std::unique_lock<std::mutex> lock{session_mutex};
49
50 auto const session = weak_session.lock();
51
52@@ -242,12 +253,10 @@
53 setting->set_ivalue(shell->get_surface_attribute(session, surf_id, static_cast<MirSurfaceAttrib>(i)));
54 }
55
56- advance_buffer(surf_id, *surface,
57- [lock, this, &surf_id, response, done, session]
58+ advance_buffer(surf_id, *surface, surface_tracker.last_buffer(surf_id), lock,
59+ [this, surf_id, response, done, session]
60 (graphics::Buffer* client_buffer, graphics::BufferIpcMsgType msg_type)
61 {
62- lock->unlock();
63-
64 response->mutable_buffer_stream()->mutable_id()->set_value(
65 surf_id.as_value());
66 pack_protobuf_buffer(*response->mutable_buffer_stream()->mutable_buffer(),
67@@ -271,7 +280,7 @@
68 {
69 SurfaceId const surf_id{request->value()};
70
71- auto const lock = std::make_shared<std::unique_lock<std::mutex>>(session_mutex);
72+ std::unique_lock<std::mutex> lock{session_mutex};
73
74 auto const session = weak_session.lock();
75
76@@ -281,15 +290,11 @@
77 report->session_next_buffer_called(session->name());
78
79 auto surface = session->get_surface(surf_id);
80-
81- advance_buffer(surf_id, *surface,
82- [lock, this, response, done, session]
83+ advance_buffer(surf_id, *surface, surface_tracker.last_buffer(surf_id), lock,
84+ [this, response, done]
85 (graphics::Buffer* client_buffer, graphics::BufferIpcMsgType msg_type)
86 {
87- lock->unlock();
88-
89 pack_protobuf_buffer(*response, client_buffer, msg_type);
90-
91 done->Run();
92 });
93 }
94@@ -306,7 +311,7 @@
95 mfd::ProtobufBufferPacker request_msg{const_cast<mir::protobuf::Buffer*>(&request->buffer())};
96 ipc_operations->unpack_buffer(request_msg, *surface_tracker.last_buffer(surface_id));
97
98- auto const lock = std::make_shared<std::unique_lock<std::mutex>>(session_mutex);
99+ std::unique_lock<std::mutex> lock{session_mutex};
100 auto const session = weak_session.lock();
101 if (!session)
102 BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
103@@ -314,17 +319,11 @@
104 report->session_exchange_buffer_called(session->name());
105
106 auto const& surface = session->get_surface(surface_id);
107- surface->swap_buffers(
108- surface_tracker.buffer_from(buffer_id),
109- [this, surface_id, lock, response, done](mg::Buffer* new_buffer)
110+ advance_buffer(surface_id, *surface, surface_tracker.buffer_from(buffer_id), lock,
111+ [this, response, done]
112+ (graphics::Buffer* new_buffer, graphics::BufferIpcMsgType msg_type)
113 {
114- lock->unlock();
115-
116- if (surface_tracker.track_buffer(surface_id, new_buffer))
117- pack_protobuf_buffer(*response, new_buffer, mg::BufferIpcMsgType::update_msg);
118- else
119- pack_protobuf_buffer(*response, new_buffer, mg::BufferIpcMsgType::full_msg);
120-
121+ pack_protobuf_buffer(*response, new_buffer, msg_type);
122 done->Run();
123 });
124 }
125
126=== modified file 'src/server/frontend/session_mediator.h'
127--- src/server/frontend/session_mediator.h 2015-01-21 07:34:50 +0000
128+++ src/server/frontend/session_mediator.h 2015-03-06 15:31:16 +0000
129@@ -192,6 +192,8 @@
130 void advance_buffer(
131 SurfaceId surf_id,
132 Surface& surface,
133+ graphics::Buffer* old_buffer,
134+ std::unique_lock<std::mutex>& lock,
135 std::function<void(graphics::Buffer*, graphics::BufferIpcMsgType)> complete);
136
137 virtual std::function<void(std::shared_ptr<Session> const&)> prompt_session_connect_handler() const;
138
139=== modified file 'src/server/frontend/surface_tracker.cpp'
140--- src/server/frontend/surface_tracker.cpp 2015-01-21 07:34:50 +0000
141+++ src/server/frontend/surface_tracker.cpp 2015-03-06 15:31:16 +0000
142@@ -1,5 +1,5 @@
143 /*
144- * Copyright © 2013 Canonical Ltd.
145+ * Copyright © 2013-2015 Canonical Ltd.
146 *
147 * This program is free software: you can redistribute it and/or modify
148 * it under the terms of the GNU General Public License version 3 as
149@@ -17,8 +17,11 @@
150 */
151
152 #include "surface_tracker.h"
153+#include "client_buffer_tracker.h"
154+
155 #include "mir/graphics/buffer.h"
156 #include "mir/graphics/buffer_id.h"
157+
158 #include <boost/throw_exception.hpp>
159 #include <stdexcept>
160
161@@ -32,6 +35,7 @@
162
163 bool mf::SurfaceTracker::track_buffer(SurfaceId surface_id, mg::Buffer* buffer)
164 {
165+ std::lock_guard<decltype(mutex)> lock{mutex};
166 auto& tracker = client_buffer_tracker[surface_id];
167 if (!tracker)
168 tracker = std::make_shared<ClientBufferTracker>(client_cache_size);
169@@ -53,6 +57,7 @@
170
171 void mf::SurfaceTracker::remove_surface(SurfaceId surface_id)
172 {
173+ std::lock_guard<decltype(mutex)> lock{mutex};
174 auto it = client_buffer_tracker.find(surface_id);
175 if (it != client_buffer_tracker.end())
176 client_buffer_tracker.erase(it);
177@@ -64,6 +69,7 @@
178
179 mg::Buffer* mf::SurfaceTracker::last_buffer(SurfaceId surface_id) const
180 {
181+ std::lock_guard<decltype(mutex)> lock{mutex};
182 auto it = client_buffer_resource.find(surface_id);
183 if (it != client_buffer_resource.end())
184 return it->second;
185@@ -74,6 +80,7 @@
186
187 mg::Buffer* mf::SurfaceTracker::buffer_from(mg::BufferID buffer_id) const
188 {
189+ std::lock_guard<decltype(mutex)> lock{mutex};
190 for (auto const& tracker : client_buffer_tracker)
191 {
192 auto buffer = tracker.second->buffer_from(buffer_id);
193
194=== modified file 'src/server/frontend/surface_tracker.h'
195--- src/server/frontend/surface_tracker.h 2015-03-04 11:06:52 +0000
196+++ src/server/frontend/surface_tracker.h 2015-03-06 15:31:16 +0000
197@@ -1,5 +1,5 @@
198 /*
199- * Copyright © 2013 Canonical Ltd.
200+ * Copyright © 2013-2015 Canonical Ltd.
201 *
202 * This program is free software: you can redistribute it and/or modify
203 * it under the terms of the GNU General Public License version 3 as
204@@ -20,9 +20,11 @@
205 #define MIR_FRONTEND_SURFACE_TRACKER_H_
206
207 #include "mir/frontend/surface_id.h"
208-#include "client_buffer_tracker.h"
209+#include "mir/graphics/buffer_id.h"
210+
211 #include <unordered_map>
212 #include <memory>
213+#include <mutex>
214
215 namespace mir
216 {
217@@ -32,7 +34,7 @@
218 }
219 namespace frontend
220 {
221-
222+class ClientBufferTracker;
223 class SurfaceTracker
224 {
225 public:
226@@ -64,6 +66,7 @@
227 /* accesses the last buffer given to track_buffer() for the given SurfaceId */
228 graphics::Buffer* last_buffer(SurfaceId) const;
229 private:
230+ mutable std::mutex mutex;
231 std::unordered_map<SurfaceId, graphics::Buffer*> client_buffer_resource;
232 };
233

Subscribers

People subscribed via source and target branches