• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
UsbEventHandler(libusb_context * context)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 
~UsbEventHandler()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 
ThreadMain()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 
UsbContext(PlatformUsbContext context)68 UsbContext::UsbContext(PlatformUsbContext context) : context_(context) {
69   DCHECK(thread_checker_.CalledOnValidThread());
70   event_handler_ = new UsbEventHandler(context_);
71 }
72 
~UsbContext()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