Commit be9342d2 authored by spang's avatar spang Committed by Commit bot

ozone: evdev: Add dedicated events thread

This creates a new thread for polling evdev on, and moves the
InputDeviceFactoryEvdev object onto that thread. We'll use this new
thread to avoid UI-thread jank affecting the cursor.

BUG=449710
TEST=boot link_freon & move cursor with simulated UI jank.
     cursor moves while UI thread is stalled.

Review URL: https://codereview.chromium.org/873833002

Cr-Commit-Position: refs/heads/master@{#313981}
parent 32a19e6a
...@@ -74,6 +74,8 @@ component("events_ozone_evdev") { ...@@ -74,6 +74,8 @@ component("events_ozone_evdev") {
"evdev/event_factory_evdev.h", "evdev/event_factory_evdev.h",
"evdev/event_modifiers_evdev.cc", "evdev/event_modifiers_evdev.cc",
"evdev/event_modifiers_evdev.h", "evdev/event_modifiers_evdev.h",
"evdev/event_thread_evdev.cc",
"evdev/event_thread_evdev.h",
"evdev/events_ozone_evdev_export.h", "evdev/events_ozone_evdev_export.h",
"evdev/input_controller_evdev.cc", "evdev/input_controller_evdev.cc",
"evdev/input_controller_evdev.h", "evdev/input_controller_evdev.h",
......
...@@ -25,6 +25,8 @@ namespace ui { ...@@ -25,6 +25,8 @@ namespace ui {
namespace { namespace {
// Thread safe dispatcher proxy for EventFactoryEvdev. // Thread safe dispatcher proxy for EventFactoryEvdev.
//
// This is used on the device I/O thread for dispatching to UI.
class ProxyDeviceEventDispatcher : public DeviceEventDispatcherEvdev { class ProxyDeviceEventDispatcher : public DeviceEventDispatcherEvdev {
public: public:
ProxyDeviceEventDispatcher( ProxyDeviceEventDispatcher(
...@@ -128,22 +130,7 @@ EventFactoryEvdev::~EventFactoryEvdev() { ...@@ -128,22 +130,7 @@ EventFactoryEvdev::~EventFactoryEvdev() {
void EventFactoryEvdev::Init() { void EventFactoryEvdev::Init() {
DCHECK(!initialized_); DCHECK(!initialized_);
// Set up device factory. StartThread();
scoped_ptr<DeviceEventDispatcherEvdev> dispatcher(
new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(),
weak_ptr_factory_.GetWeakPtr()));
input_device_factory_.reset(
new InputDeviceFactoryEvdev(dispatcher.Pass(), cursor_));
input_device_factory_proxy_.reset(
new InputDeviceFactoryEvdevProxy(base::ThreadTaskRunnerHandle::Get(),
input_device_factory_->GetWeakPtr()));
// TODO(spang): This settings interface is really broken. crbug.com/450899
input_controller_.SetInputDeviceFactory(input_device_factory_proxy_.get());
// Scan & monitor devices.
device_manager_->AddObserver(this);
device_manager_->ScanDevices(this);
initialized_ = true; initialized_ = true;
} }
...@@ -152,10 +139,11 @@ scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() { ...@@ -152,10 +139,11 @@ scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() {
// Use forwarding dispatcher for the injector rather than dispatching // Use forwarding dispatcher for the injector rather than dispatching
// directly. We cannot assume it is safe to (re-)enter ui::Event dispatch // directly. We cannot assume it is safe to (re-)enter ui::Event dispatch
// synchronously from the injection point. // synchronously from the injection point.
scoped_ptr<DeviceEventDispatcherEvdev> dispatcher( scoped_ptr<DeviceEventDispatcherEvdev> proxy_dispatcher(
new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(), new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(),
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
return make_scoped_ptr(new InputInjectorEvdev(dispatcher.Pass(), cursor_)); return make_scoped_ptr(
new InputInjectorEvdev(proxy_dispatcher.Pass(), cursor_));
} }
void EventFactoryEvdev::DispatchKeyEvent(const KeyEventParams& params) { void EventFactoryEvdev::DispatchKeyEvent(const KeyEventParams& params) {
...@@ -317,4 +305,26 @@ int EventFactoryEvdev::NextDeviceId() { ...@@ -317,4 +305,26 @@ int EventFactoryEvdev::NextDeviceId() {
return ++last_device_id_; return ++last_device_id_;
} }
void EventFactoryEvdev::StartThread() {
// Set up device factory.
scoped_ptr<DeviceEventDispatcherEvdev> proxy_dispatcher(
new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(),
weak_ptr_factory_.GetWeakPtr()));
thread_.Start(proxy_dispatcher.Pass(), cursor_,
base::Bind(&EventFactoryEvdev::OnThreadStarted,
weak_ptr_factory_.GetWeakPtr()));
}
void EventFactoryEvdev::OnThreadStarted(
scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory) {
input_device_factory_proxy_ = input_device_factory.Pass();
// TODO(spang): This settings interface is really broken. crbug.com/450899
input_controller_.SetInputDeviceFactory(input_device_factory_proxy_.get());
// Scan & monitor devices.
device_manager_->AddObserver(this);
device_manager_->ScanDevices(this);
}
} // namespace ui } // namespace ui
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ui/events/ozone/device/device_event_observer.h" #include "ui/events/ozone/device/device_event_observer.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h" #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/event_modifiers_evdev.h" #include "ui/events/ozone/evdev/event_modifiers_evdev.h"
#include "ui/events/ozone/evdev/event_thread_evdev.h"
#include "ui/events/ozone/evdev/events_ozone_evdev_export.h" #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
#include "ui/events/ozone/evdev/input_controller_evdev.h" #include "ui/events/ozone/evdev/input_controller_evdev.h"
#include "ui/events/ozone/evdev/keyboard_evdev.h" #include "ui/events/ozone/evdev/keyboard_evdev.h"
...@@ -39,6 +40,9 @@ enum class DomCode; ...@@ -39,6 +40,9 @@ enum class DomCode;
#endif #endif
// Ozone events implementation for the Linux input subsystem ("evdev"). // Ozone events implementation for the Linux input subsystem ("evdev").
//
// This is a UI thread object, but creates its own thread for I/O. See
// InputDeviceFactoryEvdev for the I/O thread part.
class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver, class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver,
public PlatformEventSource { public PlatformEventSource {
public: public:
...@@ -88,16 +92,19 @@ class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver, ...@@ -88,16 +92,19 @@ class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver,
int NextDeviceId(); int NextDeviceId();
// Device thread initialization.
void StartThread();
void OnThreadStarted(
scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory);
// Used to uniquely identify input devices. // Used to uniquely identify input devices.
int last_device_id_; int last_device_id_;
// Interface for scanning & monitoring input devices. // Interface for scanning & monitoring input devices.
DeviceManager* device_manager_; // Not owned. DeviceManager* device_manager_; // Not owned.
// Factory for per-device objects.
scoped_ptr<InputDeviceFactoryEvdev> input_device_factory_;
// Proxy for input device factory (manages device I/O objects). // Proxy for input device factory (manages device I/O objects).
// The real object lives on a different thread.
scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory_proxy_; scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory_proxy_;
// Modifier key state (shift, ctrl, etc). // Modifier key state (shift, ctrl, etc).
...@@ -115,9 +122,12 @@ class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver, ...@@ -115,9 +122,12 @@ class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver,
// Object for controlling input devices. // Object for controlling input devices.
InputControllerEvdev input_controller_; InputControllerEvdev input_controller_;
// Whether we've set up the device factory & done initial scan. // Whether we've set up the device factory.
bool initialized_; bool initialized_;
// Thread for device I/O.
EventThreadEvdev thread_;
// Support weak pointers for attach & detach callbacks. // Support weak pointers for attach & detach callbacks.
base::WeakPtrFactory<EventFactoryEvdev> weak_ptr_factory_; base::WeakPtrFactory<EventFactoryEvdev> weak_ptr_factory_;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/events/ozone/evdev/event_thread_evdev.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
#include "ui/events/ozone/evdev/input_device_factory_evdev.h"
#include "ui/events/ozone/evdev/input_device_factory_evdev_proxy.h"
namespace ui {
namespace {
// Internal base::Thread subclass for events thread.
class EvdevThread : public base::Thread {
public:
EvdevThread(scoped_ptr<DeviceEventDispatcherEvdev> dispatcher,
CursorDelegateEvdev* cursor,
const EventThreadStartCallback& callback)
: base::Thread("evdev"),
dispatcher_(dispatcher.Pass()),
cursor_(cursor),
init_callback_(callback),
init_runner_(base::ThreadTaskRunnerHandle::Get()),
input_device_factory_(nullptr) {}
~EvdevThread() override { Stop(); }
void Init() override {
TRACE_EVENT0("ozone", "EvdevThread::Init");
input_device_factory_ =
new InputDeviceFactoryEvdev(dispatcher_.Pass(), cursor_);
scoped_ptr<InputDeviceFactoryEvdevProxy> proxy(
new InputDeviceFactoryEvdevProxy(base::ThreadTaskRunnerHandle::Get(),
input_device_factory_->GetWeakPtr()));
init_runner_->PostTask(FROM_HERE,
base::Bind(init_callback_, base::Passed(&proxy)));
}
void CleanUp() override {
TRACE_EVENT0("ozone", "EvdevThread::CleanUp");
delete input_device_factory_;
}
private:
// Initialization bits passed from main thread.
scoped_ptr<DeviceEventDispatcherEvdev> dispatcher_;
CursorDelegateEvdev* cursor_;
EventThreadStartCallback init_callback_;
scoped_refptr<base::SingleThreadTaskRunner> init_runner_;
// Thread-internal state.
InputDeviceFactoryEvdev* input_device_factory_;
};
} // namespace
EventThreadEvdev::EventThreadEvdev() {
}
EventThreadEvdev::~EventThreadEvdev() {
}
void EventThreadEvdev::Start(scoped_ptr<DeviceEventDispatcherEvdev> dispatcher,
CursorDelegateEvdev* cursor,
const EventThreadStartCallback& callback) {
TRACE_EVENT0("ozone", "EventThreadEvdev::Start");
thread_.reset(new EvdevThread(dispatcher.Pass(), cursor, callback));
if (!thread_->StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_UI, 0)))
LOG(FATAL) << "Failed to create input thread";
}
} // namespace ui
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_EVENTS_OZONE_EVDEV_EVENT_THREAD_EVDEV_H_
#define UI_EVENTS_OZONE_EVDEV_EVENT_THREAD_EVDEV_H_
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
namespace base {
class Thread;
}
namespace ui {
class CursorDelegateEvdev;
class DeviceEventDispatcherEvdev;
class InputDeviceFactoryEvdevProxy;
typedef base::Callback<void(scoped_ptr<InputDeviceFactoryEvdevProxy>)>
EventThreadStartCallback;
// Wrapper for events thread.
class EventThreadEvdev {
public:
EventThreadEvdev();
~EventThreadEvdev();
// Start a new events thread. All device events will get sent to the
// passed dispatcher. The thread will call directly into cursor, so it
// must be synchronized accordingly.
void Start(scoped_ptr<DeviceEventDispatcherEvdev> dispatcher,
CursorDelegateEvdev* cursor,
const EventThreadStartCallback& callback);
private:
scoped_ptr<base::Thread> thread_;
DISALLOW_COPY_AND_ASSIGN(EventThreadEvdev);
};
} // namespace ui
#endif // UI_EVENTS_OZONE_EVDEV_EVENT_THREAD_EVDEV_H_
...@@ -22,6 +22,9 @@ class InputDeviceFactoryEvdev; ...@@ -22,6 +22,9 @@ class InputDeviceFactoryEvdev;
typedef base::Callback<void(scoped_ptr<std::string>)> GetTouchDeviceStatusReply; typedef base::Callback<void(scoped_ptr<std::string>)> GetTouchDeviceStatusReply;
// Thread safe proxy for InputDeviceFactoryEvdev. // Thread safe proxy for InputDeviceFactoryEvdev.
//
// This is used on the UI thread to proxy calls to the real object on
// the device I/O thread.
class EVENTS_OZONE_EVDEV_EXPORT InputDeviceFactoryEvdevProxy { class EVENTS_OZONE_EVDEV_EXPORT InputDeviceFactoryEvdevProxy {
public: public:
InputDeviceFactoryEvdevProxy( InputDeviceFactoryEvdevProxy(
......
...@@ -87,6 +87,8 @@ ...@@ -87,6 +87,8 @@
'evdev/event_factory_evdev.h', 'evdev/event_factory_evdev.h',
'evdev/event_modifiers_evdev.cc', 'evdev/event_modifiers_evdev.cc',
'evdev/event_modifiers_evdev.h', 'evdev/event_modifiers_evdev.h',
'evdev/event_thread_evdev.cc',
'evdev/event_thread_evdev.h',
'evdev/events_ozone_evdev_export.h', 'evdev/events_ozone_evdev_export.h',
'evdev/input_controller_evdev.cc', 'evdev/input_controller_evdev.cc',
'evdev/input_controller_evdev.h', 'evdev/input_controller_evdev.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment