Mir

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

Proposed by Alberto Aguirre
Status: Merged
Approved by: Alberto Aguirre
Approved revision: no longer in the source branch.
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
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Approve
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.
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 :

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
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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
Revision history for this message
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
=== modified file 'src/server/frontend/session_mediator.cpp'
--- src/server/frontend/session_mediator.cpp 2015-02-18 05:27:28 +0000
+++ src/server/frontend/session_mediator.cpp 2015-03-06 15:31:16 +0000
@@ -60,6 +60,7 @@
60#include <boost/throw_exception.hpp>60#include <boost/throw_exception.hpp>
6161
62#include <mutex>62#include <mutex>
63#include <thread>
63#include <functional>64#include <functional>
64#include <cstring>65#include <cstring>
6566
@@ -151,17 +152,27 @@
151void mf::SessionMediator::advance_buffer(152void mf::SessionMediator::advance_buffer(
152 SurfaceId surf_id,153 SurfaceId surf_id,
153 Surface& surface,154 Surface& surface,
155 graphics::Buffer* old_buffer,
156 std::unique_lock<std::mutex>& lock,
154 std::function<void(graphics::Buffer*, graphics::BufferIpcMsgType)> complete)157 std::function<void(graphics::Buffer*, graphics::BufferIpcMsgType)> complete)
155{158{
156 auto client_buffer = surface_tracker.last_buffer(surf_id);159 auto const tid = std::this_thread::get_id();
160
157 surface.swap_buffers(161 surface.swap_buffers(
158 client_buffer, 162 old_buffer,
159 [this, surf_id, complete](mg::Buffer* new_buffer)163 // Note: We assume that the lambda will be executed within swap_buffers
164 // (in which case the lock reference is valid) or in a different thread
165 // altogether (in which case the dangling reference is not accessed)
166 [this, tid, &lock, surf_id, complete](mg::Buffer* new_buffer)
160 {167 {
168 if (tid == std::this_thread::get_id())
169 lock.unlock();
170
161 if (surface_tracker.track_buffer(surf_id, new_buffer))171 if (surface_tracker.track_buffer(surf_id, new_buffer))
162 complete(new_buffer, mg::BufferIpcMsgType::update_msg);172 complete(new_buffer, mg::BufferIpcMsgType::update_msg);
163 else173 else
164 complete(new_buffer, mg::BufferIpcMsgType::full_msg);174 complete(new_buffer, mg::BufferIpcMsgType::full_msg);
175
165 });176 });
166}177}
167178
@@ -172,7 +183,7 @@
172 google::protobuf::Closure* done)183 google::protobuf::Closure* done)
173{184{
174185
175 auto const lock = std::make_shared<std::unique_lock<std::mutex>>(session_mutex);186 std::unique_lock<std::mutex> lock{session_mutex};
176187
177 auto const session = weak_session.lock();188 auto const session = weak_session.lock();
178189
@@ -242,12 +253,10 @@
242 setting->set_ivalue(shell->get_surface_attribute(session, surf_id, static_cast<MirSurfaceAttrib>(i)));253 setting->set_ivalue(shell->get_surface_attribute(session, surf_id, static_cast<MirSurfaceAttrib>(i)));
243 }254 }
244255
245 advance_buffer(surf_id, *surface,256 advance_buffer(surf_id, *surface, surface_tracker.last_buffer(surf_id), lock,
246 [lock, this, &surf_id, response, done, session]257 [this, surf_id, response, done, session]
247 (graphics::Buffer* client_buffer, graphics::BufferIpcMsgType msg_type)258 (graphics::Buffer* client_buffer, graphics::BufferIpcMsgType msg_type)
248 {259 {
249 lock->unlock();
250
251 response->mutable_buffer_stream()->mutable_id()->set_value(260 response->mutable_buffer_stream()->mutable_id()->set_value(
252 surf_id.as_value());261 surf_id.as_value());
253 pack_protobuf_buffer(*response->mutable_buffer_stream()->mutable_buffer(),262 pack_protobuf_buffer(*response->mutable_buffer_stream()->mutable_buffer(),
@@ -271,7 +280,7 @@
271{280{
272 SurfaceId const surf_id{request->value()};281 SurfaceId const surf_id{request->value()};
273282
274 auto const lock = std::make_shared<std::unique_lock<std::mutex>>(session_mutex);283 std::unique_lock<std::mutex> lock{session_mutex};
275284
276 auto const session = weak_session.lock();285 auto const session = weak_session.lock();
277286
@@ -281,15 +290,11 @@
281 report->session_next_buffer_called(session->name());290 report->session_next_buffer_called(session->name());
282291
283 auto surface = session->get_surface(surf_id);292 auto surface = session->get_surface(surf_id);
284293 advance_buffer(surf_id, *surface, surface_tracker.last_buffer(surf_id), lock,
285 advance_buffer(surf_id, *surface,294 [this, response, done]
286 [lock, this, response, done, session]
287 (graphics::Buffer* client_buffer, graphics::BufferIpcMsgType msg_type)295 (graphics::Buffer* client_buffer, graphics::BufferIpcMsgType msg_type)
288 {296 {
289 lock->unlock();
290
291 pack_protobuf_buffer(*response, client_buffer, msg_type);297 pack_protobuf_buffer(*response, client_buffer, msg_type);
292
293 done->Run();298 done->Run();
294 });299 });
295}300}
@@ -306,7 +311,7 @@
306 mfd::ProtobufBufferPacker request_msg{const_cast<mir::protobuf::Buffer*>(&request->buffer())};311 mfd::ProtobufBufferPacker request_msg{const_cast<mir::protobuf::Buffer*>(&request->buffer())};
307 ipc_operations->unpack_buffer(request_msg, *surface_tracker.last_buffer(surface_id));312 ipc_operations->unpack_buffer(request_msg, *surface_tracker.last_buffer(surface_id));
308313
309 auto const lock = std::make_shared<std::unique_lock<std::mutex>>(session_mutex);314 std::unique_lock<std::mutex> lock{session_mutex};
310 auto const session = weak_session.lock();315 auto const session = weak_session.lock();
311 if (!session)316 if (!session)
312 BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));317 BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session"));
@@ -314,17 +319,11 @@
314 report->session_exchange_buffer_called(session->name());319 report->session_exchange_buffer_called(session->name());
315320
316 auto const& surface = session->get_surface(surface_id);321 auto const& surface = session->get_surface(surface_id);
317 surface->swap_buffers(322 advance_buffer(surface_id, *surface, surface_tracker.buffer_from(buffer_id), lock,
318 surface_tracker.buffer_from(buffer_id),323 [this, response, done]
319 [this, surface_id, lock, response, done](mg::Buffer* new_buffer)324 (graphics::Buffer* new_buffer, graphics::BufferIpcMsgType msg_type)
320 {325 {
321 lock->unlock();326 pack_protobuf_buffer(*response, new_buffer, msg_type);
322
323 if (surface_tracker.track_buffer(surface_id, new_buffer))
324 pack_protobuf_buffer(*response, new_buffer, mg::BufferIpcMsgType::update_msg);
325 else
326 pack_protobuf_buffer(*response, new_buffer, mg::BufferIpcMsgType::full_msg);
327
328 done->Run();327 done->Run();
329 });328 });
330}329}
331330
=== modified file 'src/server/frontend/session_mediator.h'
--- src/server/frontend/session_mediator.h 2015-01-21 07:34:50 +0000
+++ src/server/frontend/session_mediator.h 2015-03-06 15:31:16 +0000
@@ -192,6 +192,8 @@
192 void advance_buffer(192 void advance_buffer(
193 SurfaceId surf_id,193 SurfaceId surf_id,
194 Surface& surface,194 Surface& surface,
195 graphics::Buffer* old_buffer,
196 std::unique_lock<std::mutex>& lock,
195 std::function<void(graphics::Buffer*, graphics::BufferIpcMsgType)> complete);197 std::function<void(graphics::Buffer*, graphics::BufferIpcMsgType)> complete);
196198
197 virtual std::function<void(std::shared_ptr<Session> const&)> prompt_session_connect_handler() const;199 virtual std::function<void(std::shared_ptr<Session> const&)> prompt_session_connect_handler() const;
198200
=== modified file 'src/server/frontend/surface_tracker.cpp'
--- src/server/frontend/surface_tracker.cpp 2015-01-21 07:34:50 +0000
+++ src/server/frontend/surface_tracker.cpp 2015-03-06 15:31:16 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2013 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
@@ -17,8 +17,11 @@
17 */17 */
1818
19#include "surface_tracker.h"19#include "surface_tracker.h"
20#include "client_buffer_tracker.h"
21
20#include "mir/graphics/buffer.h"22#include "mir/graphics/buffer.h"
21#include "mir/graphics/buffer_id.h"23#include "mir/graphics/buffer_id.h"
24
22#include <boost/throw_exception.hpp>25#include <boost/throw_exception.hpp>
23#include <stdexcept>26#include <stdexcept>
2427
@@ -32,6 +35,7 @@
3235
33bool mf::SurfaceTracker::track_buffer(SurfaceId surface_id, mg::Buffer* buffer)36bool mf::SurfaceTracker::track_buffer(SurfaceId surface_id, mg::Buffer* buffer)
34{37{
38 std::lock_guard<decltype(mutex)> lock{mutex};
35 auto& tracker = client_buffer_tracker[surface_id];39 auto& tracker = client_buffer_tracker[surface_id];
36 if (!tracker)40 if (!tracker)
37 tracker = std::make_shared<ClientBufferTracker>(client_cache_size);41 tracker = std::make_shared<ClientBufferTracker>(client_cache_size);
@@ -53,6 +57,7 @@
5357
54void mf::SurfaceTracker::remove_surface(SurfaceId surface_id)58void mf::SurfaceTracker::remove_surface(SurfaceId surface_id)
55{59{
60 std::lock_guard<decltype(mutex)> lock{mutex};
56 auto it = client_buffer_tracker.find(surface_id);61 auto it = client_buffer_tracker.find(surface_id);
57 if (it != client_buffer_tracker.end())62 if (it != client_buffer_tracker.end())
58 client_buffer_tracker.erase(it);63 client_buffer_tracker.erase(it);
@@ -64,6 +69,7 @@
6469
65mg::Buffer* mf::SurfaceTracker::last_buffer(SurfaceId surface_id) const70mg::Buffer* mf::SurfaceTracker::last_buffer(SurfaceId surface_id) const
66{71{
72 std::lock_guard<decltype(mutex)> lock{mutex};
67 auto it = client_buffer_resource.find(surface_id);73 auto it = client_buffer_resource.find(surface_id);
68 if (it != client_buffer_resource.end())74 if (it != client_buffer_resource.end())
69 return it->second;75 return it->second;
@@ -74,6 +80,7 @@
7480
75mg::Buffer* mf::SurfaceTracker::buffer_from(mg::BufferID buffer_id) const81mg::Buffer* mf::SurfaceTracker::buffer_from(mg::BufferID buffer_id) const
76{82{
83 std::lock_guard<decltype(mutex)> lock{mutex};
77 for (auto const& tracker : client_buffer_tracker)84 for (auto const& tracker : client_buffer_tracker)
78 {85 {
79 auto buffer = tracker.second->buffer_from(buffer_id);86 auto buffer = tracker.second->buffer_from(buffer_id);
8087
=== modified file 'src/server/frontend/surface_tracker.h'
--- src/server/frontend/surface_tracker.h 2015-03-04 11:06:52 +0000
+++ src/server/frontend/surface_tracker.h 2015-03-06 15:31:16 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2013 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
@@ -20,9 +20,11 @@
20#define MIR_FRONTEND_SURFACE_TRACKER_H_20#define MIR_FRONTEND_SURFACE_TRACKER_H_
2121
22#include "mir/frontend/surface_id.h"22#include "mir/frontend/surface_id.h"
23#include "client_buffer_tracker.h"23#include "mir/graphics/buffer_id.h"
24
24#include <unordered_map>25#include <unordered_map>
25#include <memory>26#include <memory>
27#include <mutex>
2628
27namespace mir29namespace mir
28{30{
@@ -32,7 +34,7 @@
32}34}
33namespace frontend35namespace frontend
34{36{
3537class ClientBufferTracker;
36class SurfaceTracker38class SurfaceTracker
37{39{
38public:40public:
@@ -64,6 +66,7 @@
64 /* accesses the last buffer given to track_buffer() for the given SurfaceId */66 /* accesses the last buffer given to track_buffer() for the given SurfaceId */
65 graphics::Buffer* last_buffer(SurfaceId) const;67 graphics::Buffer* last_buffer(SurfaceId) const;
66private:68private:
69 mutable std::mutex mutex;
67 std::unordered_map<SurfaceId, graphics::Buffer*> client_buffer_resource;70 std::unordered_map<SurfaceId, graphics::Buffer*> client_buffer_resource;
68};71};
6972

Subscribers

People subscribed via source and target branches