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

Unified Diff: media/midi/midi_manager_alsa.cc

Issue 2673423002: Web MIDI: add dynamic MidiManager instantiation support for Linux (Closed)
Patch Set: rebase again Created 3 years, 10 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
« no previous file with comments | « media/midi/midi_manager_alsa.h ('k') | media/midi/midi_manager_android.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/midi/midi_manager_alsa.cc
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc
index d99751bff01be9161f404b4681d980b7b54d839d..05efb49be60fd66817a44cd2e928d6646ef53dd6 100644
--- a/media/midi/midi_manager_alsa.cc
+++ b/media/midi/midi_manager_alsa.cc
@@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/json/json_string_value_serializer.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -27,6 +28,7 @@
#include "base/time/time.h"
#include "crypto/sha2.h"
#include "media/midi/midi_port_info.h"
+#include "media/midi/midi_service.h"
namespace midi {
@@ -35,6 +37,10 @@ namespace {
using mojom::PortState;
using mojom::Result;
+// TODO(toyoshim): use constexpr for following const values.
+const int kEventTaskRunner = 0;
+const int kSendTaskRunner = 1;
+
// Per-output buffer. This can be smaller, but then large sysex messages
// will be (harmlessly) split across multiple seq events. This should
// not have any real practical effect, except perhaps to slightly reorder
@@ -90,6 +96,17 @@ const unsigned int kCreateInputPortCaps =
const unsigned int kCreatePortType =
SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION;
+// Global variables to identify MidiManagerAlsa instance.
+const int kInvalidInstanceId = -1;
+int g_active_instance_id = kInvalidInstanceId;
+int g_next_instance_id = 0;
+base::LazyInstance<base::Lock> g_instance_id_lock = LAZY_INSTANCE_INITIALIZER;
+
+// Prevent current instance from quiting Finalize() while tasks run on external
+// TaskRunners.
+base::LazyInstance<base::Lock> g_event_task_lock = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Lock> g_send_task_lock = LAZY_INSTANCE_INITIALIZER;
+
int AddrToInt(int client, int port) {
return (client << 8) | port;
}
@@ -153,8 +170,7 @@ void SetStringIfNonEmpty(base::DictionaryValue* value,
} // namespace
-MidiManagerAlsa::MidiManagerAlsa()
- : event_thread_("MidiEventThread"), send_thread_("MidiSendThread") {}
+MidiManagerAlsa::MidiManagerAlsa(MidiService* service) : MidiManager(service) {}
MidiManagerAlsa::~MidiManagerAlsa() {
// Take lock to ensure that the members initialized on the IO thread
@@ -169,11 +185,18 @@ MidiManagerAlsa::~MidiManagerAlsa() {
CHECK(!udev_);
CHECK(!udev_monitor_);
- CHECK(!send_thread_.IsRunning());
- CHECK(!event_thread_.IsRunning());
+ base::AutoLock instance_id_lock(g_instance_id_lock.Get());
+ CHECK_EQ(kInvalidInstanceId, g_active_instance_id);
}
void MidiManagerAlsa::StartInitialization() {
+ {
+ base::AutoLock lock(g_instance_id_lock.Get());
+ CHECK_EQ(kInvalidInstanceId, g_active_instance_id);
+ instance_id_ = g_next_instance_id++;
+ g_active_instance_id = instance_id_;
+ }
+
base::AutoLock lock(lazy_init_member_lock_);
initialization_thread_checker_.reset(new base::ThreadChecker());
@@ -288,11 +311,10 @@ void MidiManagerAlsa::StartInitialization() {
// Start processing events. Don't do this before enumeration of both
// ALSA and udev.
- event_thread_.Start();
- event_thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&MidiManagerAlsa::ScheduleEventLoop, base::Unretained(this)));
- send_thread_.Start();
+ service()
+ ->GetTaskRunner(kEventTaskRunner)
+ ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop,
+ base::Unretained(this), instance_id_));
CompleteInitialization(Result::OK);
}
@@ -301,23 +323,24 @@ void MidiManagerAlsa::Finalize() {
base::AutoLock lock(lazy_init_member_lock_);
DCHECK(initialization_thread_checker_->CalledOnValidThread());
- // Tell the event thread it will soon be time to shut down. This gives
- // us assurance the thread will stop in case the SND_SEQ_EVENT_CLIENT_EXIT
- // message is lost.
+ // Tell tasks running on TaskRunners it will soon be time to shut down. This
+ // gives us assurance a task running on kEventTaskRunner will stop in case the
+ // SND_SEQ_EVENT_CLIENT_EXIT message is lost.
{
- base::AutoLock lock(shutdown_lock_);
- event_thread_shutdown_ = true;
+ base::AutoLock lock(g_instance_id_lock.Get());
+ CHECK_EQ(instance_id_, g_active_instance_id);
+ g_active_instance_id = kInvalidInstanceId;
}
- // Stop the send thread.
- send_thread_.Stop();
+ // Ensure that no tasks run on kSendTaskRunner.
+ base::AutoLock send_runner_lock(g_send_task_lock.Get());
// Close the out client. This will trigger the event thread to stop,
// because of SND_SEQ_EVENT_CLIENT_EXIT.
out_client_.reset();
- // Wait for the event thread to stop.
- event_thread_.Stop();
+ // Ensure that no tasks run on kEventTaskRunner.
+ base::AutoLock event_runner_lock(g_event_task_lock.Get());
// Destruct the other stuff we initialized in StartInitialization().
udev_monitor_.reset();
@@ -339,15 +362,13 @@ void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client,
delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta());
}
- send_thread_.task_runner()->PostDelayedTask(
- FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData,
- base::Unretained(this), port_index, data),
- delay);
-
- // Acknowledge send.
- send_thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&MidiManagerAlsa::AccumulateMidiBytesSent,
- base::Unretained(this), client, data.size()));
+ service()
+ ->GetTaskRunner(kSendTaskRunner)
+ ->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&MidiManagerAlsa::SendMidiData, base::Unretained(this),
+ instance_id_, client, port_index, data),
+ delay);
}
MidiManagerAlsa::MidiPort::Id::Id() = default;
@@ -864,9 +885,22 @@ std::string MidiManagerAlsa::AlsaCard::ExtractManufacturerString(
return "";
}
-void MidiManagerAlsa::SendMidiData(uint32_t port_index,
+void MidiManagerAlsa::SendMidiData(int instance_id,
+ MidiManagerClient* client,
+ uint32_t port_index,
const std::vector<uint8_t>& data) {
- DCHECK(send_thread_.task_runner()->BelongsToCurrentThread());
+ DCHECK(service()->GetTaskRunner(kSendTaskRunner)->BelongsToCurrentThread());
+
+ // Obtain the lock so that the instance could not be destructed while this
+ // method is running on the kSendTaskRunner.
+ base::AutoLock lock(g_send_task_lock.Get());
+ {
+ // Check if Finalize() already runs. After this check, we can access |this|
+ // safely on the kEventTaskRunner.
+ base::AutoLock instance_id_lock(g_instance_id_lock.Get());
+ if (instance_id != g_active_instance_id)
+ return;
+ }
snd_midi_event_t* encoder;
snd_midi_event_new(kSendBufferSize, &encoder);
@@ -886,15 +920,23 @@ void MidiManagerAlsa::SendMidiData(uint32_t port_index,
}
}
snd_midi_event_free(encoder);
-}
-void MidiManagerAlsa::ScheduleEventLoop() {
- event_thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this)));
+ // Acknowledge send.
+ AccumulateMidiBytesSent(client, data.size());
}
-void MidiManagerAlsa::EventLoop() {
+void MidiManagerAlsa::EventLoop(int instance_id) {
+ // Obtain the lock so that the instance could not be destructed while this
+ // method is running on the kEventTaskRunner.
+ base::AutoLock lock(g_event_task_lock.Get());
+ {
+ // Check if Finalize() already runs. After this check, we can access |this|
+ // safely on the kEventTaskRunner.
+ base::AutoLock instance_id_lock(g_instance_id_lock.Get());
+ if (instance_id != g_active_instance_id)
+ return;
+ }
+
bool loop_again = true;
struct pollfd pfd[2];
@@ -922,9 +964,6 @@ void MidiManagerAlsa::EventLoop() {
VLOG(1) << "snd_seq_event_input detected buffer overrun";
// We've lost events: check another way to see if we need to shut
// down.
- base::AutoLock lock(shutdown_lock_);
- if (event_thread_shutdown_)
- loop_again = false;
} else if (err == -EAGAIN) {
// We've read all the data.
} else if (err < 0) {
@@ -973,8 +1012,12 @@ void MidiManagerAlsa::EventLoop() {
}
// Do again.
- if (loop_again)
- ScheduleEventLoop();
+ if (loop_again) {
+ service()
+ ->GetTaskRunner(kEventTaskRunner)
+ ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop,
+ base::Unretained(this), instance_id));
+ }
}
void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event,
@@ -1401,8 +1444,8 @@ bool MidiManagerAlsa::Subscribe(uint32_t port_index,
return true;
}
-MidiManager* MidiManager::Create() {
- return new MidiManagerAlsa();
+MidiManager* MidiManager::Create(MidiService* service) {
+ return new MidiManagerAlsa(service);
}
} // namespace midi
« no previous file with comments | « media/midi/midi_manager_alsa.h ('k') | media/midi/midi_manager_android.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698