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