TaskScheduler: Atomic operations in TaskTracker
With this CL, TaskTracker never acquires a lock except when shutdown is
not in progress.
TaskTracker::State wraps an Atomic32 whose LSB indicates whether shutdown
has been initiated and whose other bits count the number of tasks
blocking shutdown. This State is accessed in the following situations:
A) Before a BLOCK_SHUTDOWN task is posted
Increment the Atomic32 by 2 [1] and read it. If the "shutdown initiated"
bit is set, acquire the lock [2] to:
- DCHECK that shutdown hasn't completed
- Record a UMA histogram
B) Before a CONTINUE_ON_SHUTDOWN or SKIP_ON_SHUTDOWN task is posted:
Read the Atomic32. The task is allowed to be posted iff the
"shutdown initiated" bit isn't set.
C) Before a BLOCK_SHUTDOWN task is executed.
Read the Atomic32. DCHECK that there are tasks blocking shutdown
(number of tasks blocking shutdown was incremented when the task
was posted).
D) Before a SKIP_ON_SHUTDOWN task is executed.
Increment the Atomic32 by 2 [1] and read it.
If the "shutdown initiated" bit isn't set:
The task is allowed to be executed.
If the "shutdown initiated bit is set:
Decrement the Atomic32 by 2 [1] (to revert the incorrect increment) and
read it. If the number of tasks blocking shutdown became zero, do [3]
(note: this can trigger [3] more than once during shutdown as multiple
threads realize that shutdown has been requested, but [3] is resilient
to this).
E) Before a CONTINUE_ON_SHUTDOWN task is executed.
Read the Atomic32. Allow the task to be executed iff the "shutdown
initiated" bit isn't set.
F) After a BLOCK_SHUTDOWN or SKIP_ON_SHUTDOWN task is executed:
Decrement the Atomic32 by 2 [1] and read it. If the number of tasks
blocking shutdown became zero and "shutdown initiated", do [3].
G) When Shutdown() is called:
Acquire the lock.
Instantiate the shutdown complete event.
Increment the Atomic32 by 1 (to set the "shutdown initiated bit") and
read it. From this moment, if a thread causes the number of tasks
blocking shutdown to become zero, it will do [3].
If there are no tasks blocking shutdown, signal the event and return.
Wait until the shutdown event is signaled.
[1] Incrementing the Atomic32 by 2 increments the number of tasks
blocking shutdown by 1 because the LSB is used to indicate whether
shutdown has been initiated.
[2] The TaskTracker must be locked to access the shutdown event and the
number of BLOCK_SHUTDOWN tasks posted during shutdown.
[3] These actions are performed by OnNumTasksBlockingShutdownIsZero():
- Acquire the lock.
- DCHECK that shutdown has started (i.e. "shutdown initiated" bit is
set and shutdown event exists).
- Signal the shutdown complete event (note: this event can be signaled
more than once per multiple threads reaching the conclusion that
shutdown is complete, ref. SKIP_ON_SHUTDOWN dance above, but this
is harmless)
Benchmark - 10 million increment/decrement per thread
Atomic Lock
4 threads Win Z840 1.5s 2.2s
4 threads Ubuntu VM 0.8s 4.9s
4 threads MacBookPro 1.8s 270.7s
8 threads Win Z840 3.0s 5.5s
8 threads Ubuntu VM 1.6s 11.8s
8 threads MacBookPro 4.2s 559.0s
BUG=553459
Review-Url: https://codereview.chromium.org/2019763002
Cr-Commit-Position: refs/heads/master@{#406260}
CrOS-Libchrome-Original-Commit: caa8d6675e165cd04fc22f24b36c1076d6720388
4 files changed