Skip to content

Commit 067eca0

Browse files
committed
Fix thread-safety of commands.
1 parent 6f4a602 commit 067eca0

File tree

4 files changed

+92
-102
lines changed

4 files changed

+92
-102
lines changed

SerialPrograms/Source/Controllers/SuperscalarScheduler.cpp

Lines changed: 79 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ SuperscalarScheduler::SuperscalarScheduler(
2929

3030

3131
void SuperscalarScheduler::clear() noexcept{
32-
SpinLockGuard lg(m_lock);
32+
// SpinLockGuard lg(m_lock);
3333
m_logger.log("Clearing schedule...");
3434
WallClock now = current_time();
3535
m_local_start = now;
@@ -54,54 +54,49 @@ void SuperscalarScheduler::clear() noexcept{
5454
bool SuperscalarScheduler::iterate_schedule(const Cancellable* cancellable){
5555
cancellable->throw_if_cancelled();
5656

57-
WallDuration duration;
58-
{
59-
SpinLockGuard lg(m_lock);
60-
61-
if (m_state_changes.empty()){
62-
m_device_sent_time = m_device_issue_time;
63-
return false;
64-
}
57+
if (m_state_changes.empty()){
58+
m_device_sent_time = m_device_issue_time;
59+
return false;
60+
}
6561

66-
auto iter = m_state_changes.begin();
67-
68-
WallClock next_state_change;
69-
if (m_device_sent_time < *iter){
70-
next_state_change = *iter;
71-
}else{
72-
auto next = iter;
73-
++next;
74-
next_state_change = next == m_state_changes.end()
75-
? m_device_issue_time
76-
: *next;
77-
}
62+
auto iter = m_state_changes.begin();
63+
64+
WallClock next_state_change;
65+
if (m_device_sent_time < *iter){
66+
next_state_change = *iter;
67+
}else{
68+
auto next = iter;
69+
++next;
70+
next_state_change = next == m_state_changes.end()
71+
? m_device_issue_time
72+
: *next;
73+
}
7874

79-
// Things get complicated if we overshoot the issue time.
80-
if (next_state_change > m_device_issue_time){
75+
// Things get complicated if we overshoot the issue time.
76+
if (next_state_change > m_device_issue_time){
8177
// m_logger.log("SuperscalarScheduler: Overshoot due to unfinished early return.", COLOR_RED);
82-
next_state_change = m_device_issue_time;
83-
}
78+
next_state_change = m_device_issue_time;
79+
}
8480

85-
duration = next_state_change - m_device_sent_time;
86-
if (duration == WallDuration::zero()){
81+
WallDuration duration = next_state_change - m_device_sent_time;
82+
if (duration == WallDuration::zero()){
8783
// m_logger.log("SuperscalarScheduler: Scheduler is stalled.", COLOR_RED);
88-
return false;
89-
}
84+
return false;
85+
}
9086

91-
// Compute the resource state at this timestamp.
92-
for (ExecutionResource* resource : m_resources){
93-
resource->m_is_busy = resource->m_busy_time <= m_device_sent_time && m_device_sent_time < resource->m_done_time;
94-
}
87+
// Compute the resource state at this timestamp.
88+
for (ExecutionResource* resource : m_resources){
89+
resource->m_is_busy = resource->m_busy_time <= m_device_sent_time && m_device_sent_time < resource->m_done_time;
90+
}
9591

96-
m_device_sent_time = next_state_change;
97-
if (next_state_change >= *iter){
98-
m_state_changes.erase(iter);
99-
}
92+
m_device_sent_time = next_state_change;
93+
if (next_state_change >= *iter){
94+
m_state_changes.erase(iter);
10095
}
10196

10297
this->push_state(cancellable, duration);
10398

104-
SpinLockGuard lg(m_lock);
99+
// SpinLockGuard lg(m_lock);
105100

106101
WallClock now = current_time();
107102
m_local_last_activity = now;
@@ -142,16 +137,13 @@ void SuperscalarScheduler::issue_wait_for_all(const Cancellable* cancellable){
142137
clear();
143138
return;
144139
}
145-
{
146-
SpinLockGuard lg(m_lock);
147-
// cout << "issue_wait_for_all(): " << m_state_changes.size() << endl;
148-
// cout << "issue_time = " << std::chrono::duration_cast<Milliseconds>((m_device_issue_time - m_local_start)).count()
149-
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
150-
// << ", max_free_time = " << std::chrono::duration_cast<Milliseconds>((m_max_free_time - m_local_start)).count()
151-
// << endl;
152-
m_device_issue_time = std::max(m_device_issue_time, m_max_free_time);
153-
m_max_free_time = m_device_issue_time;
154-
}
140+
// cout << "issue_wait_for_all(): " << m_state_changes.size() << endl;
141+
// cout << "issue_time = " << std::chrono::duration_cast<Milliseconds>((m_device_issue_time - m_local_start)).count()
142+
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
143+
// << ", max_free_time = " << std::chrono::duration_cast<Milliseconds>((m_max_free_time - m_local_start)).count()
144+
// << endl;
145+
m_device_issue_time = std::max(m_device_issue_time, m_max_free_time);
146+
m_max_free_time = m_device_issue_time;
155147
process_schedule(cancellable);
156148
}
157149
void SuperscalarScheduler::issue_nop(const Cancellable* cancellable, WallDuration delay){
@@ -161,18 +153,15 @@ void SuperscalarScheduler::issue_nop(const Cancellable* cancellable, WallDuratio
161153
if (m_pending_clear.load(std::memory_order_acquire)){
162154
clear();
163155
}
164-
{
165-
SpinLockGuard lg(m_lock);
166-
// cout << "issue_nop(): " << m_state_changes.size() << endl;
167-
// cout << "issue_time = " << std::chrono::duration_cast<Milliseconds>((m_device_issue_time - m_local_start)).count()
168-
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
169-
// << ", max_free_time = " << std::chrono::duration_cast<Milliseconds>((m_max_free_time - m_local_start)).count()
170-
// << endl;
171-
m_state_changes.insert(m_device_issue_time);
172-
m_device_issue_time += delay;
173-
m_max_free_time = std::max(m_max_free_time, m_device_issue_time);
174-
m_local_last_activity = current_time();
175-
}
156+
// cout << "issue_nop(): " << m_state_changes.size() << endl;
157+
// cout << "issue_time = " << std::chrono::duration_cast<Milliseconds>((m_device_issue_time - m_local_start)).count()
158+
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
159+
// << ", max_free_time = " << std::chrono::duration_cast<Milliseconds>((m_max_free_time - m_local_start)).count()
160+
// << endl;
161+
m_state_changes.insert(m_device_issue_time);
162+
m_device_issue_time += delay;
163+
m_max_free_time = std::max(m_max_free_time, m_device_issue_time);
164+
m_local_last_activity = current_time();
176165
process_schedule(cancellable);
177166
}
178167
void SuperscalarScheduler::wait_for_resource(const Cancellable* cancellable, ExecutionResource& resource){
@@ -185,14 +174,11 @@ void SuperscalarScheduler::wait_for_resource(const Cancellable* cancellable, Exe
185174
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
186175
// << ", free_time = " << std::chrono::duration_cast<Milliseconds>((resource.m_free_time - m_local_start)).count()
187176
// << endl;
188-
{
189-
SpinLockGuard lg(m_lock);
190-
// Resource is not ready yet. Stall until it is.
191-
if (resource.m_free_time > m_device_sent_time){
192-
// cout << "stall = " << std::chrono::duration_cast<Milliseconds>(resource.m_free_time - m_device_sent_time).count() << endl;
193-
m_device_issue_time = resource.m_free_time;
194-
m_local_last_activity = current_time();
195-
}
177+
// Resource is not ready yet. Stall until it is.
178+
if (resource.m_free_time > m_device_sent_time){
179+
// cout << "stall = " << std::chrono::duration_cast<Milliseconds>(resource.m_free_time - m_device_sent_time).count() << endl;
180+
m_device_issue_time = resource.m_free_time;
181+
m_local_last_activity = current_time();
196182
}
197183
process_schedule(cancellable);
198184
}
@@ -204,39 +190,36 @@ void SuperscalarScheduler::issue_to_resource(
204190
clear();
205191
}
206192

207-
{
208-
SpinLockGuard lg(m_lock);
209-
// Resource is busy.
210-
if (m_device_sent_time < resource.m_free_time){
211-
throw InternalProgramError(
212-
nullptr, PA_CURRENT_FUNCTION,
213-
"Attempted to issue resource that isn't ready."
214-
);
215-
}
193+
// Resource is busy.
194+
if (m_device_sent_time < resource.m_free_time){
195+
throw InternalProgramError(
196+
nullptr, PA_CURRENT_FUNCTION,
197+
"Attempted to issue resource that isn't ready."
198+
);
199+
}
216200

217-
// cout << "issue_to_resource(): delay = " << std::chrono::duration_cast<Milliseconds>(delay).count()
218-
// << ", hold = " << std::chrono::duration_cast<Milliseconds>(hold).count()
219-
// << ", cooldown = " << std::chrono::duration_cast<Milliseconds>(cooldown).count()
220-
// << endl;
221-
// cout << "issue_time = " << std::chrono::duration_cast<Milliseconds>((m_device_issue_time - m_local_start)).count()
222-
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
223-
// << endl;
201+
// cout << "issue_to_resource(): delay = " << std::chrono::duration_cast<Milliseconds>(delay).count()
202+
// << ", hold = " << std::chrono::duration_cast<Milliseconds>(hold).count()
203+
// << ", cooldown = " << std::chrono::duration_cast<Milliseconds>(cooldown).count()
204+
// << endl;
205+
// cout << "issue_time = " << std::chrono::duration_cast<Milliseconds>((m_device_issue_time - m_local_start)).count()
206+
// << ", sent_time = " << std::chrono::duration_cast<Milliseconds>((m_device_sent_time - m_local_start)).count()
207+
// << endl;
224208

225-
WallClock release_time = m_device_issue_time + hold;
226-
WallClock free_time = release_time + cooldown;
209+
WallClock release_time = m_device_issue_time + hold;
210+
WallClock free_time = release_time + cooldown;
227211

228-
m_state_changes.insert(m_device_issue_time);
229-
m_state_changes.insert(release_time);
212+
m_state_changes.insert(m_device_issue_time);
213+
m_state_changes.insert(release_time);
230214

231-
resource.m_busy_time = m_device_issue_time;
232-
resource.m_done_time = release_time;
233-
resource.m_free_time = free_time;
215+
resource.m_busy_time = m_device_issue_time;
216+
resource.m_done_time = release_time;
217+
resource.m_free_time = free_time;
234218

235-
m_device_issue_time += delay;
236-
m_max_free_time = std::max(m_max_free_time, free_time);
237-
m_max_free_time = std::max(m_max_free_time, m_device_issue_time);
238-
m_local_last_activity = current_time();
239-
}
219+
m_device_issue_time += delay;
220+
m_max_free_time = std::max(m_max_free_time, free_time);
221+
m_max_free_time = std::max(m_max_free_time, m_device_issue_time);
222+
m_local_last_activity = current_time();
240223

241224
process_schedule(cancellable);
242225
}

SerialPrograms/Source/Controllers/SuperscalarScheduler.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <atomic>
1212
#include "Common/Cpp/AbstractLogger.h"
1313
#include "Common/Cpp/CancellableScope.h"
14-
#include "Common/Cpp/Concurrency/SpinLock.h"
1514

1615
namespace PokemonAutomation{
1716

@@ -72,7 +71,7 @@ class SuperscalarScheduler{
7271
// returned to the ready state.
7372
void issue_wait_for_all(const Cancellable* cancellable);
7473

75-
// Issue a no-nothing command for the specified delay.
74+
// Issue a do-nothing command for the specified delay.
7675
// This will advance the issue timestamp.
7776
void issue_nop(const Cancellable* cancellable, WallDuration delay);
7877

@@ -107,8 +106,6 @@ class SuperscalarScheduler{
107106

108107
std::atomic<bool> m_pending_clear;
109108

110-
SpinLock m_lock;
111-
112109
// The construction time of this object. This is only used for debugging
113110
// purposes since it lets you print wall times relative to this.
114111
WallClock m_local_start;

SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_SerialPABotBase.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,10 @@ void SwitchController_SerialPABotBase::update_status_string(){
231231

232232
void SwitchController_SerialPABotBase::wait_for_all(const Cancellable* cancellable){
233233
// cout << "wait_for_all() - enter" << endl;
234-
this->issue_wait_for_all(cancellable);
234+
{
235+
WriteSpinLock lg(m_lock);
236+
this->issue_wait_for_all(cancellable);
237+
}
235238
m_serial.wait_for_all_requests(cancellable);
236239
// cout << "wait_for_all() - exit" << endl;
237240
}
@@ -279,6 +282,7 @@ void SwitchController_SerialPABotBase::issue_barrier(const Cancellable* cancella
279282
if (m_logging_suppress.load(std::memory_order_relaxed) == 0){
280283
m_logger.log("issue_barrier()", COLOR_DARKGREEN);
281284
}
285+
WriteSpinLock lg(m_lock);
282286
this->issue_wait_for_all(cancellable);
283287
}
284288
void SwitchController_SerialPABotBase::issue_nop(const Cancellable* cancellable, Milliseconds duration){
@@ -291,6 +295,7 @@ void SwitchController_SerialPABotBase::issue_nop(const Cancellable* cancellable,
291295
COLOR_DARKGREEN
292296
);
293297
}
298+
WriteSpinLock lg(m_lock);
294299
this->SuperscalarScheduler::issue_nop(cancellable, WallDuration(duration));
295300
}
296301
void SwitchController_SerialPABotBase::issue_buttons(
@@ -310,6 +315,7 @@ void SwitchController_SerialPABotBase::issue_buttons(
310315
COLOR_DARKGREEN
311316
);
312317
}
318+
WriteSpinLock lg(m_lock);
313319
for (size_t c = 0; c < 14; c++){
314320
uint16_t mask = (uint16_t)1 << c;
315321
if (button & mask){
@@ -325,7 +331,7 @@ void SwitchController_SerialPABotBase::issue_buttons(
325331
);
326332
}
327333
}
328-
this->issue_nop(cancellable, delay);
334+
this->SuperscalarScheduler::issue_nop(cancellable, delay);
329335
}
330336
void SwitchController_SerialPABotBase::issue_dpad(
331337
const Cancellable* cancellable,
@@ -344,6 +350,7 @@ void SwitchController_SerialPABotBase::issue_dpad(
344350
COLOR_DARKGREEN
345351
);
346352
}
353+
WriteSpinLock lg(m_lock);
347354
this->wait_for_resource(cancellable, m_dpad);
348355
m_dpad.position = position;
349356
this->issue_to_resource(cancellable, m_dpad, delay, hold, cooldown);
@@ -365,6 +372,7 @@ void SwitchController_SerialPABotBase::issue_left_joystick(
365372
COLOR_DARKGREEN
366373
);
367374
}
375+
WriteSpinLock lg(m_lock);
368376
this->wait_for_resource(cancellable, m_left_joystick);
369377
m_left_joystick.x = x;
370378
m_left_joystick.y = y;
@@ -388,6 +396,7 @@ void SwitchController_SerialPABotBase::issue_right_joystick(
388396
COLOR_DARKGREEN
389397
);
390398
}
399+
WriteSpinLock lg(m_lock);
391400
this->wait_for_resource(cancellable, m_right_joystick);
392401
m_right_joystick.x = x;
393402
m_right_joystick.y = y;

SerialPrograms/Source/NintendoSwitch/Controllers/NintendoSwitch_SerialPABotBase.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ class SwitchController_SerialPABotBase :
212212
BotBaseController& m_serial;
213213

214214
std::atomic<size_t> m_logging_suppress;
215+
SpinLock m_lock;
215216
};
216217

217218

0 commit comments

Comments
 (0)