Fix race condition in DataFetcherSharedMemoryBase

A race condition can occur when a polling thread tries to obtain a pointer to the shared memory via a std::map, while that map is modified by the main thread.
This patch implements a fix such that the polling thread does not have direct access to the std::map where the shared memory pointers are stored. Instead the pointer is passed as an argument of the Start() method.

This patch fixes the DataFetcherSharedMemoryBaseTest.DoesPollMotionAndOrientation test on linux tsan.

BUG=284959

Review URL: https://chromiumcodereview.appspot.com/23441047

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221404 0039d316-1c4b-4281-b951-d872f2087c98
parent a977af43
...@@ -7,10 +7,12 @@ ...@@ -7,10 +7,12 @@
#include "content/browser/device_orientation/data_fetcher_shared_memory_base.h" #include "content/browser/device_orientation/data_fetcher_shared_memory_base.h"
#if defined(OS_MACOSX) #if !defined(OS_ANDROID)
#include "content/common/device_motion_hardware_buffer.h" #include "content/common/device_motion_hardware_buffer.h"
#include "content/common/device_orientation/device_orientation_hardware_buffer.h" #include "content/common/device_orientation/device_orientation_hardware_buffer.h"
#endif
#if defined(OS_MACOSX)
class SuddenMotionSensor; class SuddenMotionSensor;
#endif #endif
...@@ -24,16 +26,17 @@ class CONTENT_EXPORT DataFetcherSharedMemory ...@@ -24,16 +26,17 @@ class CONTENT_EXPORT DataFetcherSharedMemory
virtual ~DataFetcherSharedMemory(); virtual ~DataFetcherSharedMemory();
private: private:
virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE;
virtual bool Start(ConsumerType consumer_type) OVERRIDE;
virtual bool Stop(ConsumerType consumer_type) OVERRIDE; virtual bool Stop(ConsumerType consumer_type) OVERRIDE;
#if !defined(OS_ANDROID)
DeviceMotionHardwareBuffer* motion_buffer_;
DeviceOrientationHardwareBuffer* orientation_buffer_;
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
virtual void Fetch(unsigned consumer_bitmask) OVERRIDE; virtual void Fetch(unsigned consumer_bitmask) OVERRIDE;
virtual bool IsPolling() const OVERRIDE; virtual bool IsPolling() const OVERRIDE;
DeviceMotionHardwareBuffer* motion_buffer_;
DeviceOrientationHardwareBuffer* orientation_buffer_;
scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_; scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_;
#endif #endif
......
...@@ -17,8 +17,7 @@ DataFetcherSharedMemory::DataFetcherSharedMemory() { ...@@ -17,8 +17,7 @@ DataFetcherSharedMemory::DataFetcherSharedMemory() {
DataFetcherSharedMemory::~DataFetcherSharedMemory() { DataFetcherSharedMemory::~DataFetcherSharedMemory() {
} }
bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) { bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
void* buffer = GetSharedMemoryBuffer(consumer_type);
DCHECK(buffer); DCHECK(buffer);
switch (consumer_type) { switch (consumer_type) {
......
...@@ -36,7 +36,7 @@ class DataFetcherSharedMemoryBase::PollingThread : public base::Thread { ...@@ -36,7 +36,7 @@ class DataFetcherSharedMemoryBase::PollingThread : public base::Thread {
PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher); PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher);
virtual ~PollingThread(); virtual ~PollingThread();
void AddConsumer(ConsumerType consumer_type); void AddConsumer(ConsumerType consumer_type, void* buffer);
void RemoveConsumer(ConsumerType consumer_type); void RemoveConsumer(ConsumerType consumer_type);
unsigned GetConsumersBitmask() const { return consumers_bitmask_; } unsigned GetConsumersBitmask() const { return consumers_bitmask_; }
...@@ -63,9 +63,9 @@ DataFetcherSharedMemoryBase::PollingThread::~PollingThread() { ...@@ -63,9 +63,9 @@ DataFetcherSharedMemoryBase::PollingThread::~PollingThread() {
} }
void DataFetcherSharedMemoryBase::PollingThread::AddConsumer( void DataFetcherSharedMemoryBase::PollingThread::AddConsumer(
ConsumerType consumer_type) { ConsumerType consumer_type, void* buffer) {
DCHECK(fetcher_); DCHECK(fetcher_);
if (!fetcher_->Start(consumer_type)) if (!fetcher_->Start(consumer_type, buffer))
return; return;
consumers_bitmask_ |= consumer_type; consumers_bitmask_ |= consumer_type;
...@@ -119,7 +119,8 @@ bool DataFetcherSharedMemoryBase::StartFetchingDeviceData( ...@@ -119,7 +119,8 @@ bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
if (started_consumers_ & consumer_type) if (started_consumers_ & consumer_type)
return true; return true;
if (!GetSharedMemoryBuffer(consumer_type)) void* buffer = GetSharedMemoryBuffer(consumer_type);
if (!buffer)
return false; return false;
if (IsPolling()) { if (IsPolling()) {
...@@ -129,9 +130,9 @@ bool DataFetcherSharedMemoryBase::StartFetchingDeviceData( ...@@ -129,9 +130,9 @@ bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
FROM_HERE, FROM_HERE,
base::Bind(&PollingThread::AddConsumer, base::Bind(&PollingThread::AddConsumer,
base::Unretained(polling_thread_.get()), base::Unretained(polling_thread_.get()),
consumer_type)); consumer_type, buffer));
} else { } else {
if (!Start(consumer_type)) if (!Start(consumer_type, buffer))
return false; return false;
} }
......
...@@ -45,8 +45,6 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase { ...@@ -45,8 +45,6 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase {
DataFetcherSharedMemoryBase(); DataFetcherSharedMemoryBase();
virtual ~DataFetcherSharedMemoryBase(); virtual ~DataFetcherSharedMemoryBase();
void* GetSharedMemoryBuffer(ConsumerType consumer_type);
// Returns the message loop of the polling thread. // Returns the message loop of the polling thread.
// Returns NULL if there is no polling thread. // Returns NULL if there is no polling thread.
base::MessageLoop* GetPollingMessageLoop() const; base::MessageLoop* GetPollingMessageLoop() const;
...@@ -62,12 +60,13 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase { ...@@ -62,12 +60,13 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase {
// Start() method should call InitSharedMemoryBuffer() to get the shared // Start() method should call InitSharedMemoryBuffer() to get the shared
// memory pointer. If IsPolling() is true both Start() and Stop() methods // memory pointer. If IsPolling() is true both Start() and Stop() methods
// are called from the |polling_thread_|. // are called from the |polling_thread_|.
virtual bool Start(ConsumerType consumer_type) = 0; virtual bool Start(ConsumerType consumer_type, void* buffer) = 0;
virtual bool Stop(ConsumerType consumer_type) = 0; virtual bool Stop(ConsumerType consumer_type) = 0;
private: private:
bool InitAndStartPollingThreadIfNecessary(); bool InitAndStartPollingThreadIfNecessary();
base::SharedMemory* GetSharedMemory(ConsumerType consumer_type); base::SharedMemory* GetSharedMemory(ConsumerType consumer_type);
void* GetSharedMemoryBuffer(ConsumerType consumer_type);
unsigned started_consumers_; unsigned started_consumers_;
......
...@@ -33,15 +33,16 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase { ...@@ -33,15 +33,16 @@ class FakeDataFetcher : public DataFetcherSharedMemoryBase {
} }
virtual ~FakeDataFetcher() { } virtual ~FakeDataFetcher() { }
bool Init(ConsumerType consumer_type) { bool Init(ConsumerType consumer_type, void* buffer) {
EXPECT_TRUE(buffer);
switch (consumer_type) { switch (consumer_type) {
case CONSUMER_TYPE_MOTION: case CONSUMER_TYPE_MOTION:
motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>( motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
GetSharedMemoryBuffer(consumer_type));
break; break;
case CONSUMER_TYPE_ORIENTATION: case CONSUMER_TYPE_ORIENTATION:
orientation_buffer_ = static_cast<DeviceOrientationHardwareBuffer*>( orientation_buffer_ =
GetSharedMemoryBuffer(consumer_type)); static_cast<DeviceOrientationHardwareBuffer*>(buffer);
break; break;
default: default:
return false; return false;
...@@ -128,12 +129,12 @@ class FakeNonPollingDataFetcher : public FakeDataFetcher { ...@@ -128,12 +129,12 @@ class FakeNonPollingDataFetcher : public FakeDataFetcher {
FakeNonPollingDataFetcher() { } FakeNonPollingDataFetcher() { }
virtual ~FakeNonPollingDataFetcher() { } virtual ~FakeNonPollingDataFetcher() { }
virtual bool Start(ConsumerType consumer_type) OVERRIDE { virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
base::SharedMemoryHandle handle = GetSharedMemoryHandleForProcess( base::SharedMemoryHandle handle = GetSharedMemoryHandleForProcess(
consumer_type, base::GetCurrentProcessHandle()); consumer_type, base::GetCurrentProcessHandle());
EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle)); EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle));
Init(consumer_type); Init(consumer_type, buffer);
switch (consumer_type) { switch (consumer_type) {
case CONSUMER_TYPE_MOTION: case CONSUMER_TYPE_MOTION:
UpdateMotion(); UpdateMotion();
...@@ -182,13 +183,13 @@ class FakePollingDataFetcher : public FakeDataFetcher { ...@@ -182,13 +183,13 @@ class FakePollingDataFetcher : public FakeDataFetcher {
FakePollingDataFetcher() { } FakePollingDataFetcher() { }
virtual ~FakePollingDataFetcher() { } virtual ~FakePollingDataFetcher() { }
virtual bool Start(ConsumerType consumer_type) OVERRIDE { virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop()); EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
base::SharedMemoryHandle handle = GetSharedMemoryHandleForProcess( base::SharedMemoryHandle handle = GetSharedMemoryHandleForProcess(
consumer_type, base::GetCurrentProcessHandle()); consumer_type, base::GetCurrentProcessHandle());
EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle)); EXPECT_TRUE(base::SharedMemory::IsHandleValid(handle));
Init(consumer_type); Init(consumer_type, buffer);
switch (consumer_type) { switch (consumer_type) {
case CONSUMER_TYPE_MOTION: case CONSUMER_TYPE_MOTION:
start_motion_.Signal(); start_motion_.Signal();
......
...@@ -12,7 +12,8 @@ namespace { ...@@ -12,7 +12,8 @@ namespace {
static bool SetMotionBuffer(content::DeviceMotionHardwareBuffer* buffer, static bool SetMotionBuffer(content::DeviceMotionHardwareBuffer* buffer,
bool enabled) { bool enabled) {
DCHECK(buffer); if (!buffer)
return false;
buffer->seqlock.WriteBegin(); buffer->seqlock.WriteBegin();
buffer->data.allAvailableSensorsAreActive = enabled; buffer->data.allAvailableSensorsAreActive = enabled;
buffer->seqlock.WriteEnd(); buffer->seqlock.WriteEnd();
...@@ -29,14 +30,13 @@ DataFetcherSharedMemory::DataFetcherSharedMemory() { ...@@ -29,14 +30,13 @@ DataFetcherSharedMemory::DataFetcherSharedMemory() {
DataFetcherSharedMemory::~DataFetcherSharedMemory() { DataFetcherSharedMemory::~DataFetcherSharedMemory() {
} }
bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) { bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
void* buffer = GetSharedMemoryBuffer(consumer_type);
DCHECK(buffer); DCHECK(buffer);
switch (consumer_type) { switch (consumer_type) {
case CONSUMER_TYPE_MOTION: case CONSUMER_TYPE_MOTION:
return SetMotionBuffer( motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
static_cast<DeviceMotionHardwareBuffer*>(buffer), true); return SetMotionBuffer(motion_buffer_, true);
case CONSUMER_TYPE_ORIENTATION: case CONSUMER_TYPE_ORIENTATION:
NOTIMPLEMENTED(); NOTIMPLEMENTED();
break; break;
...@@ -47,13 +47,10 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) { ...@@ -47,13 +47,10 @@ bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) {
} }
bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) { bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
void* buffer = GetSharedMemoryBuffer(consumer_type);
DCHECK(buffer);
switch (consumer_type) { switch (consumer_type) {
case CONSUMER_TYPE_MOTION: case CONSUMER_TYPE_MOTION:
return SetMotionBuffer( return SetMotionBuffer(motion_buffer_, false);
static_cast<DeviceMotionHardwareBuffer*>(buffer), false);
case CONSUMER_TYPE_ORIENTATION: case CONSUMER_TYPE_ORIENTATION:
NOTIMPLEMENTED(); NOTIMPLEMENTED();
break; break;
......
...@@ -115,10 +115,8 @@ bool DataFetcherSharedMemory::IsPolling() const { ...@@ -115,10 +115,8 @@ bool DataFetcherSharedMemory::IsPolling() const {
return true; return true;
} }
bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) { bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
DCHECK(base::MessageLoop::current() == GetPollingMessageLoop()); DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
void* buffer = GetSharedMemoryBuffer(consumer_type);
DCHECK(buffer); DCHECK(buffer);
switch (consumer_type) { switch (consumer_type) {
......
...@@ -1129,17 +1129,3 @@ ...@@ -1129,17 +1129,3 @@
fun:content::UtilityThreadImpl::UtilityThreadImpl fun:content::UtilityThreadImpl::UtilityThreadImpl
fun:content::UtilityMainThread::InitInternal fun:content::UtilityMainThread::InitInternal
} }
{
bug_284959
ThreadSanitizer:Race
fun:std::_Rb_tree_insert_and_rebalance
fun:std::_Rb_tree::_M_insert_
fun:std::_Rb_tree::_M_insert_unique_
fun:std::map::insert
fun:std::map::operator[]
fun:content::DataFetcherSharedMemoryBase::GetSharedMemory
fun:content::DataFetcherSharedMemoryBase::GetSharedMemoryBuffer
fun:content::DataFetcherSharedMemoryBase::StartFetchingDeviceData
fun:content::::DataFetcherSharedMemoryBaseTest_DoesPollMotionAndOrientation_Test::TestBody
fun:testing::internal::HandleSehExceptionsInMethodIfSupported
}
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