summaryrefslogtreecommitdiffstats
path: root/mojo/common
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-16 05:34:18 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-16 05:34:18 +0000
commit5273d8ec81d472ed23562968650b304a6874b0d8 (patch)
tree709b239fc5f1fa41e5110a836c293524f40fb6c8 /mojo/common
parentd3157a679a4b4d8e6d04de1872ba6a803d2994dc (diff)
downloadchromium_src-5273d8ec81d472ed23562968650b304a6874b0d8.zip
chromium_src-5273d8ec81d472ed23562968650b304a6874b0d8.tar.gz
chromium_src-5273d8ec81d472ed23562968650b304a6874b0d8.tar.bz2
Fixes race condition in MojoMessagePump
I didn't realize ScheduleWork() can be invoked on any thread. BUG=359973 TEST=none R=darin@chromium.org Review URL: https://codereview.chromium.org/239683002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264125 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/common')
-rw-r--r--mojo/common/message_pump_mojo.cc92
-rw-r--r--mojo/common/message_pump_mojo.h17
2 files changed, 66 insertions, 43 deletions
diff --git a/mojo/common/message_pump_mojo.cc b/mojo/common/message_pump_mojo.cc
index 2afa72f..5bc3462b 100644
--- a/mojo/common/message_pump_mojo.cc
+++ b/mojo/common/message_pump_mojo.cc
@@ -68,69 +68,84 @@ void MessagePumpMojo::RemoveHandler(const Handle& handle) {
}
void MessagePumpMojo::Run(Delegate* delegate) {
- RunState* old_state = run_state_;
RunState run_state;
// TODO: better deal with error handling.
CHECK(run_state.read_handle.is_valid());
CHECK(run_state.write_handle.is_valid());
- run_state_ = &run_state;
+ RunState* old_state = NULL;
+ {
+ base::AutoLock auto_lock(run_state_lock_);
+ old_state = run_state_;
+ run_state_ = &run_state;
+ }
+ DoRunLoop(&run_state, delegate);
+ {
+ base::AutoLock auto_lock(run_state_lock_);
+ run_state_ = old_state;
+ }
+}
+
+void MessagePumpMojo::Quit() {
+ base::AutoLock auto_lock(run_state_lock_);
+ if (run_state_)
+ run_state_->should_quit = true;
+}
+
+void MessagePumpMojo::ScheduleWork() {
+ base::AutoLock auto_lock(run_state_lock_);
+ if (run_state_)
+ SignalControlPipe(*run_state_);
+}
+
+void MessagePumpMojo::ScheduleDelayedWork(
+ const base::TimeTicks& delayed_work_time) {
+ base::AutoLock auto_lock(run_state_lock_);
+ if (!run_state_)
+ return;
+ run_state_->delayed_work_time = delayed_work_time;
+ SignalControlPipe(*run_state_);
+}
+
+void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) {
bool more_work_is_plausible = true;
for (;;) {
const bool block = !more_work_is_plausible;
- DoInternalWork(block);
+ DoInternalWork(*run_state, block);
// There isn't a good way to know if there are more handles ready, we assume
// not.
more_work_is_plausible = false;
- if (run_state.should_quit)
+ if (run_state->should_quit)
break;
more_work_is_plausible |= delegate->DoWork();
- if (run_state.should_quit)
+ if (run_state->should_quit)
break;
more_work_is_plausible |= delegate->DoDelayedWork(
- &run_state.delayed_work_time);
- if (run_state.should_quit)
+ &run_state->delayed_work_time);
+ if (run_state->should_quit)
break;
if (more_work_is_plausible)
continue;
more_work_is_plausible = delegate->DoIdleWork();
- if (run_state.should_quit)
+ if (run_state->should_quit)
break;
}
- run_state_ = old_state;
-}
-
-void MessagePumpMojo::Quit() {
- if (run_state_)
- run_state_->should_quit = true;
}
-void MessagePumpMojo::ScheduleWork() {
- SignalControlPipe();
-}
-
-void MessagePumpMojo::ScheduleDelayedWork(
- const base::TimeTicks& delayed_work_time) {
- if (!run_state_)
- return;
- run_state_->delayed_work_time = delayed_work_time;
- SignalControlPipe();
-}
-
-void MessagePumpMojo::DoInternalWork(bool block) {
- const MojoDeadline deadline = block ? GetDeadlineForWait() : 0;
- const WaitState wait_state = GetWaitState();
+void MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) {
+ const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0;
+ const WaitState wait_state = GetWaitState(run_state);
const MojoResult result =
WaitMany(wait_state.handles, wait_state.wait_flags, deadline);
if (result == 0) {
// Control pipe was written to.
uint32_t num_bytes = 0;
- ReadMessageRaw(run_state_->read_handle.get(), NULL, &num_bytes, NULL, NULL,
+ ReadMessageRaw(run_state.read_handle.get(), NULL, &num_bytes, NULL, NULL,
MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
} else if (result > 0) {
const size_t index = static_cast<size_t>(result);
@@ -187,18 +202,16 @@ void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) {
}
}
-void MessagePumpMojo::SignalControlPipe() {
- if (!run_state_)
- return;
-
+void MessagePumpMojo::SignalControlPipe(const RunState& run_state) {
// TODO(sky): deal with error?
- WriteMessageRaw(run_state_->write_handle.get(), NULL, 0, NULL, 0,
+ WriteMessageRaw(run_state.write_handle.get(), NULL, 0, NULL, 0,
MOJO_WRITE_MESSAGE_FLAG_NONE);
}
-MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const {
+MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState(
+ const RunState& run_state) const {
WaitState wait_state;
- wait_state.handles.push_back(run_state_->read_handle.get());
+ wait_state.handles.push_back(run_state.read_handle.get());
wait_state.wait_flags.push_back(MOJO_WAIT_FLAG_READABLE);
for (HandleToHandler::const_iterator i = handlers_.begin();
@@ -209,8 +222,9 @@ MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const {
return wait_state;
}
-MojoDeadline MessagePumpMojo::GetDeadlineForWait() const {
- base::TimeTicks min_time = run_state_->delayed_work_time;
+MojoDeadline MessagePumpMojo::GetDeadlineForWait(
+ const RunState& run_state) const {
+ base::TimeTicks min_time = run_state.delayed_work_time;
for (HandleToHandler::const_iterator i = handlers_.begin();
i != handlers_.end(); ++i) {
if (min_time.is_null() && i->second.deadline < min_time)
diff --git a/mojo/common/message_pump_mojo.h b/mojo/common/message_pump_mojo.h
index cc21565..c761106 100644
--- a/mojo/common/message_pump_mojo.h
+++ b/mojo/common/message_pump_mojo.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump.h"
+#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "mojo/common/mojo_common_export.h"
#include "mojo/public/cpp/system/core.h"
@@ -61,25 +62,33 @@ class MOJO_COMMON_EXPORT MessagePumpMojo : public base::MessagePump {
typedef std::map<Handle, Handler> HandleToHandler;
+ // Implementation of Run().
+ void DoRunLoop(RunState* run_state, Delegate* delegate);
+
// Services the set of handles ready. If |block| is true this waits for a
// handle to become ready, otherwise this does not block.
- void DoInternalWork(bool block);
+ void DoInternalWork(const RunState& run_state, bool block);
// Removes the first invalid handle. This is called if MojoWaitMany finds an
// invalid handle.
void RemoveFirstInvalidHandle(const WaitState& wait_state);
- void SignalControlPipe();
+ void SignalControlPipe(const RunState& run_state);
- WaitState GetWaitState() const;
+ WaitState GetWaitState(const RunState& run_state) const;
// Returns the deadline for the call to MojoWaitMany().
- MojoDeadline GetDeadlineForWait() const;
+ MojoDeadline GetDeadlineForWait(const RunState& run_state) const;
// If non-NULL we're running (inside Run()). Member is reference to value on
// stack.
RunState* run_state_;
+ // Lock for accessing |run_state_|. In general the only method that we have to
+ // worry about is ScheduleWork(). All other methods are invoked on the same
+ // thread.
+ base::Lock run_state_lock_;
+
HandleToHandler handlers_;
// An ever increasing value assigned to each Handler::id. Used to detect