From 1e41898bbc944d8348310d3ff8e08775ae430aff Mon Sep 17 00:00:00 2001 From: hogliux Date: Mon, 1 Aug 2016 14:47:39 +0100 Subject: [PATCH] Fix a memory leak in linux ALSA code for MidiInput/MidiOutput --- .../native/juce_linux_Midi.cpp | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/modules/juce_audio_devices/native/juce_linux_Midi.cpp b/modules/juce_audio_devices/native/juce_linux_Midi.cpp index 04b9e89e49..1bea000bb5 100644 --- a/modules/juce_audio_devices/native/juce_linux_Midi.cpp +++ b/modules/juce_audio_devices/native/juce_linux_Midi.cpp @@ -45,31 +45,13 @@ class AlsaClient : public ReferenceCountedObject public: typedef ReferenceCountedObjectPtr Ptr; - AlsaClient (bool forInput) - : input (forInput), handle (nullptr) + static Ptr getInstance (bool forInput) { - snd_seq_open (&handle, "default", forInput ? SND_SEQ_OPEN_INPUT - : SND_SEQ_OPEN_OUTPUT, 0); + AlsaClient*& instance = (forInput ? inInstance : outInstance); + if (instance == nullptr) + instance = new AlsaClient (forInput); - snd_seq_set_client_name (handle, forInput ? JUCE_ALSA_MIDI_INPUT_NAME - : JUCE_ALSA_MIDI_OUTPUT_NAME); - } - - ~AlsaClient() - { - if (handle != nullptr) - { - snd_seq_close (handle); - handle = nullptr; - } - - jassert (activeCallbacks.size() == 0); - - if (inputThread) - { - inputThread->stopThread (3000); - inputThread = nullptr; - } + return instance; } bool isInput() const noexcept { return input; } @@ -113,6 +95,50 @@ private: Array activeCallbacks; CriticalSection callbackLock; + static AlsaClient* inInstance; + static AlsaClient* outInstance; + + //============================================================================== + friend class ReferenceCountedObjectPtr; + friend struct ContainerDeletePolicy; + + AlsaClient (bool forInput) + : input (forInput), handle (nullptr) + { + AlsaClient*& instance = (input ? inInstance : outInstance); + jassert (instance == nullptr); + + instance = this; + + snd_seq_open (&handle, "default", forInput ? SND_SEQ_OPEN_INPUT + : SND_SEQ_OPEN_OUTPUT, 0); + + snd_seq_set_client_name (handle, forInput ? JUCE_ALSA_MIDI_INPUT_NAME + : JUCE_ALSA_MIDI_OUTPUT_NAME); + } + + ~AlsaClient() + { + AlsaClient*& instance = (input ? inInstance : outInstance); + jassert (instance != nullptr); + + instance = nullptr; + + if (handle != nullptr) + { + snd_seq_close (handle); + handle = nullptr; + } + + jassert (activeCallbacks.size() == 0); + + if (inputThread) + { + inputThread->stopThread (3000); + inputThread = nullptr; + } + } + //============================================================================== class MidiInputThread : public Thread { @@ -181,24 +207,8 @@ private: ScopedPointer inputThread; }; - -static AlsaClient::Ptr globalAlsaSequencerIn() -{ - static AlsaClient::Ptr global (new AlsaClient (true)); - return global; -} - -static AlsaClient::Ptr globalAlsaSequencerOut() -{ - static AlsaClient::Ptr global (new AlsaClient (false)); - return global; -} - -static AlsaClient::Ptr globalAlsaSequencer (bool input) -{ - return input ? globalAlsaSequencerIn() - : globalAlsaSequencerOut(); -} +AlsaClient* AlsaClient::inInstance = nullptr; +AlsaClient* AlsaClient::outInstance = nullptr; //============================================================================== // represents an input or output port of the supplied AlsaClient @@ -368,7 +378,7 @@ static AlsaPort iterateMidiDevices (const bool forInput, const int deviceIndexToOpen) { AlsaPort port; - const AlsaClient::Ptr client (globalAlsaSequencer (forInput)); + const AlsaClient::Ptr client (AlsaClient::getInstance (forInput)); if (snd_seq_t* const seqHandle = client->get()) { @@ -509,7 +519,7 @@ MidiOutput* MidiOutput::createNewDevice (const String& deviceName) MidiOutput* newDevice = nullptr; AlsaPort port; - const AlsaClient::Ptr client (globalAlsaSequencer (false)); + const AlsaClient::Ptr client (AlsaClient::getInstance (false)); port.createPort (client, deviceName, false); @@ -589,7 +599,7 @@ MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallba MidiInput* newDevice = nullptr; AlsaPort port; - const AlsaClient::Ptr client (globalAlsaSequencer (true)); + const AlsaClient::Ptr client (AlsaClient::getInstance (true)); port.createPort (client, deviceName, true);