1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "device/usb/usb_context.h" 6 7 #include "base/atomicops.h" 8 #include "base/logging.h" 9 #include "base/synchronization/waitable_event.h" 10 #include "base/threading/platform_thread.h" 11 #include "device/usb/usb_error.h" 12 #include "third_party/libusb/src/libusb/interrupt.h" 13 #include "third_party/libusb/src/libusb/libusb.h" 14 15 namespace device { 16 17 // The UsbEventHandler works around a design flaw in the libusb interface. There 18 // is currently no way to signal to libusb that any caller into one of the event 19 // handler calls should return without handling any events. 20 class UsbContext::UsbEventHandler : public base::PlatformThread::Delegate { 21 public: 22 explicit UsbEventHandler(libusb_context* context); 23 virtual ~UsbEventHandler(); 24 25 // base::PlatformThread::Delegate 26 virtual void ThreadMain() OVERRIDE; 27 28 private: 29 base::subtle::Atomic32 running_; 30 libusb_context* context_; 31 base::PlatformThreadHandle thread_handle_; 32 base::WaitableEvent start_polling_; 33 DISALLOW_COPY_AND_ASSIGN(UsbEventHandler); 34 }; 35 UsbEventHandler(libusb_context * context)36UsbContext::UsbEventHandler::UsbEventHandler(libusb_context* context) 37 : context_(context), thread_handle_(0), start_polling_(false, false) { 38 base::subtle::Release_Store(&running_, 1); 39 bool success = base::PlatformThread::Create(0, this, &thread_handle_); 40 DCHECK(success) << "Failed to create USB IO handling thread."; 41 start_polling_.Wait(); 42 } 43 ~UsbEventHandler()44UsbContext::UsbEventHandler::~UsbEventHandler() { 45 base::subtle::Release_Store(&running_, 0); 46 libusb_interrupt_handle_event(context_); 47 base::PlatformThread::Join(thread_handle_); 48 } 49 ThreadMain()50void UsbContext::UsbEventHandler::ThreadMain() { 51 base::PlatformThread::SetName("UsbEventHandler"); 52 VLOG(1) << "UsbEventHandler started."; 53 54 if (base::subtle::Acquire_Load(&running_)) { 55 start_polling_.Signal(); 56 } 57 while (base::subtle::Acquire_Load(&running_)) { 58 const int rv = libusb_handle_events(context_); 59 if (rv != LIBUSB_SUCCESS) { 60 VLOG(1) << "Failed to handle events: " 61 << ConvertPlatformUsbErrorToString(rv); 62 } 63 } 64 VLOG(1) << "UsbEventHandler shutting down."; 65 } 66 UsbContext(PlatformUsbContext context)67UsbContext::UsbContext(PlatformUsbContext context) : context_(context) { 68 DCHECK(thread_checker_.CalledOnValidThread()); 69 event_handler_ = new UsbEventHandler(context_); 70 } 71 ~UsbContext()72UsbContext::~UsbContext() { 73 // destruction of UsbEventHandler is a blocking operation. 74 DCHECK(thread_checker_.CalledOnValidThread()); 75 delete event_handler_; 76 event_handler_ = NULL; 77 libusb_exit(context_); 78 } 79 80 } // namespace device 81