Check point root marking.
Added thread list checkpoint function, this goes through every thread and runs
the checkpoint on each thread. Threads that are runnable run the checkpoint
callback themselves in the next suspend check, while suspended threads are
left suspended but have the callback called on them.
Added a checkpoint visitor member to each thread, this visitor called when the
checkpoint request flag is set during transitions to suspended from runnable.
Using the checkpoint to mark the roots reduces the first pause of partial /
full gc to around 1 ms.
Change-Id: I97239cc72ee0e4a3397e9138a62ee559268dce0a
diff --git a/src/thread.h b/src/thread.h
index d559449..abfd719 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -101,10 +101,17 @@
kSuspendRequest = 1, // If set implies that suspend_count_ > 0.
kExceptionPending = 2, // If set implies that exception_ != NULL.
kEnterInterpreter = 4, // Instruct managed code it should enter the interpreter.
+ kCheckpointRequest = 8, // Request that the thread do some set of work.
};
class PACKED Thread {
public:
+ class CheckpointFunction {
+ public:
+ virtual ~CheckpointFunction() { }
+ virtual void Run(Thread* self) = 0;
+ };
+
// Space to throw a StackOverflowError in.
#if !defined(ART_USE_LLVM_COMPILER)
static const size_t kStackOverflowReservedBytes = 4 * KB;
@@ -167,13 +174,17 @@
return debug_suspend_count_;
}
- bool IsSuspended() const EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_suspend_count_lock_) {
- return GetState() != kRunnable && ReadFlag(kSuspendRequest);
+ bool IsSuspended() const {
+ union StateAndFlags state_and_flags = state_and_flags_;
+ return state_and_flags.as_struct.state != kRunnable &&
+ (state_and_flags.as_struct.flags & kSuspendRequest) != 0;
}
void ModifySuspendCount(Thread* self, int delta, bool for_debugger)
EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_suspend_count_lock_);
+ bool RequestCheckpoint(CheckpointFunction* function);
+
// Called when thread detected that the thread_suspend_count_ was non-zero. Gives up share of
// mutator_lock_ and waits until it is resumed and thread_suspend_count_ is zero.
void FullSuspendCheck()
@@ -570,6 +581,19 @@
held_mutexes_[level] = mutex;
}
+ void RunCheckpointFunction() {
+ CHECK(checkpoint_function_ != NULL);
+ checkpoint_function_->Run(this);
+ }
+
+ bool ReadFlag(ThreadFlag flag) const {
+ return (state_and_flags_.as_struct.flags & flag) != 0;
+ }
+
+ void AtomicSetFlag(ThreadFlag flag);
+
+ void AtomicClearFlag(ThreadFlag flag);
+
private:
// We have no control over the size of 'bool', but want our boolean fields
// to be 4-byte quantities.
@@ -617,14 +641,6 @@
void NotifyLocked(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_);
- bool ReadFlag(ThreadFlag flag) const {
- return (state_and_flags_.as_struct.flags & flag) != 0;
- }
-
- void AtomicSetFlag(ThreadFlag flag);
-
- void AtomicClearFlag(ThreadFlag flag);
-
static void ThreadExitCallback(void* arg);
// TLS key used to retrieve the Thread*.
@@ -759,6 +775,9 @@
// Cause for last suspension.
const char* last_no_thread_suspension_cause_;
+ // Pending checkpoint functions.
+ CheckpointFunction* checkpoint_function_;
+
public:
// Runtime support function pointers
// TODO: move this near the top, since changing its offset requires all oats to be recompiled!