reduce usb install exit latency by waiting on a cancel uevent, rather than relying on a timeout.

This commit is contained in:
ITotalJustice
2025-05-03 17:17:53 +01:00
parent 30cf4826f8
commit 7072647611
4 changed files with 39 additions and 7 deletions

View File

@@ -14,6 +14,10 @@ struct Base {
return false;
}
virtual void SignalCancel() {
}
Result GetOpenResult() const {
return m_open_result;
}

View File

@@ -32,6 +32,14 @@ struct Usb final : Base {
Result WaitForConnection(u64 timeout, std::vector<std::string>& out_names);
void SetFileNameForTranfser(const std::string& name);
auto GetCancelEvent() {
return &m_uevent;
}
void SignalCancel() override {
ueventSignal(GetCancelEvent());
}
public:
// custom allocator for std::vector that respects alignment.
// https://en.cppreference.com/w/cpp/named_req/Allocator
@@ -69,16 +77,18 @@ private:
Result SendFileRangeCmd(u64 offset, u64 size);
Event *GetCompletionEvent(UsbSessionEndpoint ep) const;
Result WaitTransferCompletion(UsbSessionEndpoint ep, u64 timeout) const;
Result WaitTransferCompletion(UsbSessionEndpoint ep, u64 timeout);
Result TransferAsync(UsbSessionEndpoint ep, void *buffer, u32 size, u32 *out_urb_id) const;
Result GetTransferResult(UsbSessionEndpoint ep, u32 urb_id, u32 *out_requested_size, u32 *out_transferred_size) const;
Result TransferPacketImpl(bool read, void *page, u32 size, u32 *out_size_transferred, u64 timeout) const;
Result TransferPacketImpl(bool read, void *page, u32 size, u32 *out_size_transferred, u64 timeout);
Result TransferAll(bool read, void *data, u32 size, u64 timeout);
private:
UsbDsInterface* m_interface{};
UsbDsEndpoint* m_endpoints[2]{};
u64 m_transfer_timeout{};
UEvent m_uevent{};
// std::vector<UEvent*> m_cancel_events{};
// aligned buffer that transfer data is copied to and from.
// a vector is used to avoid multiple alloc within the transfer loop.
PageAlignedVector m_aligned{};

View File

@@ -10,8 +10,8 @@
namespace sphaira::ui::menu::usb {
namespace {
constexpr u64 CONNECTION_TIMEOUT = 1e+9 * 1; // 1 second
constexpr u64 TRANSFER_TIMEOUT = 1e+9 * 5; // 5 seconds
constexpr u64 CONNECTION_TIMEOUT = UINT64_MAX;
constexpr u64 TRANSFER_TIMEOUT = UINT64_MAX;
void thread_func(void* user) {
auto app = static_cast<Menu*>(user);
@@ -76,6 +76,7 @@ Menu::Menu() : MenuBase{"USB"_i18n} {
}
mutexInit(&m_mutex);
if (m_state != State::Failed) {
threadCreate(&m_thread, thread_func, this, nullptr, 1024*32, 0x2C, 1);
threadStart(&m_thread);
@@ -85,6 +86,7 @@ Menu::Menu() : MenuBase{"USB"_i18n} {
Menu::~Menu() {
// signal for thread to exit and wait.
m_stop_source.request_stop();
m_usb_source->SignalCancel();
threadWaitForExit(&m_thread);
threadClose(&m_thread);
@@ -117,6 +119,8 @@ void Menu::Update(Controller* controller, TouchInfo* touch) {
const auto rc = yati::InstallFromSource(pbox, m_usb_source, file_name);
if (R_FAILED(rc)) {
m_usb_source->SignalCancel();
log_write("exiting usb install\n");
return false;
}

View File

@@ -64,6 +64,7 @@ static_assert(sizeof(USBCmdHeader) == 0x20, "USBCmdHeader must be 0x20!");
Usb::Usb(u64 transfer_timeout) {
m_open_result = usbDsInitialize();
m_transfer_timeout = transfer_timeout;
ueventCreate(GetCancelEvent(), true);
// this avoids allocations during transfers.
m_aligned.reserve(1024 * 1024 * 16);
}
@@ -261,9 +262,22 @@ Event *Usb::GetCompletionEvent(UsbSessionEndpoint ep) const {
return std::addressof(m_endpoints[ep]->CompletionEvent);
}
Result Usb::WaitTransferCompletion(UsbSessionEndpoint ep, u64 timeout) const {
Result Usb::WaitTransferCompletion(UsbSessionEndpoint ep, u64 timeout) {
auto event = GetCompletionEvent(ep);
const auto rc = eventWait(event, timeout);
const std::array waiters{
waiterForEvent(event),
waiterForUEvent(GetCancelEvent()),
};
s32 idx;
auto rc = waitObjects(&idx, waiters.data(), waiters.size(), timeout);
// check if we got one of the cancel events.
if (R_SUCCEEDED(rc) && idx != 0) {
log_write("got usb cancel event\n");
rc = 0xEC01; // cancelled.
}
if (R_FAILED(rc)) {
R_TRY(usbDsEndpoint_Cancel(m_endpoints[ep]));
@@ -287,7 +301,7 @@ Result Usb::GetTransferResult(UsbSessionEndpoint ep, u32 urb_id, u32 *out_reques
R_SUCCEED();
}
Result Usb::TransferPacketImpl(bool read, void *page, u32 size, u32 *out_size_transferred, u64 timeout) const {
Result Usb::TransferPacketImpl(bool read, void *page, u32 size, u32 *out_size_transferred, u64 timeout) {
u32 urb_id;
/* If we're not configured yet, wait to become configured first. */