From ec582967e854b074d7489ab5294dc716ee091068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Wed, 13 Nov 2024 13:15:55 +0100 Subject: [PATCH] fruity: Fix hang when a USB op starts at teardown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Which would result in such transfers never completing, as our USB worker is no longer processing libusb events. Kudos to @mrmacete for helping track this one down. Co-authored-by: Håvard Sørbø --- src/fruity/device-monitor.vala | 42 ++++++++++++++++++++++++++-------- src/fruity/usb.vala | 2 +- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/fruity/device-monitor.vala b/src/fruity/device-monitor.vala index 8d16955c2..73f13a55b 100644 --- a/src/fruity/device-monitor.vala +++ b/src/fruity/device-monitor.vala @@ -770,7 +770,8 @@ namespace Frida.Fruity { } public async void start (Cancellable? cancellable) throws IOError { - state = STARTING; + lock (state) + state = STARTING; usb_worker = new Thread ("frida-core-device-usb", perform_usb_work); @@ -782,11 +783,13 @@ namespace Frida.Fruity { assert_not_reached (); } - state = STARTED; + lock (state) + state = STARTED; } public async void stop (Cancellable? cancellable) throws IOError { - state = FLUSHING; + lock (state) + state = FLUSHING; io_cancellable.cancel (); @@ -814,7 +817,8 @@ namespace Frida.Fruity { usb_context = null; - state = STOPPED; + lock (state) + state = STOPPED; } public async void activate_modeswitch_support (Cancellable? cancellable) throws IOError { @@ -911,7 +915,7 @@ namespace Frida.Fruity { polled_usb_timer = null; } - lock (pending_usb_ops) { + lock (state) { if (pending_usb_ops.is_empty) state = STOPPING; } @@ -1048,16 +1052,36 @@ namespace Frida.Fruity { polled_usb_devices = current_devices; } - private UsbOperation allocate_usb_operation () { + private UsbOperation allocate_usb_operation () throws Error { var op = new PendingUsbOperation (this); - lock (pending_usb_ops) - pending_usb_ops.add (op); + + bool added = false; + lock (state) { + switch (state) { + case CREATED: + break; + case STARTING: + case STARTED: + pending_usb_ops.add (op); + added = true; + break; + case FLUSHING: + case STOPPING: + case STOPPED: + break; + } + } + + if (!added) + throw new Error.INVALID_OPERATION ("Unable to allocate USB operation in the current state"); + return op; } private void on_usb_operation_complete (PendingUsbOperation op) { - lock (pending_usb_ops) + lock (state) pending_usb_ops.remove (op); + usb_context.interrupt_event_handler (); } diff --git a/src/fruity/usb.vala b/src/fruity/usb.vala index 728e9f926..9d540c8a0 100644 --- a/src/fruity/usb.vala +++ b/src/fruity/usb.vala @@ -290,7 +290,7 @@ namespace Frida.Fruity { } internal interface UsbDeviceBackend : Object { - public abstract UsbOperation allocate_usb_operation (); + public abstract UsbOperation allocate_usb_operation () throws Error; } internal interface UsbOperation : Object {