From b15de0c0580633701c19c32bb60bcd64f30da867 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Tue, 24 Jan 2017 13:12:19 -0800 Subject: [PATCH] ART: Add ThreadPool mode that creates peers Add a mode where worker threads in a thread pool will get a Java peer. Add a test. Bug: 29547798 Bug: 31684920 Test: m test-art-host-gtest-thread_pool_test Change-Id: I3654cc2be1294a79881b6ac9f84445a1e7f24b70 --- runtime/thread_pool.cc | 11 +++++++--- runtime/thread_pool.h | 9 +++++++- runtime/thread_pool_test.cc | 52 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index d9179c389..d24a5e5c4 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -88,7 +88,10 @@ void ThreadPoolWorker::Run() { void* ThreadPoolWorker::Callback(void* arg) { ThreadPoolWorker* worker = reinterpret_cast(arg); Runtime* runtime = Runtime::Current(); - CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, nullptr, false)); + CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), + true, + nullptr, + worker->thread_pool_->create_peers_)); worker->thread_ = Thread::Current(); // Thread pool workers cannot call into java. worker->thread_->SetCanCallIntoJava(false); @@ -112,7 +115,7 @@ void ThreadPool::RemoveAllTasks(Thread* self) { tasks_.clear(); } -ThreadPool::ThreadPool(const char* name, size_t num_threads) +ThreadPool::ThreadPool(const char* name, size_t num_threads, bool create_peers) : name_(name), task_queue_lock_("task queue lock"), task_queue_condition_("task queue condition", task_queue_lock_), @@ -124,7 +127,8 @@ ThreadPool::ThreadPool(const char* name, size_t num_threads) total_wait_time_(0), // Add one since the caller of constructor waits on the barrier too. creation_barier_(num_threads + 1), - max_active_workers_(num_threads) { + max_active_workers_(num_threads), + create_peers_(create_peers) { Thread* self = Thread::Current(); while (GetThreadCount() < num_threads) { const std::string worker_name = StringPrintf("%s worker thread %zu", name_.c_str(), @@ -217,6 +221,7 @@ Task* ThreadPool::TryGetTaskLocked() { void ThreadPool::Wait(Thread* self, bool do_work, bool may_hold_locks) { if (do_work) { + CHECK(!create_peers_); Task* task = nullptr; while ((task = TryGetTask(self)) != nullptr) { task->Run(self); diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h index 7ecfcd128..a465e1105 100644 --- a/runtime/thread_pool.h +++ b/runtime/thread_pool.h @@ -105,11 +105,17 @@ class ThreadPool { // Remove all tasks in the queue. void RemoveAllTasks(Thread* self) REQUIRES(!task_queue_lock_); - ThreadPool(const char* name, size_t num_threads); + // Create a named thread pool with the given number of threads. + // + // If create_peers is true, all worker threads will have a Java peer object. Note that if the + // pool is asked to do work on the current thread (see Wait), a peer may not be available. Wait + // will conservatively abort if create_peers and do_work are true. + ThreadPool(const char* name, size_t num_threads, bool create_peers = false); virtual ~ThreadPool(); // Wait for all tasks currently on queue to get completed. If the pool has been stopped, only // wait till all already running tasks are done. + // When the pool was created with peers for workers, do_work must not be true (see ThreadPool()). void Wait(Thread* self, bool do_work, bool may_hold_locks) REQUIRES(!task_queue_lock_); size_t GetTaskCount(Thread* self) REQUIRES(!task_queue_lock_); @@ -159,6 +165,7 @@ class ThreadPool { uint64_t total_wait_time_; Barrier creation_barier_; size_t max_active_workers_ GUARDED_BY(task_queue_lock_); + const bool create_peers_; private: friend class ThreadPoolWorker; diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index 14c2c3bac..28aa21f7a 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -20,6 +20,7 @@ #include "atomic.h" #include "common_runtime_test.h" +#include "scoped_thread_state_change-inl.h" #include "thread-inl.h" namespace art { @@ -159,4 +160,55 @@ TEST_F(ThreadPoolTest, RecursiveTest) { EXPECT_EQ((1 << depth) - 1, count.LoadSequentiallyConsistent()); } +class PeerTask : public Task { + public: + PeerTask() {} + + void Run(Thread* self) { + ScopedObjectAccess soa(self); + CHECK(self->GetPeer() != nullptr); + } + + void Finalize() { + delete this; + } +}; + +class NoPeerTask : public Task { + public: + NoPeerTask() {} + + void Run(Thread* self) { + ScopedObjectAccess soa(self); + CHECK(self->GetPeer() == nullptr); + } + + void Finalize() { + delete this; + } +}; + +// Tests for create_peer functionality. +TEST_F(ThreadPoolTest, PeerTest) { + Thread* self = Thread::Current(); + { + ThreadPool thread_pool("Thread pool test thread pool", 1); + thread_pool.AddTask(self, new NoPeerTask()); + thread_pool.StartWorkers(self); + thread_pool.Wait(self, false, false); + } + + { + // To create peers, the runtime needs to be started. + self->TransitionFromSuspendedToRunnable(); + bool started = runtime_->Start(); + ASSERT_TRUE(started); + + ThreadPool thread_pool("Thread pool test thread pool", 1, true); + thread_pool.AddTask(self, new PeerTask()); + thread_pool.StartWorkers(self); + thread_pool.Wait(self, false, false); + } +} + } // namespace art -- 2.11.0