mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge pull request #230 from TomHarte/CyclicShutdown
Eliminates potential cyclic entry into CSMachine during its `-dealloc`.
This commit is contained in:
commit
a5f9869769
@ -19,26 +19,38 @@
|
|||||||
- (void)machineDidChangeClockIsUnlimited;
|
- (void)machineDidChangeClockIsUnlimited;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
struct SpeakerDelegate: public Outputs::Speaker::Delegate {
|
struct LockProtectedDelegate {
|
||||||
__weak CSMachine *machine;
|
// Contractual promise is: machine — the pointer **and** the object ** — may be accessed only
|
||||||
|
// in sections protected by the machineAccessLock;
|
||||||
|
NSLock *machineAccessLock;
|
||||||
|
__unsafe_unretained CSMachine *machine;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpeakerDelegate: public Outputs::Speaker::Delegate, public LockProtectedDelegate {
|
||||||
void speaker_did_complete_samples(Outputs::Speaker *speaker, const std::vector<int16_t> &buffer) {
|
void speaker_did_complete_samples(Outputs::Speaker *speaker, const std::vector<int16_t> &buffer) {
|
||||||
|
[machineAccessLock lock];
|
||||||
[machine speaker:speaker didCompleteSamples:buffer.data() length:(int)buffer.size()];
|
[machine speaker:speaker didCompleteSamples:buffer.data() length:(int)buffer.size()];
|
||||||
|
[machineAccessLock unlock];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MachineDelegate: CRTMachine::Machine::Delegate {
|
struct MachineDelegate: CRTMachine::Machine::Delegate, public LockProtectedDelegate {
|
||||||
__weak CSMachine *machine;
|
|
||||||
void machine_did_change_clock_rate(CRTMachine::Machine *sender) {
|
void machine_did_change_clock_rate(CRTMachine::Machine *sender) {
|
||||||
|
[machineAccessLock lock];
|
||||||
[machine machineDidChangeClockRate];
|
[machine machineDidChangeClockRate];
|
||||||
|
[machineAccessLock unlock];
|
||||||
}
|
}
|
||||||
void machine_did_change_clock_is_unlimited(CRTMachine::Machine *sender) {
|
void machine_did_change_clock_is_unlimited(CRTMachine::Machine *sender) {
|
||||||
|
[machineAccessLock lock];
|
||||||
[machine machineDidChangeClockIsUnlimited];
|
[machine machineDidChangeClockIsUnlimited];
|
||||||
|
[machineAccessLock unlock];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@implementation CSMachine {
|
@implementation CSMachine {
|
||||||
SpeakerDelegate _speakerDelegate;
|
SpeakerDelegate _speakerDelegate;
|
||||||
MachineDelegate _machineDelegate;
|
MachineDelegate _machineDelegate;
|
||||||
|
NSLock *_delegateMachineAccessLock;
|
||||||
CRTMachine::Machine *_machine;
|
CRTMachine::Machine *_machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,8 +58,12 @@ struct MachineDelegate: CRTMachine::Machine::Delegate {
|
|||||||
self = [super init];
|
self = [super init];
|
||||||
if(self) {
|
if(self) {
|
||||||
_machine = (CRTMachine::Machine *)machine;
|
_machine = (CRTMachine::Machine *)machine;
|
||||||
|
_delegateMachineAccessLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
_machineDelegate.machine = self;
|
_machineDelegate.machine = self;
|
||||||
_speakerDelegate.machine = self;
|
_speakerDelegate.machine = self;
|
||||||
|
_machineDelegate.machineAccessLock = _delegateMachineAccessLock;
|
||||||
|
_speakerDelegate.machineAccessLock = _delegateMachineAccessLock;
|
||||||
|
|
||||||
_machine->set_delegate(&_machineDelegate);
|
_machine->set_delegate(&_machineDelegate);
|
||||||
}
|
}
|
||||||
@ -67,6 +83,17 @@ struct MachineDelegate: CRTMachine::Machine::Delegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
|
// The two delegate's references to this machine are nilled out here because close_output may result
|
||||||
|
// in a data flush, which might cause an audio callback, which could cause the audio queue to decide
|
||||||
|
// that it's out of data, resulting in an attempt further to run the machine while it is dealloc'ing.
|
||||||
|
//
|
||||||
|
// They are nilled inside an explicit lock because that allows the delegates to protect their entire
|
||||||
|
// call into the machine, not just the pointer access.
|
||||||
|
[_delegateMachineAccessLock lock];
|
||||||
|
_machineDelegate.machine = nil;
|
||||||
|
_speakerDelegate.machine = nil;
|
||||||
|
[_delegateMachineAccessLock unlock];
|
||||||
|
|
||||||
[_view performWithGLContext:^{
|
[_view performWithGLContext:^{
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_machine->close_output();
|
_machine->close_output();
|
||||||
@ -77,8 +104,7 @@ struct MachineDelegate: CRTMachine::Machine::Delegate {
|
|||||||
- (float)idealSamplingRateFromRange:(NSRange)range {
|
- (float)idealSamplingRateFromRange:(NSRange)range {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
std::shared_ptr<Outputs::Speaker> speaker = _machine->get_speaker();
|
std::shared_ptr<Outputs::Speaker> speaker = _machine->get_speaker();
|
||||||
if(speaker)
|
if(speaker) {
|
||||||
{
|
|
||||||
return speaker->get_ideal_clock_rate_in_range((float)range.location, (float)(range.location + range.length));
|
return speaker->get_ideal_clock_rate_in_range((float)range.location, (float)(range.location + range.length));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -94,8 +120,7 @@ struct MachineDelegate: CRTMachine::Machine::Delegate {
|
|||||||
- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(float)sampleRate bufferSize:(NSUInteger)bufferSize {
|
- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(float)sampleRate bufferSize:(NSUInteger)bufferSize {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
std::shared_ptr<Outputs::Speaker> speaker = _machine->get_speaker();
|
std::shared_ptr<Outputs::Speaker> speaker = _machine->get_speaker();
|
||||||
if(speaker)
|
if(speaker) {
|
||||||
{
|
|
||||||
speaker->set_output_rate(sampleRate, (int)bufferSize);
|
speaker->set_output_rate(sampleRate, (int)bufferSize);
|
||||||
speaker->set_delegate(delegate);
|
speaker->set_delegate(delegate);
|
||||||
return YES;
|
return YES;
|
||||||
|
Loading…
Reference in New Issue
Block a user