Commit d52b2f15 authored by maksim.sisov's avatar maksim.sisov Committed by Commit bot

[sensors](Linux) Fix tsan data race in sensor reader

This CL fixes a tsan data race, which is caused by calling StopFetchingData
from different threads. It must not be allowed. Use the same thread by using
a PostTask.

BUG=673760
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_chromium_tsan_rel_ng

Review-Url: https://codereview.chromium.org/2569763004
Cr-Commit-Position: refs/heads/master@{#439798}
parent a91cd206
...@@ -270,9 +270,6 @@ char kTSanDefaultSuppressions[] = ...@@ -270,9 +270,6 @@ char kTSanDefaultSuppressions[] =
// http://crbug.com/587199 // http://crbug.com/587199
"race:base::TimerTest_OneShotTimer_CustomTaskRunner_Test::TestBody\n" "race:base::TimerTest_OneShotTimer_CustomTaskRunner_Test::TestBody\n"
// http://crbug.com/673760
"race:device::PollingSensorReader::StopFetchingData\n"
// End of suppressions. // End of suppressions.
; // Please keep this semicolon. ; // Please keep this semicolon.
......
...@@ -29,12 +29,16 @@ PlatformSensorLinux::PlatformSensorLinux( ...@@ -29,12 +29,16 @@ PlatformSensorLinux::PlatformSensorLinux(
default_configuration_( default_configuration_(
PlatformSensorConfiguration(sensor_device->device_frequency)), PlatformSensorConfiguration(sensor_device->device_frequency)),
reporting_mode_(sensor_device->reporting_mode), reporting_mode_(sensor_device->reporting_mode),
polling_thread_task_runner_(std::move(polling_thread_task_runner)),
weak_factory_(this) { weak_factory_(this) {
sensor_reader_ = sensor_reader_ = SensorReader::Create(
SensorReader::Create(sensor_device, this, polling_thread_task_runner); sensor_device, weak_factory_.GetWeakPtr(), task_runner_);
} }
PlatformSensorLinux::~PlatformSensorLinux() = default; PlatformSensorLinux::~PlatformSensorLinux() {
DCHECK(task_runner_->BelongsToCurrentThread());
polling_thread_task_runner_->DeleteSoon(FROM_HERE, sensor_reader_.release());
}
mojom::ReportingMode PlatformSensorLinux::GetReportingMode() { mojom::ReportingMode PlatformSensorLinux::GetReportingMode() {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
...@@ -62,15 +66,18 @@ void PlatformSensorLinux::NotifyPlatformSensorError() { ...@@ -62,15 +66,18 @@ void PlatformSensorLinux::NotifyPlatformSensorError() {
bool PlatformSensorLinux::StartSensor( bool PlatformSensorLinux::StartSensor(
const PlatformSensorConfiguration& configuration) { const PlatformSensorConfiguration& configuration) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
if (!sensor_reader_) polling_thread_task_runner_->PostTask(
return false; FROM_HERE,
return sensor_reader_->StartFetchingData(configuration); base::Bind(&SensorReader::StartFetchingData,
base::Unretained(sensor_reader_.get()), configuration));
return true;
} }
void PlatformSensorLinux::StopSensor() { void PlatformSensorLinux::StopSensor() {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(sensor_reader_); polling_thread_task_runner_->PostTask(
sensor_reader_->StopFetchingData(); FROM_HERE, base::Bind(&SensorReader::StopFetchingData,
base::Unretained(sensor_reader_.get())));
} }
bool PlatformSensorLinux::CheckSensorConfiguration( bool PlatformSensorLinux::CheckSensorConfiguration(
......
...@@ -45,6 +45,8 @@ class PlatformSensorLinux : public PlatformSensor { ...@@ -45,6 +45,8 @@ class PlatformSensorLinux : public PlatformSensor {
const PlatformSensorConfiguration default_configuration_; const PlatformSensorConfiguration default_configuration_;
const mojom::ReportingMode reporting_mode_; const mojom::ReportingMode reporting_mode_;
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner_;
// A sensor reader that reads values from sensor files // A sensor reader that reads values from sensor files
// and stores them to a SensorReading structure. // and stores them to a SensorReading structure.
std::unique_ptr<SensorReader> sensor_reader_; std::unique_ptr<SensorReader> sensor_reader_;
......
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#include "device/generic_sensor/platform_sensor_provider_linux.h" #include "device/generic_sensor/platform_sensor_provider_linux.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "base/task_runner_util.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "device/generic_sensor/linux/sensor_data_linux.h" #include "device/generic_sensor/linux/sensor_data_linux.h"
#include "device/generic_sensor/platform_sensor_linux.h" #include "device/generic_sensor/platform_sensor_linux.h"
#include "device/generic_sensor/platform_sensor_reader_linux.h"
namespace device { namespace device {
...@@ -59,8 +61,9 @@ void PlatformSensorProviderLinux::SensorDeviceFound( ...@@ -59,8 +61,9 @@ void PlatformSensorProviderLinux::SensorDeviceFound(
mojom::SensorType type, mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping, mojo::ScopedSharedBufferMapping mapping,
const PlatformSensorProviderBase::CreateSensorCallback& callback, const PlatformSensorProviderBase::CreateSensorCallback& callback,
SensorInfoLinux* sensor_device) { const SensorInfoLinux* sensor_device) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
DCHECK(sensor_device);
if (!StartPollingThread()) { if (!StartPollingThread()) {
callback.Run(nullptr); callback.Run(nullptr);
......
...@@ -58,7 +58,7 @@ class DEVICE_GENERIC_SENSOR_EXPORT PlatformSensorProviderLinux ...@@ -58,7 +58,7 @@ class DEVICE_GENERIC_SENSOR_EXPORT PlatformSensorProviderLinux
mojom::SensorType type, mojom::SensorType type,
mojo::ScopedSharedBufferMapping mapping, mojo::ScopedSharedBufferMapping mapping,
const PlatformSensorProviderBase::CreateSensorCallback& callback, const PlatformSensorProviderBase::CreateSensorCallback& callback,
SensorInfoLinux* sensor_device); const SensorInfoLinux* sensor_device);
bool StartPollingThread(); bool StartPollingThread();
......
...@@ -17,14 +17,13 @@ namespace device { ...@@ -17,14 +17,13 @@ namespace device {
class PollingSensorReader : public SensorReader { class PollingSensorReader : public SensorReader {
public: public:
PollingSensorReader( PollingSensorReader(const SensorInfoLinux* sensor_device,
const SensorInfoLinux* sensor_device, base::WeakPtr<PlatformSensorLinux> sensor,
PlatformSensorLinux* sensor, scoped_refptr<base::SingleThreadTaskRunner> task_runner);
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner);
~PollingSensorReader() override; ~PollingSensorReader() override;
// SensorReader implements: // SensorReader implements:
bool StartFetchingData( void StartFetchingData(
const PlatformSensorConfiguration& configuration) override; const PlatformSensorConfiguration& configuration) override;
void StopFetchingData() override; void StopFetchingData() override;
...@@ -47,59 +46,53 @@ class PollingSensorReader : public SensorReader { ...@@ -47,59 +46,53 @@ class PollingSensorReader : public SensorReader {
// Used to apply scalings and invert signs if needed. // Used to apply scalings and invert signs if needed.
const SensorPathsLinux::ReaderFunctor apply_scaling_func_; const SensorPathsLinux::ReaderFunctor apply_scaling_func_;
// Owned pointer to a timer. Will be deleted on a polling thread once // Repeating timer for data polling.
// destructor is called. base::RepeatingTimer timer_;
base::RepeatingTimer* timer_;
base::WeakPtrFactory<PollingSensorReader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PollingSensorReader); DISALLOW_COPY_AND_ASSIGN(PollingSensorReader);
}; };
PollingSensorReader::PollingSensorReader( PollingSensorReader::PollingSensorReader(
const SensorInfoLinux* sensor_device, const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor, base::WeakPtr<PlatformSensorLinux> sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner) scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: SensorReader(sensor, polling_task_runner), : SensorReader(sensor, std::move(task_runner)),
sensor_file_paths_(sensor_device->device_reading_files), sensor_file_paths_(sensor_device->device_reading_files),
scaling_value_(sensor_device->device_scaling_value), scaling_value_(sensor_device->device_scaling_value),
offset_value_(sensor_device->device_offset_value), offset_value_(sensor_device->device_offset_value),
apply_scaling_func_(sensor_device->apply_scaling_func), apply_scaling_func_(sensor_device->apply_scaling_func) {}
timer_(new base::RepeatingTimer()),
weak_factory_(this) {}
PollingSensorReader::~PollingSensorReader() { PollingSensorReader::~PollingSensorReader() {
polling_task_runner_->DeleteSoon(FROM_HERE, timer_); DCHECK(thread_checker_.CalledOnValidThread());
} }
bool PollingSensorReader::StartFetchingData( void PollingSensorReader::StartFetchingData(
const PlatformSensorConfiguration& configuration) { const PlatformSensorConfiguration& configuration) {
DCHECK(thread_checker_.CalledOnValidThread());
if (is_reading_active_) if (is_reading_active_)
StopFetchingData(); StopFetchingData();
InitializeTimer(configuration);
return polling_task_runner_->PostTask(
FROM_HERE, base::Bind(&PollingSensorReader::InitializeTimer,
weak_factory_.GetWeakPtr(), configuration));
} }
void PollingSensorReader::StopFetchingData() { void PollingSensorReader::StopFetchingData() {
DCHECK(thread_checker_.CalledOnValidThread());
is_reading_active_ = false; is_reading_active_ = false;
timer_->Stop(); timer_.Stop();
} }
void PollingSensorReader::InitializeTimer( void PollingSensorReader::InitializeTimer(
const PlatformSensorConfiguration& configuration) { const PlatformSensorConfiguration& configuration) {
DCHECK(polling_task_runner_->BelongsToCurrentThread()); DCHECK(thread_checker_.CalledOnValidThread());
timer_->Start(FROM_HERE, base::TimeDelta::FromMicroseconds( DCHECK(!is_reading_active_);
base::Time::kMicrosecondsPerSecond / timer_.Start(FROM_HERE, base::TimeDelta::FromMicroseconds(
configuration.frequency()), base::Time::kMicrosecondsPerSecond /
this, &PollingSensorReader::PollForData); configuration.frequency()),
this, &PollingSensorReader::PollForData);
is_reading_active_ = true; is_reading_active_ = true;
} }
void PollingSensorReader::PollForData() { void PollingSensorReader::PollForData() {
DCHECK(polling_task_runner_->BelongsToCurrentThread()); DCHECK(thread_checker_.CalledOnValidThread());
base::ThreadRestrictions::AssertIOAllowed();
SensorReading readings; SensorReading readings;
DCHECK_LE(sensor_file_paths_.size(), arraysize(readings.values)); DCHECK_LE(sensor_file_paths_.size(), arraysize(readings.values));
...@@ -127,36 +120,41 @@ void PollingSensorReader::PollForData() { ...@@ -127,36 +120,41 @@ void PollingSensorReader::PollForData() {
if (is_reading_active_) { if (is_reading_active_) {
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::UpdatePlatformSensorReading, FROM_HERE, base::Bind(&PlatformSensorLinux::UpdatePlatformSensorReading,
base::Unretained(sensor_), readings)); sensor_, readings));
} }
} }
// static // static
std::unique_ptr<SensorReader> SensorReader::Create( std::unique_ptr<SensorReader> SensorReader::Create(
const SensorInfoLinux* sensor_device, const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor, base::WeakPtr<PlatformSensorLinux> sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner) { scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
base::ThreadRestrictions::AssertIOAllowed();
// TODO(maksims): implement triggered reading. At the moment, // TODO(maksims): implement triggered reading. At the moment,
// only polling read is supported. // only polling read is supported.
return base::MakeUnique<PollingSensorReader>(sensor_device, sensor, return base::MakeUnique<PollingSensorReader>(sensor_device, sensor,
polling_thread_task_runner); std::move(task_runner));
} }
SensorReader::SensorReader( SensorReader::SensorReader(
PlatformSensorLinux* sensor, base::WeakPtr<PlatformSensorLinux> sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner) scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: sensor_(sensor), : sensor_(sensor),
polling_task_runner_(polling_task_runner), task_runner_(std::move(task_runner)),
task_runner_(base::ThreadTaskRunnerHandle::Get()), is_reading_active_(false) {
is_reading_active_(false) {} thread_checker_.DetachFromThread();
}
SensorReader::~SensorReader() = default; SensorReader::~SensorReader() {
DCHECK(thread_checker_.CalledOnValidThread());
}
void SensorReader::NotifyReadError() { void SensorReader::NotifyReadError() {
DCHECK(thread_checker_.CalledOnValidThread());
if (is_reading_active_) { if (is_reading_active_) {
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, base::Bind(&PlatformSensorLinux::NotifyPlatformSensorError, FROM_HERE,
base::Unretained(sensor_))); base::Bind(&PlatformSensorLinux::NotifyPlatformSensorError, sensor_));
} }
} }
......
...@@ -5,7 +5,11 @@ ...@@ -5,7 +5,11 @@
#ifndef DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_ #ifndef DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_
#define DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_ #define DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_READER_LINUX_H_
#include "base/callback.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "device/generic_sensor/generic_sensor_export.h"
namespace base { namespace base {
class SingleThreadTaskRunner; class SingleThreadTaskRunner;
...@@ -13,45 +17,49 @@ class SingleThreadTaskRunner; ...@@ -13,45 +17,49 @@ class SingleThreadTaskRunner;
namespace device { namespace device {
class PlatformSensorLinux;
class PlatformSensorConfiguration; class PlatformSensorConfiguration;
class PlatformSensorLinux;
struct SensorInfoLinux; struct SensorInfoLinux;
// A generic reader class that can be implemented with two different strategies: // A generic reader class that can be implemented with two different strategies:
// polling and on trigger. // polling and on trigger. All methods are not thread-safe and must be called
// on a polling thread that allows I/O.
class SensorReader { class SensorReader {
public: public:
// Creates a new instance of SensorReader. At the moment, only polling // Creates a new instance of SensorReader. At the moment, only polling
// reader is supported. // reader is supported.
static std::unique_ptr<SensorReader> Create( static std::unique_ptr<SensorReader> Create(
const SensorInfoLinux* sensor_device, const SensorInfoLinux* sensor_device,
PlatformSensorLinux* sensor, base::WeakPtr<PlatformSensorLinux> sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_thread_task_runner); scoped_refptr<base::SingleThreadTaskRunner> task_runner);
virtual ~SensorReader(); virtual ~SensorReader();
// Starts fetching data based on strategy this reader has chosen. // Starts fetching data based on strategy this reader has chosen.
// Only polling strategy is supported at the moment. Thread safe. // Only polling strategy is supported at the moment.
virtual bool StartFetchingData( virtual void StartFetchingData(
const PlatformSensorConfiguration& configuration) = 0; const PlatformSensorConfiguration& configuration) = 0;
// Stops fetching data. Thread safe. // Stops fetching data.
virtual void StopFetchingData() = 0; virtual void StopFetchingData() = 0;
protected: protected:
SensorReader(PlatformSensorLinux* sensor, SensorReader(base::WeakPtr<PlatformSensorLinux> sensor,
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner); scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Notifies |sensor_| about an error. // Notifies |sensor_| about an error.
void NotifyReadError(); void NotifyReadError();
// Non-owned pointer to a sensor that created this reader. // In builds with DCHECK enabled checks that methods of this
PlatformSensorLinux* sensor_; // and derived classes are called on a right thread.
base::ThreadChecker thread_checker_;
// A task runner that is used to poll data. // A sensor that this reader is owned by and notifies about errors and
scoped_refptr<base::SingleThreadTaskRunner> polling_task_runner_; // readings to.
base::WeakPtr<PlatformSensorLinux> sensor_;
// A task runner that belongs to a thread this reader is created on. // A task runner that is used to report about new readings and errors
// to a |sensor_|.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Indicates if reading is active. // Indicates if reading is active.
......
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