• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UsbEventHandler(libusb_context * context)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 
~UsbEventHandler()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 
ThreadMain()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 
UsbContext(PlatformUsbContext context)63 UsbContext::UsbContext(PlatformUsbContext context) : context_(context) {
64   DCHECK(thread_checker_.CalledOnValidThread());
65   event_handler_ = new UsbEventHandler(context_);
66 }
67 
~UsbContext()68 UsbContext::~UsbContext() {
69   // destruction of UsbEventHandler is a blocking operation.
70   DCHECK(thread_checker_.CalledOnValidThread());
71   delete event_handler_;
72   event_handler_ = NULL;
73   libusb_exit(context_);
74 }
75