diff options
author | Jamieson Christian | 2003-06-11 05:54:46 +0000 |
---|---|---|
committer | Jamieson Christian | 2003-06-11 05:54:46 +0000 |
commit | d2c952b3154523a718c49df9b5a01318c4dc709c (patch) | |
tree | 63347cbfd537020aa4b9f661161711c42fdd1fba /sound | |
parent | 167ad2575a68ec09e6b855c8d3eb3cbc4cdcfeef (diff) | |
download | scummvm-rg350-d2c952b3154523a718c49df9b5a01318c4dc709c.tar.gz scummvm-rg350-d2c952b3154523a718c49df9b5a01318c4dc709c.tar.bz2 scummvm-rg350-d2c952b3154523a718c49df9b5a01318c4dc709c.zip |
Fixed race condition in MPU401 shutdown
svn-id: r8432
Diffstat (limited to 'sound')
-rw-r--r-- | sound/mpu401.cpp | 46 | ||||
-rw-r--r-- | sound/mpu401.h | 10 |
2 files changed, 36 insertions, 20 deletions
diff --git a/sound/mpu401.cpp b/sound/mpu401.cpp index cd435d5d95..39bfdef482 100644 --- a/sound/mpu401.cpp +++ b/sound/mpu401.cpp @@ -76,18 +76,29 @@ const char *MidiDriver::getErrorName(int error_code) { return midi_errors[error_code]; } -MidiDriver_MPU401::MidiDriver_MPU401() : MidiDriver() { - uint i; - - _started_thread = false; // palmos - _timer_proc = NULL; // palmos - _timer_param = NULL; // palmos +MidiDriver_MPU401::MidiDriver_MPU401() : + MidiDriver(), + _started_thread (false), + _timer_proc (0), + _timer_param (0), + _mutex (0) +{ + uint i; for (i = 0; i < ARRAYSIZE(_midi_channels); ++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_MPU401 *chan; uint i; @@ -106,40 +117,45 @@ MidiChannel *MidiDriver_MPU401::allocateChannel() { void MidiDriver_MPU401::setTimerCallback (void *timer_param, void (*timer_proc) (void *)) { if (!_timer_proc || !timer_proc) { - _timer_proc = (TimerCallback *) timer_proc; + _timer_proc = timer_proc; _timer_param = timer_param; if (!_started_thread && timer_proc) { // 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 // could convert it to use the timer API instead, we could get // rid of create_thread completely. + _mutex = g_system->create_mutex(); + _started_thread = true; g_system->create_thread(midi_driver_thread, this); } - _started_thread = true; } } #if !defined(__MORPHOS__) && !defined(__PALM_OS__) +typedef void (*TimerCallback) (void*); + 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; - 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); cur_time = g_system->get_msecs(); while (old_time < cur_time) { 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) - (*(mid->_timer_proc)) (mid->_timer_param); + (*(TimerCallback)(mid->_timer_proc)) (mid->_timer_param); } } + g_system->unlock_mutex (mid->_mutex); return 0; } #endif diff --git a/sound/mpu401.h b/sound/mpu401.h index ecf8cd0919..a85bb6af0c 100644 --- a/sound/mpu401.h +++ b/sound/mpu401.h @@ -30,8 +30,6 @@ // //////////////////////////////////////// -typedef void TimerCallback (void *); - class MidiDriver_MPU401; class MidiChannel_MPU401 : public MidiChannel { @@ -78,8 +76,9 @@ public: class MidiDriver_MPU401 : public MidiDriver { private: MidiChannel_MPU401 _midi_channels [16]; - bool _started_thread; - TimerCallback *_timer_proc; + volatile bool _started_thread; + void *_mutex; // Concurrent shutdown barrier + volatile void *_timer_proc; void *_timer_param; static int midi_driver_thread (void *param); @@ -87,8 +86,9 @@ private: public: MidiDriver_MPU401(); + virtual void close(); 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 *getPercussionChannel() { return &_midi_channels [9]; } |