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