Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(989)

Side by Side Diff: media/midi/midi_manager.cc

Issue 2443113002: Fix possible multiple calls to MidiManager::StartInitialization() in StartSession() (Closed)
Patch Set: comment Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« media/midi/midi_manager.h ('K') | « media/midi/midi_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/midi/midi_manager.h" 5 #include "media/midi/midi_manager.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/metrics/histogram_macros.h" 9 #include "base/metrics/histogram_macros.h"
10 #include "base/single_thread_task_runner.h" 10 #include "base/single_thread_task_runner.h"
(...skipping 20 matching lines...) Expand all
31 SESSION_STARTED, 31 SESSION_STARTED,
32 SESSION_ENDED, 32 SESSION_ENDED,
33 INITIALIZED, 33 INITIALIZED,
34 INPUT_PORT_ADDED, 34 INPUT_PORT_ADDED,
35 OUTPUT_PORT_ADDED, 35 OUTPUT_PORT_ADDED,
36 36
37 // New items should be inserted here, and |MAX| should point the last item. 37 // New items should be inserted here, and |MAX| should point the last item.
38 MAX = INITIALIZED, 38 MAX = INITIALIZED,
39 }; 39 };
40 40
41 // Used in StartSession.
42 enum class Completion {
43 COMPLETE_SYNCHRONOUSLY,
44 INVOKE_INITIALIZATION,
45 COMPLETE_ASYNCHRONOUSLY,
46 };
47
48 void ReportUsage(Usage usage) { 41 void ReportUsage(Usage usage) {
49 UMA_HISTOGRAM_ENUMERATION("Media.Midi.Usage", 42 UMA_HISTOGRAM_ENUMERATION("Media.Midi.Usage",
50 static_cast<Sample>(usage), 43 static_cast<Sample>(usage),
51 static_cast<Sample>(Usage::MAX) + 1); 44 static_cast<Sample>(Usage::MAX) + 1);
52 } 45 }
53 46
54 } // namespace 47 } // namespace
55 48
56 MidiManager::MidiManager() 49 MidiManager::MidiManager()
57 : initialized_(false), finalized_(false), result_(Result::NOT_INITIALIZED) { 50 : initialization_state_(InitializationState::NOT_STARTED),
51 finalized_(false),
52 result_(Result::NOT_INITIALIZED) {
58 ReportUsage(Usage::CREATED); 53 ReportUsage(Usage::CREATED);
59 } 54 }
60 55
61 MidiManager::~MidiManager() { 56 MidiManager::~MidiManager() {
62 // Make sure that Finalize() is called to clean up resources allocated on 57 // Make sure that Finalize() is called to clean up resources allocated on
63 // the Chrome_IOThread. 58 // the Chrome_IOThread.
64 base::AutoLock auto_lock(lock_); 59 base::AutoLock auto_lock(lock_);
65 CHECK(finalized_); 60 CHECK(finalized_);
66 } 61 }
67 62
(...skipping 16 matching lines...) Expand all
84 base::Unretained(this))); 79 base::Unretained(this)));
85 session_thread_runner_ = nullptr; 80 session_thread_runner_ = nullptr;
86 } else { 81 } else {
87 finalized_ = true; 82 finalized_ = true;
88 } 83 }
89 } 84 }
90 85
91 void MidiManager::StartSession(MidiManagerClient* client) { 86 void MidiManager::StartSession(MidiManagerClient* client) {
92 ReportUsage(Usage::SESSION_STARTED); 87 ReportUsage(Usage::SESSION_STARTED);
93 88
94 Completion completion = Completion::COMPLETE_SYNCHRONOUSLY; 89 bool needs_initialization = false;
95 Result result = Result::NOT_INITIALIZED;
96 90
97 { 91 {
98 base::AutoLock auto_lock(lock_); 92 base::AutoLock auto_lock(lock_);
99 if (clients_.find(client) != clients_.end() || 93 if (clients_.find(client) != clients_.end() ||
100 pending_clients_.find(client) != pending_clients_.end()) { 94 pending_clients_.find(client) != pending_clients_.end()) {
101 // Should not happen. But just in case the renderer is compromised. 95 // Should not happen. But just in case the renderer is compromised.
102 NOTREACHED(); 96 NOTREACHED();
103 return; 97 return;
104 } 98 }
105 99
106 if (initialized_) { 100 // Do not accept a new request if Shutdown() was already called.
Shao-Chuan Lee 2016/10/24 08:54:34 I guess this check should be moved in front of the
Takashi Toyoshima 2016/10/24 10:07:29 Thanks, this looks a nice improvement!
101 if (finalized_) {
102 client->CompleteStartSession(Result::INITIALIZATION_ERROR);
103 return;
104 }
105
106 if (initialization_state_ == InitializationState::COMPLETED) {
107 // Platform dependent initialization was already finished for previously 107 // Platform dependent initialization was already finished for previously
108 // initialized clients. 108 // initialized clients.
109 if (result_ == Result::OK) { 109 if (result_ == Result::OK) {
110 AddInitialPorts(client); 110 AddInitialPorts(client);
111 clients_.insert(client); 111 clients_.insert(client);
112 } 112 }
113 // Complete synchronously with |result_|; 113 // Complete synchronously with |result_|;
114 result = result_; 114 client->CompleteStartSession(result_);
115 } else { 115 return;
116 bool too_many_pending_clients_exist =
117 pending_clients_.size() >= kMaxPendingClientCount;
118 // Do not accept a new request if the pending client list contains too
119 // many clients, or Shutdown() was already called.
120 if (too_many_pending_clients_exist || finalized_) {
121 result = Result::INITIALIZATION_ERROR;
122 } else {
123 // Call StartInitialization() only for the first request.
124 if (pending_clients_.empty()) {
125 completion = Completion::INVOKE_INITIALIZATION;
126 session_thread_runner_ = base::ThreadTaskRunnerHandle::Get();
127 } else {
128 completion = Completion::COMPLETE_ASYNCHRONOUSLY;
129 }
130 pending_clients_.insert(client);
131 }
132 } 116 }
133 117
134 if (completion == Completion::COMPLETE_SYNCHRONOUSLY) { 118 // Do not accept a new request if the pending client list contains too
135 client->CompleteStartSession(result); 119 // many clients.
120 if (pending_clients_.size() >= kMaxPendingClientCount) {
121 client->CompleteStartSession(Result::INITIALIZATION_ERROR);
136 return; 122 return;
137 } 123 }
124
125 if (initialization_state_ == InitializationState::NOT_STARTED) {
126 // Set fields protected by |lock_| here and call StartInitialization()
127 // later.
128 needs_initialization = true;
129 session_thread_runner_ = base::ThreadTaskRunnerHandle::Get();
130 initialization_state_ = InitializationState::STARTED;
131 }
132
133 pending_clients_.insert(client);
138 } 134 }
139 135
140 if (completion == Completion::INVOKE_INITIALIZATION) { 136 if (needs_initialization) {
141 // Lazily initialize the MIDI back-end. 137 // Lazily initialize the MIDI back-end.
142 TRACE_EVENT0("midi", "MidiManager::StartInitialization"); 138 TRACE_EVENT0("midi", "MidiManager::StartInitialization");
143 // CompleteInitialization() will be called asynchronously when platform 139 // CompleteInitialization() will be called asynchronously when platform
144 // dependent initialization is finished. 140 // dependent initialization is finished.
145 StartInitialization(); 141 StartInitialization();
146 } 142 }
147 } 143 }
148 144
149 void MidiManager::EndSession(MidiManagerClient* client) { 145 void MidiManager::EndSession(MidiManagerClient* client) {
150 ReportUsage(Usage::SESSION_ENDED); 146 ReportUsage(Usage::SESSION_ENDED);
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 ReportUsage(Usage::INITIALIZED); 230 ReportUsage(Usage::INITIALIZED);
235 UMA_HISTOGRAM_ENUMERATION("Media.Midi.InputPorts", 231 UMA_HISTOGRAM_ENUMERATION("Media.Midi.InputPorts",
236 static_cast<Sample>(input_ports_.size()), 232 static_cast<Sample>(input_ports_.size()),
237 kMaxUmaDevices + 1); 233 kMaxUmaDevices + 1);
238 UMA_HISTOGRAM_ENUMERATION("Media.Midi.OutputPorts", 234 UMA_HISTOGRAM_ENUMERATION("Media.Midi.OutputPorts",
239 static_cast<Sample>(output_ports_.size()), 235 static_cast<Sample>(output_ports_.size()),
240 kMaxUmaDevices + 1); 236 kMaxUmaDevices + 1);
241 237
242 base::AutoLock auto_lock(lock_); 238 base::AutoLock auto_lock(lock_);
243 DCHECK(clients_.empty()); 239 DCHECK(clients_.empty());
244 DCHECK(!initialized_); 240 DCHECK_EQ(initialization_state_, InitializationState::STARTED);
245 initialized_ = true; 241 initialization_state_ = InitializationState::COMPLETED;
246 result_ = result; 242 result_ = result;
247 243
248 for (auto* client : pending_clients_) { 244 for (auto* client : pending_clients_) {
249 if (result_ == Result::OK) { 245 if (result_ == Result::OK) {
250 AddInitialPorts(client); 246 AddInitialPorts(client);
251 clients_.insert(client); 247 clients_.insert(client);
252 } 248 }
253 client->CompleteStartSession(result_); 249 client->CompleteStartSession(result_);
254 } 250 }
255 pending_clients_.clear(); 251 pending_clients_.clear();
(...skipping 12 matching lines...) Expand all
268 Finalize(); 264 Finalize();
269 base::AutoLock auto_lock(lock_); 265 base::AutoLock auto_lock(lock_);
270 finalized_ = true; 266 finalized_ = true;
271 267
272 // Detach all clients so that they do not call MidiManager methods any more. 268 // Detach all clients so that they do not call MidiManager methods any more.
273 for (auto* client : clients_) 269 for (auto* client : clients_)
274 client->Detach(); 270 client->Detach();
275 } 271 }
276 272
277 } // namespace midi 273 } // namespace midi
OLDNEW
« media/midi/midi_manager.h ('K') | « media/midi/midi_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698