mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-07 12:54:34 +00:00
Merge pull request #739 from TomHarte/SDLThreadSafety
Resolves thread safety issues in SDK kiosk mode.
This commit is contained in:
commit
c398aa60c1
@ -158,6 +158,8 @@
|
|||||||
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
|
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
|
||||||
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A471F9B8FA70062DABF /* Typer.cpp */; };
|
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A471F9B8FA70062DABF /* Typer.cpp */; };
|
||||||
4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A481F9B8FA70062DABF /* MemoryFuzzer.cpp */; };
|
4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A481F9B8FA70062DABF /* MemoryFuzzer.cpp */; };
|
||||||
|
4B2BF19123DCC6A200C3AD60 /* BD500.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA03523CEB86000B98D9E /* BD500.cpp */; };
|
||||||
|
4B2BF19223DCC6A800C3AD60 /* STX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA03323C58B1E00B98D9E /* STX.cpp */; };
|
||||||
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */; };
|
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */; };
|
||||||
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */; };
|
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */; };
|
||||||
4B2C45421E3C3896002A2389 /* cartridge.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B2C45411E3C3896002A2389 /* cartridge.png */; };
|
4B2C45421E3C3896002A2389 /* cartridge.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B2C45411E3C3896002A2389 /* cartridge.png */; };
|
||||||
@ -4252,6 +4254,7 @@
|
|||||||
4B055AD31FAE9B0B0060FFFF /* Microdisc.cpp in Sources */,
|
4B055AD31FAE9B0B0060FFFF /* Microdisc.cpp in Sources */,
|
||||||
4B055AB41FAE860F0060FFFF /* OricTAP.cpp in Sources */,
|
4B055AB41FAE860F0060FFFF /* OricTAP.cpp in Sources */,
|
||||||
4B055AB71FAE860F0060FFFF /* TZX.cpp in Sources */,
|
4B055AB71FAE860F0060FFFF /* TZX.cpp in Sources */,
|
||||||
|
4B2BF19123DCC6A200C3AD60 /* BD500.cpp in Sources */,
|
||||||
4B055ADA1FAE9B460060FFFF /* 1770.cpp in Sources */,
|
4B055ADA1FAE9B460060FFFF /* 1770.cpp in Sources */,
|
||||||
4B055ADC1FAE9B460060FFFF /* AY38910.cpp in Sources */,
|
4B055ADC1FAE9B460060FFFF /* AY38910.cpp in Sources */,
|
||||||
4B055AD71FAE9B180060FFFF /* Keyboard.cpp in Sources */,
|
4B055AD71FAE9B180060FFFF /* Keyboard.cpp in Sources */,
|
||||||
@ -4303,6 +4306,7 @@
|
|||||||
4BEBFB4E2002C4BF000708CC /* MSXDSK.cpp in Sources */,
|
4BEBFB4E2002C4BF000708CC /* MSXDSK.cpp in Sources */,
|
||||||
4B055ADD1FAE9B460060FFFF /* i8272.cpp in Sources */,
|
4B055ADD1FAE9B460060FFFF /* i8272.cpp in Sources */,
|
||||||
4B055A9C1FAE85DA0060FFFF /* CPCDSK.cpp in Sources */,
|
4B055A9C1FAE85DA0060FFFF /* CPCDSK.cpp in Sources */,
|
||||||
|
4B2BF19223DCC6A800C3AD60 /* STX.cpp in Sources */,
|
||||||
4B0ACC2723775819008902D0 /* AtariST.cpp in Sources */,
|
4B0ACC2723775819008902D0 /* AtariST.cpp in Sources */,
|
||||||
4B8318B922D3E56D006DB630 /* MemoryPacker.cpp in Sources */,
|
4B8318B922D3E56D006DB630 /* MemoryPacker.cpp in Sources */,
|
||||||
4B055ABA1FAE86170060FFFF /* Commodore.cpp in Sources */,
|
4B055ABA1FAE86170060FFFF /* Commodore.cpp in Sources */,
|
||||||
@ -5075,6 +5079,7 @@
|
|||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
OTHER_CPLUSPLUSFLAGS = (
|
OTHER_CPLUSPLUSFLAGS = (
|
||||||
"$(OTHER_CFLAGS)",
|
"$(OTHER_CFLAGS)",
|
||||||
"-Wreorder",
|
"-Wreorder",
|
||||||
@ -5121,6 +5126,7 @@
|
|||||||
GCC_WARN_UNUSED_LABEL = YES;
|
GCC_WARN_UNUSED_LABEL = YES;
|
||||||
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
INFOPLIST_FILE = "Clock Signal/Info.plist";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
OTHER_CPLUSPLUSFLAGS = (
|
OTHER_CPLUSPLUSFLAGS = (
|
||||||
"$(OTHER_CFLAGS)",
|
"$(OTHER_CFLAGS)",
|
||||||
"-Wreorder",
|
"-Wreorder",
|
||||||
|
@ -35,9 +35,11 @@ namespace {
|
|||||||
|
|
||||||
struct BestEffortUpdaterDelegate: public Concurrency::BestEffortUpdater::Delegate {
|
struct BestEffortUpdaterDelegate: public Concurrency::BestEffortUpdater::Delegate {
|
||||||
Time::Seconds update(Concurrency::BestEffortUpdater *updater, Time::Seconds duration, bool did_skip_previous_update, int flags) override {
|
Time::Seconds update(Concurrency::BestEffortUpdater *updater, Time::Seconds duration, bool did_skip_previous_update, int flags) override {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(*machine_mutex);
|
||||||
return machine->crt_machine()->run_until(duration, flags);
|
return machine->crt_machine()->run_until(duration, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::mutex *machine_mutex;
|
||||||
Machine::DynamicMachine *machine;
|
Machine::DynamicMachine *machine;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,6 +105,7 @@ class ActivityObserver: public Activity::Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set_aspect_ratio(float aspect_ratio) {
|
void set_aspect_ratio(float aspect_ratio) {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(mutex);
|
||||||
lights_.clear();
|
lights_.clear();
|
||||||
|
|
||||||
// Generate a bunch of LEDs for connected drives.
|
// Generate a bunch of LEDs for connected drives.
|
||||||
@ -129,6 +132,7 @@ class ActivityObserver: public Activity::Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void draw() {
|
void draw() {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(mutex);
|
||||||
for(const auto &lit_led: lit_leds_) {
|
for(const auto &lit_led: lit_leds_) {
|
||||||
if(blinking_leds_.find(lit_led) == blinking_leds_.end() && lights_.find(lit_led) != lights_.end())
|
if(blinking_leds_.find(lit_led) == blinking_leds_.end() && lights_.find(lit_led) != lights_.end())
|
||||||
lights_[lit_led]->draw(0.0, 0.8, 0.0);
|
lights_[lit_led]->draw(0.0, 0.8, 0.0);
|
||||||
@ -139,26 +143,31 @@ class ActivityObserver: public Activity::Observer {
|
|||||||
private:
|
private:
|
||||||
std::vector<std::string> leds_;
|
std::vector<std::string> leds_;
|
||||||
void register_led(const std::string &name) override {
|
void register_led(const std::string &name) override {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(mutex);
|
||||||
leds_.push_back(name);
|
leds_.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> drives_;
|
std::vector<std::string> drives_;
|
||||||
void register_drive(const std::string &name) override {
|
void register_drive(const std::string &name) override {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(mutex);
|
||||||
drives_.push_back(name);
|
drives_.push_back(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_led_status(const std::string &name, bool lit) override {
|
void set_led_status(const std::string &name, bool lit) override {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(mutex);
|
||||||
if(lit) lit_leds_.insert(name);
|
if(lit) lit_leds_.insert(name);
|
||||||
else lit_leds_.erase(name);
|
else lit_leds_.erase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void announce_drive_event(const std::string &name, DriveEvent event) override {
|
void announce_drive_event(const std::string &name, DriveEvent event) override {
|
||||||
|
std::lock_guard<std::mutex> lock_guard(mutex);
|
||||||
blinking_leds_.insert(name);
|
blinking_leds_.insert(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::unique_ptr<Outputs::Display::OpenGL::Rectangle>> lights_;
|
std::map<std::string, std::unique_ptr<Outputs::Display::OpenGL::Rectangle>> lights_;
|
||||||
std::set<std::string> lit_leds_;
|
std::set<std::string> lit_leds_;
|
||||||
std::set<std::string> blinking_leds_;
|
std::set<std::string> blinking_leds_;
|
||||||
|
std::mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool KeyboardKeyForSDLScancode(SDL_Keycode scancode, Inputs::Keyboard::Key &key) {
|
bool KeyboardKeyForSDLScancode(SDL_Keycode scancode, Inputs::Keyboard::Key &key) {
|
||||||
@ -442,6 +451,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Create and configure a machine.
|
// Create and configure a machine.
|
||||||
::Machine::Error error;
|
::Machine::Error error;
|
||||||
|
std::mutex machine_mutex;
|
||||||
std::unique_ptr<::Machine::DynamicMachine> machine(::Machine::MachineForTargets(targets, rom_fetcher, error));
|
std::unique_ptr<::Machine::DynamicMachine> machine(::Machine::MachineForTargets(targets, rom_fetcher, error));
|
||||||
if(!machine) {
|
if(!machine) {
|
||||||
switch(error) {
|
switch(error) {
|
||||||
@ -463,6 +473,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
best_effort_updater_delegate.machine = machine.get();
|
best_effort_updater_delegate.machine = machine.get();
|
||||||
|
best_effort_updater_delegate.machine_mutex = &machine_mutex;
|
||||||
speaker_delegate.updater = &updater;
|
speaker_delegate.updater = &updater;
|
||||||
updater.set_delegate(&best_effort_updater_delegate);
|
updater.set_delegate(&best_effort_updater_delegate);
|
||||||
|
|
||||||
@ -617,7 +628,17 @@ int main(int argc, char *argv[]) {
|
|||||||
bool should_quit = false;
|
bool should_quit = false;
|
||||||
Uint32 fullscreen_mode = 0;
|
Uint32 fullscreen_mode = 0;
|
||||||
while(!should_quit) {
|
while(!should_quit) {
|
||||||
// Process all pending events.
|
// Wait for vsync, draw a new frame and post a machine update.
|
||||||
|
// NB: machine_mutex is *not* currently locked, therefore it shouldn't
|
||||||
|
// be 'most' of the time.
|
||||||
|
SDL_GL_SwapWindow(window);
|
||||||
|
scan_target.update(int(window_width), int(window_height));
|
||||||
|
scan_target.draw(int(window_width), int(window_height));
|
||||||
|
if(activity_observer) activity_observer->draw();
|
||||||
|
updater.update();
|
||||||
|
|
||||||
|
// Grab the machine lock and process all pending events.
|
||||||
|
std::lock_guard<std::mutex> lock_guard(machine_mutex);
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while(SDL_PollEvent(&event)) {
|
while(SDL_PollEvent(&event)) {
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
@ -643,9 +664,12 @@ int main(int argc, char *argv[]) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
|
case SDL_KEYUP: {
|
||||||
|
const auto keyboard_machine = machine->keyboard_machine();
|
||||||
|
|
||||||
|
if(event.type == SDL_KEYDOWN) {
|
||||||
// Syphon off the key-press if it's control+shift+V (paste).
|
// Syphon off the key-press if it's control+shift+V (paste).
|
||||||
if(event.key.keysym.sym == SDLK_v && (SDL_GetModState()&KMOD_CTRL) && (SDL_GetModState()&KMOD_SHIFT)) {
|
if(event.key.keysym.sym == SDLK_v && (SDL_GetModState()&KMOD_CTRL) && (SDL_GetModState()&KMOD_SHIFT)) {
|
||||||
const auto keyboard_machine = machine->keyboard_machine();
|
|
||||||
if(keyboard_machine) {
|
if(keyboard_machine) {
|
||||||
keyboard_machine->type_string(SDL_GetClipboardText());
|
keyboard_machine->type_string(SDL_GetClipboardText());
|
||||||
break;
|
break;
|
||||||
@ -702,8 +726,6 @@ int main(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliberate fallthrough...
|
|
||||||
case SDL_KEYUP: {
|
|
||||||
|
|
||||||
// Syphon off alt+enter (toggle full-screen) upon key up only; this was previously a key down action,
|
// Syphon off alt+enter (toggle full-screen) upon key up only; this was previously a key down action,
|
||||||
// but the SDL_KEYDOWN announcement was found to be reposted after changing graphics mode on some
|
// but the SDL_KEYDOWN announcement was found to be reposted after changing graphics mode on some
|
||||||
@ -720,10 +742,10 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bool is_pressed = event.type == SDL_KEYDOWN;
|
const bool is_pressed = event.type == SDL_KEYDOWN;
|
||||||
|
|
||||||
const auto keyboard_machine = machine->keyboard_machine();
|
|
||||||
if(keyboard_machine) {
|
if(keyboard_machine) {
|
||||||
Inputs::Keyboard::Key key = Inputs::Keyboard::Key::Space;
|
Inputs::Keyboard::Key key = Inputs::Keyboard::Key::Space;
|
||||||
if(!KeyboardKeyForSDLScancode(event.key.keysym.scancode, key)) break;
|
if(!KeyboardKeyForSDLScancode(event.key.keysym.scancode, key)) break;
|
||||||
@ -760,12 +782,13 @@ int main(int argc, char *argv[]) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
if(uses_mouse && !SDL_GetRelativeMouseMode()) {
|
case SDL_MOUSEBUTTONUP: {
|
||||||
|
if(uses_mouse && event.type == SDL_MOUSEBUTTONDOWN && !SDL_GetRelativeMouseMode()) {
|
||||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||||
window_titler.set_mouse_is_captured(true);
|
window_titler.set_mouse_is_captured(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_MOUSEBUTTONUP: {
|
|
||||||
const auto mouse_machine = machine->mouse_machine();
|
const auto mouse_machine = machine->mouse_machine();
|
||||||
if(mouse_machine) {
|
if(mouse_machine) {
|
||||||
mouse_machine->get_mouse().set_button_pressed(
|
mouse_machine->get_mouse().set_button_pressed(
|
||||||
@ -834,16 +857,10 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display a new frame and wait for vsync.
|
|
||||||
updater.update();
|
|
||||||
scan_target.update(int(window_width), int(window_height));
|
|
||||||
scan_target.draw(int(window_width), int(window_height));
|
|
||||||
if(activity_observer) activity_observer->draw();
|
|
||||||
SDL_GL_SwapWindow(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up.
|
// Clean up.
|
||||||
|
updater.flush(); // Ensure no further updates will occur.
|
||||||
joysticks.clear();
|
joysticks.clear();
|
||||||
SDL_DestroyWindow( window );
|
SDL_DestroyWindow( window );
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
Loading…
Reference in New Issue
Block a user