Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1489)

Unified Diff: content/child/shared_memory_data_consumer_handle.cc

Issue 1234213002: Fix data races on |SharedMemoryDataConsumerHandle::Context::notification_task_runner_| (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add AssertAquired(). Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/child/shared_memory_data_consumer_handle.cc
diff --git a/content/child/shared_memory_data_consumer_handle.cc b/content/child/shared_memory_data_consumer_handle.cc
index f11435ada87c22572379c59ce9b80f2e50c85b44..7bf404a5281e2884dc031534fb89343cb0e4db89 100644
--- a/content/child/shared_memory_data_consumer_handle.cc
+++ b/content/child/shared_memory_data_consumer_handle.cc
@@ -46,6 +46,8 @@ class DelegateThreadSafeReceivedData final
using Result = blink::WebDataConsumerHandle::Result;
+// All methods (except for ctor/dtor) must be called with |lock_| aquired
+// unless otherwise stated.
class SharedMemoryDataConsumerHandle::Context final
: public base::RefCountedThreadSafe<Context> {
public:
@@ -59,8 +61,12 @@ class SharedMemoryDataConsumerHandle::Context final
is_handle_active_(true),
is_two_phase_read_in_progress_(false) {}
- bool IsEmpty() const { return queue_.empty(); }
+ bool IsEmpty() const {
+ lock_.AssertAcquired();
+ return queue_.empty();
+ }
void ClearIfNecessary() {
+ lock_.AssertAcquired();
if (!is_handle_locked() && !is_handle_active()) {
// No one is interested in the contents.
if (is_on_reader_detached_valid_) {
@@ -73,20 +79,35 @@ class SharedMemoryDataConsumerHandle::Context final
}
}
void ClearQueue() {
+ lock_.AssertAcquired();
for (auto& data : queue_) {
delete data;
}
queue_.clear();
first_offset_ = 0;
}
- RequestPeer::ThreadSafeReceivedData* Top() { return queue_.front(); }
+ RequestPeer::ThreadSafeReceivedData* Top() {
+ lock_.AssertAcquired();
+ return queue_.front();
+ }
void Push(scoped_ptr<RequestPeer::ThreadSafeReceivedData> data) {
+ lock_.AssertAcquired();
queue_.push_back(data.release());
}
- size_t first_offset() const { return first_offset_; }
- Result result() const { return result_; }
- void set_result(Result r) { result_ = r; }
+ size_t first_offset() const {
+ lock_.AssertAcquired();
+ return first_offset_;
+ }
+ Result result() const {
+ lock_.AssertAcquired();
+ return result_;
+ }
+ void set_result(Result r) {
+ lock_.AssertAcquired();
+ result_ = r;
+ }
void AcquireReaderLock(Client* client) {
+ lock_.AssertAcquired();
DCHECK(!notification_task_runner_);
DCHECK(!client_);
notification_task_runner_ = base::ThreadTaskRunnerHandle::Get();
@@ -99,11 +120,13 @@ class SharedMemoryDataConsumerHandle::Context final
}
}
void ReleaseReaderLock() {
+ lock_.AssertAcquired();
DCHECK(notification_task_runner_);
notification_task_runner_ = nullptr;
client_ = nullptr;
}
void PostNotify() {
+ lock_.AssertAcquired();
auto runner = notification_task_runner_;
if (!runner)
return;
@@ -113,10 +136,12 @@ class SharedMemoryDataConsumerHandle::Context final
runner->PostTask(FROM_HERE,
base::Bind(&Context::NotifyInternal, this, false));
}
+ // Must be called with |lock_| not aquired.
void Notify() { NotifyInternal(true); }
// This function doesn't work in the destructor if |on_reader_detached_| is
// not null.
void ResetOnReaderDetached() {
+ lock_.AssertAcquired();
if (on_reader_detached_.is_null()) {
DCHECK(!is_on_reader_detached_valid_);
return;
@@ -132,14 +157,25 @@ class SharedMemoryDataConsumerHandle::Context final
FROM_HERE, base::Bind(&Context::ResetOnReaderDetachedWithLock, this));
}
}
- bool is_handle_locked() const { return notification_task_runner_; }
+ bool is_handle_locked() const {
+ lock_.AssertAcquired();
+ return notification_task_runner_;
+ }
bool IsReaderBoundToCurrentThread() const {
+ lock_.AssertAcquired();
return notification_task_runner_ &&
notification_task_runner_->BelongsToCurrentThread();
}
- bool is_handle_active() const { return is_handle_active_; }
- void set_is_handle_active(bool b) { is_handle_active_ = b; }
+ bool is_handle_active() const {
+ lock_.AssertAcquired();
+ return is_handle_active_;
+ }
+ void set_is_handle_active(bool b) {
+ lock_.AssertAcquired();
+ is_handle_active_ = b;
+ }
void Consume(size_t s) {
+ lock_.AssertAcquired();
first_offset_ += s;
auto top = Top();
if (static_cast<size_t>(top->length()) <= first_offset_) {
@@ -149,18 +185,24 @@ class SharedMemoryDataConsumerHandle::Context final
}
}
bool is_two_phase_read_in_progress() const {
+ lock_.AssertAcquired();
return is_two_phase_read_in_progress_;
}
void set_is_two_phase_read_in_progress(bool b) {
+ lock_.AssertAcquired();
is_two_phase_read_in_progress_ = b;
}
+ // Can be called with |lock_| not aquired.
base::Lock& lock() { return lock_; }
private:
+ // Must be called with |lock_| not aquired.
void NotifyInternal(bool repost) {
- // Note that this function is not protected by |lock_|.
-
- auto runner = notification_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> runner;
+ {
+ base::AutoLock lock(lock_);
+ runner = notification_task_runner_;
+ }
if (!runner)
return;
@@ -180,6 +222,7 @@ class SharedMemoryDataConsumerHandle::Context final
}
}
void Clear() {
+ lock_.AssertAcquired();
for (auto& data : queue_) {
delete data;
}
@@ -190,6 +233,7 @@ class SharedMemoryDataConsumerHandle::Context final
// null. We have an assert in the destructor.
ResetOnReaderDetached();
}
+ // Must be called with |lock_| not aquired.
void ResetOnReaderDetachedWithLock() {
base::AutoLock lock(lock_);
ResetOnReaderDetached();
@@ -197,6 +241,7 @@ class SharedMemoryDataConsumerHandle::Context final
friend class base::RefCountedThreadSafe<Context>;
~Context() {
+ base::AutoLock lock(lock_);
DCHECK(on_reader_detached_.is_null());
// This is necessary because the queue stores raw pointers.
@@ -273,44 +318,33 @@ void SharedMemoryDataConsumerHandle::Writer::AddData(
}
void SharedMemoryDataConsumerHandle::Writer::Close() {
- bool needs_notification = false;
-
- {
- base::AutoLock lock(context_->lock());
- if (context_->result() == Ok) {
- context_->set_result(Done);
- context_->ResetOnReaderDetached();
- needs_notification = context_->IsEmpty();
+ base::AutoLock lock(context_->lock());
+ if (context_->result() == Ok) {
+ context_->set_result(Done);
+ context_->ResetOnReaderDetached();
+ if (context_->IsEmpty()) {
+ // We cannot issue the notification synchronously because this function
+ // can be called in the client's callback.
+ context_->PostNotify();
}
}
- if (needs_notification) {
- // We cannot issue the notification synchronously because this function can
- // be called in the client's callback.
- context_->PostNotify();
- }
}
void SharedMemoryDataConsumerHandle::Writer::Fail() {
- bool needs_notification = false;
- {
- base::AutoLock lock(context_->lock());
- if (context_->result() == Ok) {
- // TODO(yhirano): Use an appropriate error code other than
- // UnexpectedError.
- context_->set_result(UnexpectedError);
-
- if (context_->is_two_phase_read_in_progress()) {
- // If we are in two-phase read session, we cannot discard the data. We
- // will clear the queue at the end of the session.
- } else {
- context_->ClearQueue();
- }
+ base::AutoLock lock(context_->lock());
+ if (context_->result() == Ok) {
+ // TODO(yhirano): Use an appropriate error code other than
+ // UnexpectedError.
+ context_->set_result(UnexpectedError);
- context_->ResetOnReaderDetached();
- needs_notification = true;
+ if (context_->is_two_phase_read_in_progress()) {
+ // If we are in two-phase read session, we cannot discard the data. We
+ // will clear the queue at the end of the session.
+ } else {
+ context_->ClearQueue();
}
- }
- if (needs_notification) {
+
+ context_->ResetOnReaderDetached();
// We cannot issue the notification synchronously because this function can
// be called in the client's callback.
context_->PostNotify();
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698