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") {
"evdev/event_factory_evdev.h",
"evdev/event_modifiers_evdev.cc",
"evdev/event_modifiers_evdev.h",
"evdev/event_thread_evdev.cc",
"evdev/event_thread_evdev.h",
"evdev/events_ozone_evdev_export.h",
"evdev/input_controller_evdev.cc",
"evdev/input_controller_evdev.h",
......
......@@ -25,6 +25,8 @@ namespace ui {
namespace {
// Thread safe dispatcher proxy for EventFactoryEvdev.
//
// This is used on the device I/O thread for dispatching to UI.
class ProxyDeviceEventDispatcher : public DeviceEventDispatcherEvdev {
public:
ProxyDeviceEventDispatcher(
......@@ -128,22 +130,7 @@ EventFactoryEvdev::~EventFactoryEvdev() {
void EventFactoryEvdev::Init() {
DCHECK(!initialized_);
// Set up device factory.
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);
StartThread();
initialized_ = true;
}
......@@ -152,10 +139,11 @@ scoped_ptr<SystemInputInjector> EventFactoryEvdev::CreateSystemInputInjector() {
// Use forwarding dispatcher for the injector rather than dispatching
// directly. We cannot assume it is safe to (re-)enter ui::Event dispatch
// synchronously from the injection point.
scoped_ptr<DeviceEventDispatcherEvdev> dispatcher(
scoped_ptr<DeviceEventDispatcherEvdev> proxy_dispatcher(
new ProxyDeviceEventDispatcher(base::ThreadTaskRunnerHandle::Get(),
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) {
......@@ -317,4 +305,26 @@ int EventFactoryEvdev::NextDeviceId() {
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
......@@ -13,6 +13,7 @@
#include "ui/events/ozone/device/device_event_observer.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_thread_evdev.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/keyboard_evdev.h"
......@@ -39,6 +40,9 @@ enum class DomCode;
#endif
// 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,
public PlatformEventSource {
public:
......@@ -88,16 +92,19 @@ class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver,
int NextDeviceId();
// Device thread initialization.
void StartThread();
void OnThreadStarted(
scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory);
// Used to uniquely identify input devices.
int last_device_id_;
// Interface for scanning & monitoring input devices.
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).
// The real object lives on a different thread.
scoped_ptr<InputDeviceFactoryEvdevProxy> input_device_factory_proxy_;
// Modifier key state (shift, ctrl, etc).
......@@ -115,9 +122,12 @@ class EVENTS_OZONE_EVDEV_EXPORT EventFactoryEvdev : public DeviceEventObserver,
// Object for controlling input devices.
InputControllerEvdev input_controller_;
// Whether we've set up the device factory & done initial scan.
// Whether we've set up the device factory.
bool initialized_;
// Thread for device I/O.
EventThreadEvdev thread_;
// Support weak pointers for attach & detach callbacks.
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;
typedef base::Callback<void(scoped_ptr<std::string>)> GetTouchDeviceStatusReply;
// 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 {
public:
InputDeviceFactoryEvdevProxy(
......
......@@ -87,6 +87,8 @@
'evdev/event_factory_evdev.h',
'evdev/event_modifiers_evdev.cc',
'evdev/event_modifiers_evdev.h',
'evdev/event_thread_evdev.cc',
'evdev/event_thread_evdev.h',
'evdev/events_ozone_evdev_export.h',
'evdev/input_controller_evdev.cc',
'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