Commit c8a1dc54 authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

Reland "[MessageLoop] Lock-free ScheduleWork() scheme"

This is a reland of f7da13a2
(original change in PS1)

The original change was missing acquire ordering in
DisconnectFromParent(). This is necessary in order for
the disconnecting thread to see all memory side-effects
previously made by other threads (or some side-effects
of message_loop_->ScheduleWork() could racily come in
after ~MessageLoop()).

Also removed the DCHECK that
|operations_state_ == kDisconnectedBit| at the end of
DisconnectFromParent() as it was incorrect. A racy
BeforeOperation() call can make it 1->3 (and no-op) after
DisconnectFromParent() made it 0->1.

And lastly, added a scoped allowance to always allow the
very fast wait instead of requiring callers to know about
this implementation detail of MessageLoop (and reverted
changes to //net).

Original change's description:
> [MessageLoop] Lock-free ScheduleWork() scheme
>
> The Lock is causing hangs because of priority inversion
> mixed with priority boosting (ScheduleWork() tends to
> boost the destination thread which may deschedule the
> posting thread; if the posting thread is a background
> thread this boost-induded-desched-while-holding-lock
> can cause a livelock). See https://crbug.com/890978#c10
> for example crashes catching this.
>
> The Lock was only necessary for startup/shutdown and is
> being replaced by a lock-free atomic scheme in this CL.
>
> MessagePump::ScheduleWork() itself was already thread-safe
> (but the Android impl did unnecessarily check a non-atomic bool)
>
> This adds a WaitableEvent in ~MessageLoop(); hence the requirement
> for a wait-allowance in net's EmbeddedTestServer.
>
> TBR=zhongyi@chromium.org (embedded_test_server.cc side-effects)
>
> Bug: 890978, 874237
> Change-Id: I0916e5a99035a935b0a23a770af256f334e78c43
> Reviewed-on: https://chromium-review.googlesource.com/c/1278631
> Commit-Queue: Gabriel Charette <gab@chromium.org>
> Reviewed-by: François Doray <fdoray@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#601600}

Bug: 890978, 874237, 897925
Change-Id: I17c515f9a3169bbdfc303a4b259f34097e31730d
Reviewed-on: https://chromium-review.googlesource.com/c/1297129Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#602166}
parent e72bb599
This diff is collapsed.
......@@ -260,8 +260,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate,
// destructor to make sure all the task's destructors get called.
void DeletePendingTasks();
// Wakes up the message pump. Can be called on any thread. The caller is
// responsible for synchronizing ScheduleWork() calls.
// Wakes up the message pump. Thread-safe (and callers should avoid holding a
// Lock at all cost while making this call as some platforms' priority
// boosting features have been observed to cause the caller to get descheduled
// : https://crbug.com/890978).
void ScheduleWork();
// Returns |next_run_time| capped at 1 day from |recent_time_|. This is used
......
......@@ -112,9 +112,11 @@ class BASE_EXPORT MessagePump {
virtual void Quit() = 0;
// Schedule a DoWork callback to happen reasonably soon. Does nothing if a
// DoWork callback is already scheduled. This method may be called from any
// thread. Once this call is made, DoWork should not be "starved" at least
// until it returns a value of false.
// DoWork callback is already scheduled. Once this call is made, DoWork should
// not be "starved" at least until it returns a value of false. Thread-safe
// (and callers should avoid holding a Lock at all cost while making this call
// as some platforms' priority boosting features have been observed to cause
// the caller to get descheduled : https://crbug.com/890978).
virtual void ScheduleWork() = 0;
// Schedule a DoDelayedWork callback to happen at the specified time,
......
......@@ -278,9 +278,6 @@ void MessagePumpForUI::Quit() {
}
void MessagePumpForUI::ScheduleWork() {
if (ShouldQuit())
return;
// Write (add) 1 to the eventfd. This tells the Looper to wake up and call our
// callback, allowing us to run tasks. This also allows us to detect, when we
// clear the fd, whether additional work was scheduled after we finished
......
......@@ -149,6 +149,7 @@ class TaskTracker;
class AdjustOOMScoreHelper;
class GetAppOutputScopedAllowBaseSyncPrimitives;
class MessageLoop;
class SimpleThread;
class StackSamplingProfiler;
class Thread;
......@@ -353,6 +354,7 @@ class BASE_EXPORT ScopedAllowBaseSyncPrimitivesOutsideBlockingScope {
ThreadRestrictionsTest,
ScopedAllowBaseSyncPrimitivesOutsideBlockingScopeResetsState);
friend class ::KeyStorageLinux;
friend class base::MessageLoop;
friend class content::SynchronousCompositor;
friend class content::SynchronousCompositorHost;
friend class content::SynchronousCompositorSyncCallBridge;
......
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