1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-16 15:29:34 +00:00

Resolve crash of machines that require the ROM requester.

This commit is contained in:
Thomas Harte 2022-08-22 17:01:41 -04:00
parent 38a509bc20
commit 1b197d0bb2
2 changed files with 41 additions and 27 deletions

View File

@ -65,34 +65,14 @@ template <> struct TaskQueueStorage<void> {
action occupies the asynchronous thread for long enough. So it is not true that @c perform will be
called once per action.
*/
template <bool perform_automatically, typename Performer = void> class AsyncTaskQueue: public TaskQueueStorage<Performer> {
template <bool perform_automatically, bool start_immediately = true, typename Performer = void> class AsyncTaskQueue: public TaskQueueStorage<Performer> {
public:
template <typename... Args> AsyncTaskQueue(Args&&... args) :
TaskQueueStorage<Performer>(std::forward<Args>(args)...),
thread_{
[this] {
ActionVector actions;
while(!should_quit_) {
// Wait for new actions to be signalled, and grab them.
std::unique_lock lock(condition_mutex_);
while(actions_.empty()) {
condition_.wait(lock);
}
std::swap(actions, actions_);
lock.unlock();
// Update to now (which is possibly a no-op).
TaskQueueStorage<Performer>::update();
// Perform the actions and destroy them.
for(const auto &action: actions) {
action();
}
actions.clear();
}
}
} {}
TaskQueueStorage<Performer>(std::forward<Args>(args)...) {
if constexpr (start_immediately) {
start();
}
}
/// Enqueus @c post_action to be performed asynchronously at some point
/// in the future. If @c perform_automatically is @c true then the action
@ -136,6 +116,37 @@ template <bool perform_automatically, typename Performer = void> class AsyncTask
}
}
/// Starts the queue if it has never been started before.
///
/// This is not guaranteed safely to restart a stopped queue.
void start() {
thread_ = std::move(std::thread{
[this] {
ActionVector actions;
// Continue until told to quit.
while(!should_quit_) {
// Wait for new actions to be signalled, and grab them.
std::unique_lock lock(condition_mutex_);
while(actions_.empty()) {
condition_.wait(lock);
}
std::swap(actions, actions_);
lock.unlock();
// Update to now (which is possibly a no-op).
TaskQueueStorage<Performer>::update();
// Perform the actions and destroy them.
for(const auto &action: actions) {
action();
}
actions.clear();
}
}
});
}
/// Schedules any remaining unscheduled work, then blocks synchronously
/// until all scheduled work has been performed.
void flush() {

View File

@ -122,7 +122,7 @@ struct ActivityObserver: public Activity::Observer {
CSJoystickManager *_joystickManager;
NSMutableArray<CSMachineLED *> *_leds;
Concurrency::AsyncTaskQueue<true, MachineUpdater> updater;
Concurrency::AsyncTaskQueue<true, false, MachineUpdater> updater;
Time::ScanSynchroniser _scanSynchroniser;
NSTimer *_joystickTimer;
@ -149,6 +149,9 @@ struct ActivityObserver: public Activity::Observer {
return nil;
}
updater.performer.machine = _machine->timed_machine();
if(updater.performer.machine) {
updater.start();
}
// Use the keyboard as a joystick if the machine has no keyboard, or if it has a 'non-exclusive' keyboard.
_inputMode =