summarylogtreecommitdiffstats
path: root/0005-ozone-wayland-Use-mutex-before-accessing-surfaces-ma.patch
blob: 9a4e8e822cb3241cf1113997eb30634d73899824 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
From fd1d8bfd55d5b1d073cbad3ebe8f058c49f3702a Mon Sep 17 00:00:00 2001
From: Maksim Sisov <msisov@igalia.com>
Date: Mon, 5 Aug 2019 16:14:47 +0300
Subject: [PATCH 5/5] [ozone/wayland] Use mutex before accessing surfaces map.

We must make sure that accessing surfaces map from different threads
is safe. Otherwise, this is subject to races and unexpected crashes.

Bug: 987950
Change-Id: I2e70e9c1ad48943be518c3571b7ca1fb91f8d51b
---
 ui/ozone/platform/wayland/BUILD.gn            |  1 +
 .../wayland/gpu/gbm_pixmap_wayland.cc         |  6 +-
 .../wayland/gpu/gbm_surfaceless_wayland.cc    |  2 +-
 .../wayland/gpu/wayland_buffer_manager_gpu.cc | 61 ++++++++-----------
 .../wayland/gpu/wayland_buffer_manager_gpu.h  | 14 ++++-
 .../wayland/gpu/wayland_canvas_surface.cc     |  2 +-
 .../wayland/gpu/wayland_surface_gpu.cc        | 16 +++++
 .../wayland/gpu/wayland_surface_gpu.h         | 13 +++-
 8 files changed, 72 insertions(+), 43 deletions(-)
 create mode 100644 ui/ozone/platform/wayland/gpu/wayland_surface_gpu.cc

diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 686138bb614a..a1560a20fe23 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -30,6 +30,7 @@ source_set("wayland") {
     "gpu/wayland_canvas_surface.h",
     "gpu/wayland_surface_factory.cc",
     "gpu/wayland_surface_factory.h",
+    "gpu/wayland_surface_gpu.cc",
     "gpu/wayland_surface_gpu.h",
     "host/wayland_buffer_manager_connector.cc",
     "host/wayland_buffer_manager_connector.h",
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index 5d8167bdfd89..917f849811a2 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -126,10 +126,10 @@ bool GbmPixmapWayland::ScheduleOverlayPlane(
     const gfx::RectF& crop_rect,
     bool enable_blend,
     std::unique_ptr<gfx::GpuFence> gpu_fence) {
-  auto* surface = buffer_manager_->GetSurface(widget);
-  DCHECK(surface);
+  auto surface_weak = buffer_manager_->GetSurface(widget);
+  DCHECK(surface_weak);
   GbmSurfacelessWayland* surfaceless =
-      static_cast<GbmSurfacelessWayland*>(surface);
+      static_cast<GbmSurfacelessWayland*>(surface_weak.get());
   DCHECK(surfaceless);
 
   surfaceless->QueueOverlayPlane(
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 70ea08acfa11..0554e772f5cb 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -34,7 +34,7 @@ GbmSurfacelessWayland::GbmSurfacelessWayland(
       has_implicit_external_sync_(
           HasEGLExtension("EGL_ARM_implicit_external_sync")),
       weak_factory_(this) {
-  buffer_manager_->RegisterSurface(widget_, this);
+  buffer_manager_->RegisterSurface(widget_, GetWeakPtr());
   unsubmitted_frames_.push_back(std::make_unique<PendingFrame>());
 }
 
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
index 63bfa3032fde..f113a9887bdc 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.cc
@@ -43,19 +43,13 @@ void WaylandBufferManagerGpu::OnSubmission(gfx::AcceleratedWidget widget,
                                            gfx::SwapResult swap_result) {
   DCHECK(io_thread_runner_->BelongsToCurrentThread());
   DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
-  auto* surface = GetSurface(widget);
-  // There can be a race between destruction and submitting the last frames. The
-  // surface can be destroyed by the time the host receives a request to destroy
-  // a buffer, and is able to call the OnSubmission for that specific buffer.
-  if (surface) {
-    // As long as mojo calls rerouted to the IO child thread, we have to reroute
-    // them back to the same thread, where the original commit buffer call came
-    // from.
-    commit_thread_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&WaylandSurfaceGpu::OnSubmission, base::Unretained(surface),
-                   buffer_id, swap_result));
-  }
+  auto surface = GetSurface(widget);
+  // As long as mojo calls rerouted to the IO child thread, we have to reroute
+  // them back to the same thread, where the original commit buffer call came
+  // from.
+  commit_thread_runner_->PostTask(
+      FROM_HERE, base::Bind(&WaylandSurfaceGpu::OnSubmission, surface,
+                            buffer_id, swap_result));
 }
 
 void WaylandBufferManagerGpu::OnPresentation(
@@ -64,36 +58,35 @@ void WaylandBufferManagerGpu::OnPresentation(
     const gfx::PresentationFeedback& feedback) {
   DCHECK(io_thread_runner_->BelongsToCurrentThread());
   DCHECK_NE(widget, gfx::kNullAcceleratedWidget);
-  auto* surface = GetSurface(widget);
-  // There can be a race between destruction and presenting the last frames. The
-  // surface can be destroyed by the time the host receives a request to destroy
-  // a buffer, and is able to call the OnPresentation for that specific buffer.
-  if (surface) {
-    // As long as mojo calls rerouted to the IO child thread, we have to reroute
-    // them back to the same thread, where the original commit buffer call came
-    // from.
-    commit_thread_runner_->PostTask(
-        FROM_HERE, base::Bind(&WaylandSurfaceGpu::OnPresentation,
-                              base::Unretained(surface), buffer_id, feedback));
-  }
-}
-
-void WaylandBufferManagerGpu::RegisterSurface(gfx::AcceleratedWidget widget,
-                                              WaylandSurfaceGpu* surface) {
+  auto surface = GetSurface(widget);
+  // As long as mojo calls rerouted to the IO child thread, we have to reroute
+  // them back to the same thread, where the original commit buffer call came
+  // from.
+  commit_thread_runner_->PostTask(
+      FROM_HERE, base::Bind(&WaylandSurfaceGpu::OnPresentation, surface,
+                            buffer_id, feedback));
+}
+
+void WaylandBufferManagerGpu::RegisterSurface(
+    gfx::AcceleratedWidget widget,
+    base::WeakPtr<WaylandSurfaceGpu> surface) {
+  base::AutoLock scoped_lock(lock_);
   widget_to_surface_map_.insert(std::make_pair(widget, surface));
 }
 
 void WaylandBufferManagerGpu::UnregisterSurface(gfx::AcceleratedWidget widget) {
+  base::AutoLock scoped_lock(lock_);
   widget_to_surface_map_.erase(widget);
 }
 
-WaylandSurfaceGpu* WaylandBufferManagerGpu::GetSurface(
-    gfx::AcceleratedWidget widget) const {
-  WaylandSurfaceGpu* surface = nullptr;
+base::WeakPtr<WaylandSurfaceGpu> WaylandBufferManagerGpu::GetSurface(
+    gfx::AcceleratedWidget widget) {
+  base::AutoLock scoped_lock(lock_);
+
   auto it = widget_to_surface_map_.find(widget);
   if (it != widget_to_surface_map_.end())
-    surface = it->second;
-  return surface;
+    return it->second;
+  return nullptr;
 }
 
 void WaylandBufferManagerGpu::CreateDmabufBasedBuffer(
diff --git a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
index 87439610cfc3..631d715e719e 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h
@@ -8,6 +8,8 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
@@ -64,9 +66,11 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
   // result of the below operations, they must register themselves with the
   // below APIs.
   void RegisterSurface(gfx::AcceleratedWidget widget,
-                       WaylandSurfaceGpu* surface);
+                       base::WeakPtr<WaylandSurfaceGpu> surface);
   void UnregisterSurface(gfx::AcceleratedWidget widget);
-  WaylandSurfaceGpu* GetSurface(gfx::AcceleratedWidget widget) const;
+  // A client of this method must always get and acquire lock before doing
+  // any manipulations with the surface. Once done, the lock must be released.
+  base::WeakPtr<WaylandSurfaceGpu> GetSurface(gfx::AcceleratedWidget widget);
 
   // Methods, which can be used when in both in-process-gpu and out of process
   // modes. These calls are forwarded to the browser process through the
@@ -156,7 +160,8 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
   mojo::AssociatedBinding<ozone::mojom::WaylandBufferManagerGpu>
       associated_binding_;
 
-  std::map<gfx::AcceleratedWidget, WaylandSurfaceGpu*> widget_to_surface_map_;
+  std::map<gfx::AcceleratedWidget, base::WeakPtr<WaylandSurfaceGpu>>
+      widget_to_surface_map_;  // Guarded by |lock_|.
 
   // This task runner can be used to pass messages back to the same thread,
   // where the commit buffer request came from. For example, swap requests come
@@ -171,6 +176,9 @@ class WaylandBufferManagerGpu : public ozone::mojom::WaylandBufferManagerGpu {
   // needed to ensure mojo calls happen on a right sequence.
   scoped_refptr<base::SingleThreadTaskRunner> io_thread_runner_;
 
+  // Protects access to |widget_to_surface_map_|.
+  base::Lock lock_;
+
   DISALLOW_COPY_AND_ASSIGN(WaylandBufferManagerGpu);
 };
 
diff --git a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
index 6de24d7fd177..ce44ebac2915 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_canvas_surface.cc
@@ -29,7 +29,7 @@ WaylandCanvasSurface::WaylandCanvasSurface(
     WaylandBufferManagerGpu* buffer_manager,
     gfx::AcceleratedWidget widget)
     : buffer_manager_(buffer_manager), widget_(widget) {
-  buffer_manager_->RegisterSurface(widget_, this);
+  buffer_manager_->RegisterSurface(widget_, GetWeakPtr());
 }
 
 WaylandCanvasSurface::~WaylandCanvasSurface() {
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.cc
new file mode 100644
index 000000000000..85296edcca42
--- /dev/null
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.cc
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h"
+
+namespace ui {
+
+WaylandSurfaceGpu::WaylandSurfaceGpu() = default;
+WaylandSurfaceGpu::~WaylandSurfaceGpu() = default;
+
+base::WeakPtr<WaylandSurfaceGpu> WaylandSurfaceGpu::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h b/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h
index ace5279e838e..38d285317ab3 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 
 namespace gfx {
 enum class SwapResult;
@@ -22,7 +23,7 @@ namespace ui {
 // the buffer.
 class WaylandSurfaceGpu {
  public:
-  virtual ~WaylandSurfaceGpu() {}
+  virtual ~WaylandSurfaceGpu();
 
   // Tells the surface the result of the last swap of buffer with the
   // |buffer_id|.
@@ -33,6 +34,16 @@ class WaylandSurfaceGpu {
   // |buffer_id|.
   virtual void OnPresentation(uint32_t buffer_id,
                               const gfx::PresentationFeedback& feedback) = 0;
+
+ protected:
+  WaylandSurfaceGpu();
+
+  base::WeakPtr<WaylandSurfaceGpu> GetWeakPtr();
+
+ private:
+  base::WeakPtrFactory<WaylandSurfaceGpu> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(WaylandSurfaceGpu);
 };
 
 }  // namespace ui
-- 
2.22.0