Fixed race condition in MPU401 shutdown
svn-id: r8432
This commit is contained in:
parent
167ad2575a
commit
d2c952b315
8 changed files with 43 additions and 21 deletions
|
@ -90,6 +90,8 @@ int MidiDriver_CORE::open() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiDriver_CORE::close() {
|
void MidiDriver_CORE::close() {
|
||||||
|
MidiDriver_MPU401::close();
|
||||||
|
|
||||||
// Stop the output
|
// Stop the output
|
||||||
AudioOutputUnitStop(au_output);
|
AudioOutputUnitStop(au_output);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ int MidiDriver_ETUDE::open()
|
||||||
|
|
||||||
void MidiDriver_ETUDE::close()
|
void MidiDriver_ETUDE::close()
|
||||||
{
|
{
|
||||||
|
MidiDriver_MPU401::close();
|
||||||
exit_morphos_music();
|
exit_morphos_music();
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
class MidiDriver_NULL : public MidiDriver_MPU401 {
|
class MidiDriver_NULL : public MidiDriver_MPU401 {
|
||||||
public:
|
public:
|
||||||
int open();
|
int open();
|
||||||
void close() { }
|
|
||||||
void send(uint32 b) { }
|
void send(uint32 b) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,8 @@ bail:
|
||||||
|
|
||||||
void MidiDriver_QT::close()
|
void MidiDriver_QT::close()
|
||||||
{
|
{
|
||||||
|
MidiDriver_MPU401::close();
|
||||||
|
|
||||||
for (int i = 0; i < 15; i++) {
|
for (int i = 0; i < 15; i++) {
|
||||||
if (qtNoteChannel[i] != NULL)
|
if (qtNoteChannel[i] != NULL)
|
||||||
NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]);
|
NADisposeNoteChannel(qtNoteAllocator, qtNoteChannel[i]);
|
||||||
|
|
|
@ -87,6 +87,7 @@ int MidiDriver_SEQ::open() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiDriver_SEQ::close() {
|
void MidiDriver_SEQ::close() {
|
||||||
|
MidiDriver_MPU401::close();
|
||||||
::close(device);
|
::close(device);
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ void MidiDriver_WIN::close() {
|
||||||
if (!_isOpen)
|
if (!_isOpen)
|
||||||
return;
|
return;
|
||||||
_isOpen = false;
|
_isOpen = false;
|
||||||
|
MidiDriver_MPU401::close();
|
||||||
midiOutUnprepareHeader (_mo, &_streamHeader, sizeof (_streamHeader));
|
midiOutUnprepareHeader (_mo, &_streamHeader, sizeof (_streamHeader));
|
||||||
check_error(midiOutClose(_mo));
|
check_error(midiOutClose(_mo));
|
||||||
CloseHandle (_streamEvent);
|
CloseHandle (_streamEvent);
|
||||||
|
|
|
@ -76,18 +76,29 @@ const char *MidiDriver::getErrorName(int error_code) {
|
||||||
return midi_errors[error_code];
|
return midi_errors[error_code];
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiDriver_MPU401::MidiDriver_MPU401() : MidiDriver() {
|
MidiDriver_MPU401::MidiDriver_MPU401() :
|
||||||
|
MidiDriver(),
|
||||||
|
_started_thread (false),
|
||||||
|
_timer_proc (0),
|
||||||
|
_timer_param (0),
|
||||||
|
_mutex (0)
|
||||||
|
{
|
||||||
|
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
_started_thread = false; // palmos
|
|
||||||
_timer_proc = NULL; // palmos
|
|
||||||
_timer_param = NULL; // palmos
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) {
|
for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) {
|
||||||
_midi_channels [i].init (this, i);
|
_midi_channels [i].init (this, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MidiDriver_MPU401::close() {
|
||||||
|
if (_mutex) {
|
||||||
|
_started_thread = false;
|
||||||
|
g_system->lock_mutex (_mutex); // Wait for the timer thread to shutdown.
|
||||||
|
g_system->unlock_mutex (_mutex);
|
||||||
|
g_system->delete_mutex (_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MidiChannel *MidiDriver_MPU401::allocateChannel() {
|
MidiChannel *MidiDriver_MPU401::allocateChannel() {
|
||||||
MidiChannel_MPU401 *chan;
|
MidiChannel_MPU401 *chan;
|
||||||
uint i;
|
uint i;
|
||||||
|
@ -106,40 +117,45 @@ MidiChannel *MidiDriver_MPU401::allocateChannel() {
|
||||||
|
|
||||||
void MidiDriver_MPU401::setTimerCallback (void *timer_param, void (*timer_proc) (void *)) {
|
void MidiDriver_MPU401::setTimerCallback (void *timer_param, void (*timer_proc) (void *)) {
|
||||||
if (!_timer_proc || !timer_proc) {
|
if (!_timer_proc || !timer_proc) {
|
||||||
_timer_proc = (TimerCallback *) timer_proc;
|
_timer_proc = timer_proc;
|
||||||
_timer_param = timer_param;
|
_timer_param = timer_param;
|
||||||
if (!_started_thread && timer_proc) {
|
if (!_started_thread && timer_proc) {
|
||||||
// TODO: This is the only place in ScummVM where create_thread is
|
// TODO: This is the only place in ScummVM where create_thread is
|
||||||
// being used. And it's used for a timer like thread. So if we
|
// being used. And it's used for a timer like thread. So if we
|
||||||
// could convert it to use the timer API instead, we could get
|
// could convert it to use the timer API instead, we could get
|
||||||
// rid of create_thread completely.
|
// rid of create_thread completely.
|
||||||
|
_mutex = g_system->create_mutex();
|
||||||
|
_started_thread = true;
|
||||||
g_system->create_thread(midi_driver_thread, this);
|
g_system->create_thread(midi_driver_thread, this);
|
||||||
}
|
}
|
||||||
_started_thread = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__MORPHOS__) && !defined(__PALM_OS__)
|
#if !defined(__MORPHOS__) && !defined(__PALM_OS__)
|
||||||
|
typedef void (*TimerCallback) (void*);
|
||||||
|
|
||||||
int MidiDriver_MPU401::midi_driver_thread(void *param) {
|
int MidiDriver_MPU401::midi_driver_thread(void *param) {
|
||||||
volatile MidiDriver_MPU401 *mid = (MidiDriver_MPU401 *)param;
|
MidiDriver_MPU401 *mid = (MidiDriver_MPU401 *)param;
|
||||||
int old_time, cur_time;
|
int old_time, cur_time;
|
||||||
|
|
||||||
old_time = g_system->get_msecs();
|
// Grab the MidiDriver's mutex. When the MidiDriver
|
||||||
|
// shuts down, it will wait on that mutex until we've
|
||||||
|
// detected the shutdown and quit looping.
|
||||||
|
g_system->lock_mutex (mid->_mutex);
|
||||||
|
|
||||||
for (;;) {
|
old_time = g_system->get_msecs();
|
||||||
|
while (mid->_started_thread) {
|
||||||
g_system->delay_msecs(10);
|
g_system->delay_msecs(10);
|
||||||
|
|
||||||
cur_time = g_system->get_msecs();
|
cur_time = g_system->get_msecs();
|
||||||
while (old_time < cur_time) {
|
while (old_time < cur_time) {
|
||||||
old_time += 10;
|
old_time += 10;
|
||||||
// Don't use mid->_se_on_timer()
|
|
||||||
// We must come in through IMuseMonitor to protect
|
|
||||||
// against conflicts with script access to IMuse.
|
|
||||||
if (mid->_timer_proc)
|
if (mid->_timer_proc)
|
||||||
(*(mid->_timer_proc)) (mid->_timer_param);
|
(*(TimerCallback)(mid->_timer_proc)) (mid->_timer_param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_system->unlock_mutex (mid->_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
typedef void TimerCallback (void *);
|
|
||||||
|
|
||||||
class MidiDriver_MPU401;
|
class MidiDriver_MPU401;
|
||||||
|
|
||||||
class MidiChannel_MPU401 : public MidiChannel {
|
class MidiChannel_MPU401 : public MidiChannel {
|
||||||
|
@ -78,8 +76,9 @@ public:
|
||||||
class MidiDriver_MPU401 : public MidiDriver {
|
class MidiDriver_MPU401 : public MidiDriver {
|
||||||
private:
|
private:
|
||||||
MidiChannel_MPU401 _midi_channels [16];
|
MidiChannel_MPU401 _midi_channels [16];
|
||||||
bool _started_thread;
|
volatile bool _started_thread;
|
||||||
TimerCallback *_timer_proc;
|
void *_mutex; // Concurrent shutdown barrier
|
||||||
|
volatile void *_timer_proc;
|
||||||
void *_timer_param;
|
void *_timer_param;
|
||||||
|
|
||||||
static int midi_driver_thread (void *param);
|
static int midi_driver_thread (void *param);
|
||||||
|
@ -87,8 +86,9 @@ private:
|
||||||
public:
|
public:
|
||||||
MidiDriver_MPU401();
|
MidiDriver_MPU401();
|
||||||
|
|
||||||
|
virtual void close();
|
||||||
void setTimerCallback(void *timer_param, void (*timer_proc) (void *));
|
void setTimerCallback(void *timer_param, void (*timer_proc) (void *));
|
||||||
uint32 getBaseTempo(void) { return 10000; } // 0x4A0000; } // Now referenced in microseconds between callbacks
|
uint32 getBaseTempo(void) { return 10000; }
|
||||||
|
|
||||||
MidiChannel *allocateChannel();
|
MidiChannel *allocateChannel();
|
||||||
MidiChannel *getPercussionChannel() { return &_midi_channels [9]; }
|
MidiChannel *getPercussionChannel() { return &_midi_channels [9]; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue