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

Unified Diff: media/midi/midi_manager.cc

Issue 1315793008: Web MIDI: introduce MidiManager::Shutdown to shutdown gracefully (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: build fix (mac typo) Created 5 years, 2 months 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 side-by-side diff with in-line comments
Download patch
Index: media/midi/midi_manager.cc
diff --git a/media/midi/midi_manager.cc b/media/midi/midi_manager.cc
index 6e8c1a266fa86502407d929db218eb1e85afc1f5..9acd49126274dd0c49b8ed38371ec55c0322d98c 100644
--- a/media/midi/midi_manager.cc
+++ b/media/midi/midi_manager.cc
@@ -34,6 +34,13 @@ enum class Usage {
MAX = INITIALIZED,
};
+// Used in StartSession.
+enum class Completion {
+ COMPLETE_SYNCHRONOUSLY,
+ INVOKE_INITIALIZATION,
+ COMPLETE_ASYNCHRONOUSLY,
+};
+
void ReportUsage(Usage usage) {
UMA_HISTOGRAM_ENUMERATION("Media.Midi.Usage",
static_cast<Sample>(usage),
@@ -43,14 +50,14 @@ void ReportUsage(Usage usage) {
} // namespace
MidiManager::MidiManager()
- : initialized_(false), result_(Result::NOT_INITIALIZED) {
+ : initialized_(false), finalized_(false), result_(Result::NOT_INITIALIZED) {
ReportUsage(Usage::CREATED);
}
MidiManager::~MidiManager() {
- UMA_HISTOGRAM_ENUMERATION("Media.Midi.ResultOnShutdown",
- static_cast<Sample>(result_),
- static_cast<Sample>(Result::MAX) + 1);
+ // Make sure that Finalize() is called to clean up resources allocated on
+ // the Chrome_IOThread.
+ DCHECK(finalized_);
}
#if !defined(OS_MACOSX) && !defined(OS_WIN) && \
@@ -61,66 +68,74 @@ MidiManager* MidiManager::Create() {
}
#endif
+void MidiManager::Shutdown() {
+ UMA_HISTOGRAM_ENUMERATION("Media.Midi.ResultOnShutdown",
+ static_cast<int>(result_),
+ static_cast<int>(Result::MAX) + 1);
+ base::AutoLock auto_lock(lock_);
+ if (session_thread_runner_) {
+ session_thread_runner_->PostTask(
+ FROM_HERE, base::Bind(&MidiManager::ShutdownOnSessionThread,
+ base::Unretained(this)));
+ session_thread_runner_ = nullptr;
+ } else {
+ finalized_ = true;
+ }
+}
+
void MidiManager::StartSession(MidiManagerClient* client) {
ReportUsage(Usage::SESSION_STARTED);
- bool session_is_ready;
- bool session_needs_initialization = false;
- bool too_many_pending_clients_exist = false;
+ Completion completion = Completion::COMPLETE_SYNCHRONOUSLY;
+ Result result = Result::NOT_INITIALIZED;
{
base::AutoLock auto_lock(lock_);
- session_is_ready = initialized_;
if (clients_.find(client) != clients_.end() ||
pending_clients_.find(client) != pending_clients_.end()) {
// Should not happen. But just in case the renderer is compromised.
NOTREACHED();
return;
}
- if (!session_is_ready) {
- // Do not accept a new request if the pending client list contains too
- // many clients.
- too_many_pending_clients_exist =
- pending_clients_.size() >= kMaxPendingClientCount;
- if (!too_many_pending_clients_exist) {
+ if (initialized_) {
+ // Platform dependent initialization was already finished for previously
+ // initialized clients.
+ if (result_ == Result::OK) {
+ AddInitialPorts(client);
+ clients_.insert(client);
+ }
+ // Complete synchronously with |result_|;
+ result = result_;
+ } else {
+ bool too_many_pending_clients_exist =
+ pending_clients_.size() >= kMaxPendingClientCount;
+ // Do not accept a new request if the pending client list contains too
+ // many clients, or Shutdown() was already called.
+ if (too_many_pending_clients_exist || finalized_) {
+ result = Result::INITIALIZATION_ERROR;
+ } else {
// Call StartInitialization() only for the first request.
- session_needs_initialization = pending_clients_.empty();
+ if (pending_clients_.empty()) {
+ completion = Completion::INVOKE_INITIALIZATION;
+ session_thread_runner_ = base::MessageLoop::current()->task_runner();
+ } else {
+ completion = Completion::COMPLETE_ASYNCHRONOUSLY;
+ }
pending_clients_.insert(client);
}
}
}
- // Lazily initialize the MIDI back-end.
- if (!session_is_ready) {
- if (session_needs_initialization) {
- TRACE_EVENT0("midi", "MidiManager::StartInitialization");
- session_thread_runner_ =
- base::MessageLoop::current()->task_runner();
- StartInitialization();
- }
- if (too_many_pending_clients_exist) {
- // Return an error immediately if there are too many requests.
- client->CompleteStartSession(Result::INITIALIZATION_ERROR);
- return;
- }
+ if (completion == Completion::COMPLETE_SYNCHRONOUSLY) {
+ client->CompleteStartSession(result);
+ } else if (completion == Completion::INVOKE_INITIALIZATION) {
+ // Lazily initialize the MIDI back-end.
+ TRACE_EVENT0("midi", "MidiManager::StartInitialization");
// CompleteInitialization() will be called asynchronously when platform
// dependent initialization is finished.
- return;
+ StartInitialization();
}
-
- // Platform dependent initialization was already finished for previously
- // initialized clients.
- Result result;
- {
- base::AutoLock auto_lock(lock_);
- if (result_ == Result::OK) {
- AddInitialPorts(client);
- clients_.insert(client);
- }
- result = result_;
- }
- client->CompleteStartSession(result);
}
void MidiManager::EndSession(MidiManagerClient* client) {
@@ -154,14 +169,12 @@ void MidiManager::StartInitialization() {
}
void MidiManager::CompleteInitialization(Result result) {
- DCHECK(session_thread_runner_.get());
- // It is safe to post a task to the IO thread from here because the IO thread
- // should have stopped if the MidiManager is going to be destructed.
- session_thread_runner_->PostTask(
- FROM_HERE,
- base::Bind(&MidiManager::CompleteInitializationInternal,
- base::Unretained(this),
- result));
+ base::AutoLock auto_lock(lock_);
+ if (session_thread_runner_) {
+ session_thread_runner_->PostTask(
+ FROM_HERE, base::Bind(&MidiManager::CompleteInitializationInternal,
+ base::Unretained(this), result));
+ }
}
void MidiManager::AddInputPort(const MidiPortInfo& info) {
@@ -242,5 +255,15 @@ void MidiManager::AddInitialPorts(MidiManagerClient* client) {
client->AddOutputPort(info);
}
+void MidiManager::ShutdownOnSessionThread() {
+ Finalize();
+ base::AutoLock auto_lock(lock_);
+ finalized_ = true;
+
+ // Detach all clients so that they do not call MidiManager methods any more.
+ for (auto client : clients_)
+ client->Detached();
+}
+
} // namespace midi
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698