Home | History | Annotate | Download | only in usb_service
      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