~mixxxdevelopers/mixxx/fixes_soundcardSync

« back to all changes in this revision

Viewing changes to mixxx/src/midi/mididevice.cpp

  • Committer: Albert Santoni
  • Date: 2010-11-02 06:39:35 UTC
  • Revision ID: alberts@mixxx.org-20101102063935-vaur40f1nsx1aqh7
* Renamed m_mappingMutex to m_mappingPtrMutex for a little bit more clarity.
* Added an m_bSendInhibit flag (setSendInhibit(bool)) that prevents a race condition when the MIDI scripting engine tries to send a message while we're shutting it down.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    m_bIsOpen = false;
43
43
    m_bMidiLearn = false;
44
44
    m_bReceiveInhibit = false;
 
45
    m_bSendInhibit = false;
45
46
 
46
47
    if (m_pMidiMapping == NULL) {
47
48
        m_pMidiMapping = new MidiMapping(this);
60
61
    QMutexLocker locker(&m_mutex);
61
62
 
62
63
    qDebug() << "MidiDevice: Deleting MidiMapping...";
63
 
    m_mappingMutex.lock();
 
64
    m_mappingPtrMutex.lock();
64
65
    delete m_pMidiMapping;
65
 
    m_mappingMutex.unlock();
 
66
    m_mappingPtrMutex.unlock();
66
67
}
67
68
 
68
69
void MidiDevice::startup()
69
70
{
70
 
    m_mappingMutex.lock();
 
71
    QMutexLocker locker(&m_mappingPtrMutex);
71
72
#ifdef __MIDISCRIPT__
 
73
    setReceiveInhibit(true);
72
74
    m_pMidiMapping->startupScriptEngine();
 
75
    setReceiveInhibit(false);
73
76
#endif
74
 
    m_mappingMutex.unlock();
75
77
}
76
78
 
77
79
void MidiDevice::shutdown()
78
80
{
79
 
    m_mappingMutex.lock();
 
81
    QMutexLocker locker(&m_mappingPtrMutex);
 
82
    //Stop us from processing any MIDI messages that are 
 
83
    //received while we're trying to shut down the scripting engine.
 
84
    //This prevents a deadlock that can happen because we've locked 
 
85
    //the MIDI mapping pointer mutex (in the line above). If a
 
86
    //MIDI message is received while this is locked, the script
 
87
    //engine can end up waiting for the MIDI message to be
 
88
    //mapped and we end up with a deadlock.
 
89
    //Similarly, if a MIDI message is sent from the scripting 
 
90
    //engine while we've held this lock, we'll end up with
 
91
    //a similar deadlock. (Note that shutdownScriptEngin()
 
92
    //waits for the scripting engine thread to terminate,
 
93
    //which will never happen if it's stuck waiting for 
 
94
    //m_mappingPtrMutex to unlock.
 
95
    setReceiveInhibit(true);
 
96
    setSendInhibit(true);
80
97
#ifdef __MIDISCRIPT__
81
98
    m_pMidiMapping->shutdownScriptEngine();
82
99
#endif
83
 
    m_mappingMutex.unlock();
 
100
    setReceiveInhibit(false);
 
101
    setSendInhibit(false);
84
102
}
85
103
 
86
104
void MidiDevice::setMidiMapping(MidiMapping* mapping)
87
105
{
88
106
    m_mutex.lock();
89
 
    m_mappingMutex.lock();
 
107
    m_mappingPtrMutex.lock();
90
108
    m_pMidiMapping = mapping;
91
 
    
 
109
 
92
110
    if (m_pCorrespondingOutputDevice)
93
111
    {
94
112
        m_pCorrespondingOutputDevice->setMidiMapping(m_pMidiMapping);
95
113
    }
96
 
    m_mappingMutex.unlock();
 
114
    m_mappingPtrMutex.unlock();
97
115
    m_mutex.unlock();
98
116
}
99
117
 
141
159
    m_bMidiLearn = true;
142
160
    m_mutex.unlock();
143
161
 
144
 
    m_mappingMutex.lock();
 
162
    m_mappingPtrMutex.lock();
145
163
    connect(this, SIGNAL(midiEvent(MidiMessage)), m_pMidiMapping, SLOT(finishMidiLearn(MidiMessage)));
146
 
    m_mappingMutex.unlock();
 
164
    m_mappingPtrMutex.unlock();
147
165
}
148
166
 
149
167
void MidiDevice::disableMidiLearn() {
151
169
    m_bMidiLearn = false;
152
170
    m_mutex.unlock();
153
171
 
154
 
    m_mappingMutex.lock();
 
172
    m_mappingPtrMutex.lock();
155
173
    disconnect(this, SIGNAL(midiEvent(MidiMessage)), m_pMidiMapping, SLOT(finishMidiLearn(MidiMessage)));
156
 
    m_mappingMutex.unlock();
 
174
    m_mappingPtrMutex.unlock();
157
175
}
158
176
 
159
177
void MidiDevice::receive(MidiStatusByte status, char channel, char control, char value)
183
201
        return; // Don't process midi messages further when MIDI learning
184
202
    }
185
203
 
186
 
    QMutexLocker mappingLocker(&m_mappingMutex);
 
204
    QMutexLocker mappingLocker(&m_mappingPtrMutex);
187
205
 
188
206
    // Only check for a mapping if the status byte is one we know how to handle
189
207
    if (status == MIDI_STATUS_NOTE_ON 
259
277
    QMutexLocker locker(&m_mutex);
260
278
    m_bReceiveInhibit = inhibit;
261
279
}
 
280
 
 
281
void MidiDevice::setSendInhibit(bool inhibit)
 
282
{
 
283
    //See comments for m_bSendInhibit.
 
284
    QMutexLocker locker(&m_mutex);
 
285
    m_bSendInhibit = inhibit;
 
286
}