Skip to content

Commit da67b5e

Browse files
committed
Fix hang when closing connection while connection is hung.
1 parent de11465 commit da67b5e

File tree

8 files changed

+47
-11
lines changed

8 files changed

+47
-11
lines changed

ClientSource/Connection/BotBase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class BotBaseController{
3636
virtual State state() const = 0;
3737
virtual size_t queue_limit() const = 0;
3838

39+
virtual void notify_all() = 0;
40+
3941
// Waits for all pending requests to finish.
4042
virtual void wait_for_all_requests(const Cancellable* cancelled = nullptr) = 0;
4143

ClientSource/Connection/PABotBase.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ void PABotBase::stop(){
124124
// it is safe to destruct.
125125
m_state.store(State::STOPPED, std::memory_order_release);
126126
}
127+
void PABotBase::notify_all(){
128+
std::unique_lock<std::mutex> lg(m_sleep_lock);
129+
m_cv.notify_all();
130+
}
131+
127132
void PABotBase::set_queue_limit(size_t queue_limit){
128133
m_max_pending_requests.store(queue_limit, std::memory_order_relaxed);
129134
}
@@ -810,13 +815,17 @@ BotBaseMessage PABotBase::issue_request_and_wait(
810815
}
811816

812817
uint64_t seqnum = issue_request(cancelled, request, false);
813-
return wait_for_request(seqnum);
818+
return wait_for_request(seqnum, cancelled);
814819
}
815-
BotBaseMessage PABotBase::wait_for_request(uint64_t seqnum){
820+
BotBaseMessage PABotBase::wait_for_request(uint64_t seqnum, const Cancellable* cancelled){
816821
auto scope_check = m_sanitizer.check_scope();
817822

818823
std::unique_lock<std::mutex> lg(m_sleep_lock);
819824
while (true){
825+
if (cancelled && cancelled->cancelled()){
826+
throw OperationCancelledException();
827+
}
828+
820829
{
821830
WriteSpinLock slg(m_state_lock, "PABotBase::issue_request_and_wait()");
822831
auto iter = m_pending_requests.find(seqnum);

ClientSource/Connection/PABotBase.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class PABotBase : public BotBaseController, private PABotBaseConnection{
6868
virtual State state() const override{
6969
return m_state.load(std::memory_order_acquire);
7070
}
71+
virtual void notify_all() override;
7172

7273
virtual size_t queue_limit() const override{
7374
return m_max_pending_requests.load(std::memory_order_relaxed);
@@ -170,7 +171,7 @@ class PABotBase : public BotBaseController, private PABotBaseConnection{
170171
) override;
171172

172173
private:
173-
BotBaseMessage wait_for_request(uint64_t seqnum);
174+
BotBaseMessage wait_for_request(uint64_t seqnum, const Cancellable* cancelled = nullptr);
174175

175176
private:
176177
Logger& m_logger;

SerialPrograms/Source/NintendoSwitch/Controllers/SerialPABotBase/NintendoSwitch_PokkenController.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ SerialPABotBase_PokkenController::SerialPABotBase_PokkenController(
4343
{}
4444
SerialPABotBase_PokkenController::~SerialPABotBase_PokkenController(){
4545
stop();
46+
m_scope.cancel(nullptr);
4647
{
4748
std::unique_lock<std::mutex> lg(m_sleep_lock);
49+
if (m_serial){
50+
m_serial->notify_all();
51+
}
4852
m_cv.notify_all();
4953
m_stopping.store(true, std::memory_order_relaxed);
5054
}
@@ -100,7 +104,6 @@ void SerialPABotBase_PokkenController::push_state(const Cancellable* cancellable
100104

101105

102106
void SerialPABotBase_PokkenController::status_thread(){
103-
104107
constexpr std::chrono::milliseconds PERIOD(1000);
105108
std::atomic<WallClock> last_ack(current_time());
106109

@@ -134,8 +137,6 @@ void SerialPABotBase_PokkenController::status_thread(){
134137
}
135138
});
136139

137-
CancellableHolder<CancellableScope> scope;
138-
139140
WallClock next_ping = current_time();
140141
while (true){
141142
if (m_stopping.load(std::memory_order_relaxed) || !m_handle.is_ready()){
@@ -147,7 +148,7 @@ void SerialPABotBase_PokkenController::status_thread(){
147148
pabb_MsgAckRequestI32 response;
148149
m_serial->issue_request_and_wait(
149150
NintendoSwitch::DeviceRequest_system_clock(),
150-
&scope
151+
&m_scope
151152
).convert<PABB_MSG_ACK_REQUEST_I32>(logger(), response);
152153
last_ack.store(current_time(), std::memory_order_relaxed);
153154
uint32_t wallclock = response.data;
@@ -162,6 +163,8 @@ void SerialPABotBase_PokkenController::status_thread(){
162163
theme_friendly_darkblue()
163164
);
164165
}
166+
}catch (OperationCancelledException&){
167+
break;
165168
}catch (InvalidConnectionStateException&){
166169
break;
167170
}catch (SerialProtocolException& e){

SerialPrograms/Source/NintendoSwitch/Controllers/SerialPABotBase/NintendoSwitch_PokkenController.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class SerialPABotBase_PokkenController final : public SerialPABotBase_ProControl
3636
void status_thread();
3737

3838
private:
39+
CancellableHolder<CancellableScope> m_scope;
3940
std::atomic<bool> m_stopping;
4041
std::mutex m_sleep_lock;
4142
std::condition_variable m_cv;

SerialPrograms/Source/NintendoSwitch/Controllers/SerialPABotBase/NintendoSwitch_WirelessProController.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "Common/Cpp/Concurrency/ReverseLockGuard.h"
1111
#include "Common/NintendoSwitch/NintendoSwitch_Protocol_ESP32.h"
1212
#include "ClientSource/Libraries/MessageConverter.h"
13+
#include "CommonFramework/GlobalSettingsPanel.h"
1314
#include "CommonFramework/Options/Environment/ThemeSelectorOption.h"
1415
#include "Controllers/ControllerCapability.h"
1516
#include "NintendoSwitch/Commands/NintendoSwitch_Messages_Device.h"
@@ -43,8 +44,12 @@ SerialPABotBase_WirelessProController::SerialPABotBase_WirelessProController(
4344
{}
4445
SerialPABotBase_WirelessProController::~SerialPABotBase_WirelessProController(){
4546
stop();
47+
m_scope.cancel(nullptr);
4648
{
4749
std::unique_lock<std::mutex> lg(m_sleep_lock);
50+
if (m_serial){
51+
m_serial->notify_all();
52+
}
4853
m_cv.notify_all();
4954
m_stopping.store(true, std::memory_order_relaxed);
5055
}
@@ -82,6 +87,21 @@ class SerialPABotBase_WirelessProController::MessageControllerState : public Bot
8287
};
8388

8489
int register_message_converters_ESP32(){
90+
register_message_converter(
91+
PABB_MSG_ESP32_REQUEST_STATUS,
92+
[](const std::string& body){
93+
// Disable this by default since it's very spammy.
94+
if (!GlobalSettings::instance().LOG_EVERYTHING){
95+
return std::string();
96+
}
97+
std::ostringstream ss;
98+
ss << "ESP32_controller_status() - ";
99+
if (body.size() != sizeof(pabb_esp32_RequestStatus)){ ss << "(invalid size)" << std::endl; return ss.str(); }
100+
const auto* params = (const pabb_esp32_RequestStatus*)body.c_str();
101+
ss << "seqnum = " << (uint64_t)params->seqnum;
102+
return ss.str();
103+
}
104+
);
85105
register_message_converter(
86106
PABB_MSG_ESP32_REPORT,
87107
[](const std::string& body){
@@ -181,7 +201,6 @@ void SerialPABotBase_WirelessProController::push_state(const Cancellable* cancel
181201

182202

183203
void SerialPABotBase_WirelessProController::status_thread(){
184-
185204
constexpr std::chrono::milliseconds PERIOD(1000);
186205
std::atomic<WallClock> last_ack(current_time());
187206

@@ -215,8 +234,6 @@ void SerialPABotBase_WirelessProController::status_thread(){
215234
}
216235
});
217236

218-
CancellableHolder<CancellableScope> scope;
219-
220237
WallClock next_ping = current_time();
221238
while (true){
222239
if (m_stopping.load(std::memory_order_relaxed) || !m_handle.is_ready()){
@@ -228,7 +245,7 @@ void SerialPABotBase_WirelessProController::status_thread(){
228245
pabb_MsgAckRequestI32 response;
229246
m_serial->issue_request_and_wait(
230247
MessageControllerStatus(),
231-
&scope
248+
&m_scope
232249
).convert<PABB_MSG_ACK_REQUEST_I32>(logger(), response);
233250
last_ack.store(current_time(), std::memory_order_relaxed);
234251

SerialPrograms/Source/NintendoSwitch/Controllers/SerialPABotBase/NintendoSwitch_WirelessProController.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class SerialPABotBase_WirelessProController final : public SerialPABotBase_ProCo
3939
void status_thread();
4040

4141
private:
42+
CancellableHolder<CancellableScope> m_scope;
4243
std::atomic<bool> m_stopping;
4344
std::mutex m_sleep_lock;
4445
std::condition_variable m_cv;

SerialPrograms/Source/Tests/TestUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class DummyBotBase : public BotBaseController{
6262
virtual State state() const override { return State::RUNNING; }
6363
virtual size_t queue_limit() const override { return PABB_DEVICE_QUEUE_SIZE; }
6464

65+
virtual void notify_all() override{}
66+
6567
virtual void wait_for_all_requests(const Cancellable* cancelled = nullptr) override {}
6668

6769
virtual bool try_stop_all_commands() override { return true; }

0 commit comments

Comments
 (0)