ThreadPoolWorker::ThreadPoolWorker(AbstractThreadPool* thread_pool, const std::string& name,
size_t stack_size)
: thread_pool_(thread_pool),
name_(name) {
std::string error_msg; // On Bionic, we know pthreads will give us a big-enough stack with // a guard page, so don't do anything special on Bionic libc. if (kUseCustomThreadPoolStack) { // Add an inaccessible page to catch stack overflow.
stack_size += gPageSize;
stack_ = MemMap::MapAnonymous(name.c_str(),
stack_size,
PROT_READ | PROT_WRITE, /*low_4gb=*/ false,
&error_msg);
CHECK(stack_.IsValid()) << error_msg;
CHECK_ALIGNED_PARAM(stack_.Begin(), gPageSize);
CheckedCall(mprotect, "mprotect bottom page of thread pool worker stack",
stack_.Begin(),
gPageSize,
PROT_NONE);
} constchar* reason = "new thread pool worker thread";
pthread_attr_t attr;
CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason); if (kUseCustomThreadPoolStack) {
CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack_.Begin(), stack_.Size()), reason);
} else {
CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), reason);
}
CHECK_PTHREAD_CALL(pthread_create, (&pthread_, &attr, &Callback, this), reason);
CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
}
ThreadPoolWorker::~ThreadPoolWorker() {
CHECK_PTHREAD_CALL(pthread_join, (pthread_, nullptr), "thread pool worker shutdown");
}
// Set the "nice" priority for tid (0 means self). staticvoid SetPriorityForTid(pid_t tid, int priority) {
CHECK_GE(priority, PRIO_MIN);
CHECK_LE(priority, PRIO_MAX); int result = setpriority(PRIO_PROCESS, tid, priority); if (result != 0) { #ifdefined(ART_TARGET_ANDROID)
PLOG(WARNING) << "Failed to setpriority to :" << priority; #endif // Setpriority may fail on host due to ulimit issues.
}
}
void* ThreadPoolWorker::Callback(void* arg) {
ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg);
Runtime* runtime = Runtime::Current(); // Don't run callbacks for ThreadPoolWorkers. These are created for JITThreadPool and // HeapThreadPool and are purely internal threads of the runtime and we don't need to run // callbacks for the thread attach / detach listeners. // (b/251163712) Calling callbacks for heap thread pool workers causes deadlocks in some libjdwp // tests. Deadlocks happen when a GC thread is attached while libjdwp holds the event handler // lock for an event that triggers an entrypoint update from deopt manager.
CHECK(runtime->AttachCurrentThread(
worker->name_.c_str(), true, // Thread-groups are only tracked by the peer j.l.Thread objects. If we aren't creating peers // we don't need to specify the thread group. We want to place these threads in the System // thread group because that thread group is where important threads that debuggers and // similar tools should not mess with are placed. As this is an internal-thread-pool we might // rely on being able to (for example) wait for all threads to finish some task. If debuggers // are suspending these threads that might not be possible.
worker->thread_pool_->create_peers_ ? runtime->GetSystemThreadGroup() : nullptr,
worker->thread_pool_->create_peers_, /* should_run_callbacks= */ false));
worker->thread_ = Thread::Current(); // Mark thread pool workers as runtime-threads.
worker->thread_->SetIsRuntimeThread(true); // Do work until its time to shut down.
worker->Run();
runtime->DetachCurrentThread(/* should_run_callbacks= */ false); // On zygote fork, we wait for this thread to exit completely. Set to highest Java priority // to speed that up.
SetPriorityForTid(0/* this thread */, Thread::PriorityToNiceness(kMaxThreadPriority)); return nullptr;
}
void ThreadPool::AddTask(Thread* self, Task* task) {
MutexLock mu(self, task_queue_lock_);
tasks_.push_back(task); // If we have any waiters, signal one. if (started_ && waiting_count_ != 0) {
task_queue_condition_.Signal(self);
}
}
void ThreadPool::RemoveAllTasks(Thread* self) { // The ThreadPool is responsible for calling Finalize (which usually delete // the task memory) on all the tasks.
Task* task = nullptr; do {
{
MutexLock mu(self, task_queue_lock_); if (tasks_.empty()) { return;
}
task = tasks_.front();
tasks_.pop_front();
}
task->Finalize();
} while (true);
}
const std::vector<ThreadPoolWorker*>& AbstractThreadPool::GetWorkers() { // Wait for all the workers to be created before returning them.
WaitForWorkersToBeCreated(); return threads_;
}
void AbstractThreadPool::DeleteThreads() {
{
Thread* self = Thread::Current();
MutexLock mu(self, task_queue_lock_); // Tell any remaining workers to shut down.
shutting_down_ = true; // Broadcast to everyone waiting.
task_queue_condition_.Broadcast(self);
completion_condition_.Broadcast(self);
} // Wait for the threads to finish. We expect the user of the pool // not to run multi-threaded calls to `CreateThreads` and `DeleteThreads`, // so we don't guard the field here.
STLDeleteElements(&threads_);
}
Task* AbstractThreadPool::GetTask(Thread* self) {
MutexLock mu(self, task_queue_lock_); while (!IsShuttingDown()) { const size_t thread_count = GetThreadCount(); // Ensure that we don't use more threads than the maximum active workers. const size_t active_threads = thread_count - waiting_count_; // <= since self is considered an active worker. if (active_threads <= max_active_workers_) {
Task* task = TryGetTaskLocked(); if (task != nullptr) { return task;
}
}
++waiting_count_; if (waiting_count_ == GetThreadCount() && !HasOutstandingTasks()) { // We may be done, lets broadcast to the completion condition.
completion_condition_.Broadcast(self);
} const uint64_t wait_start = kMeasureWaitTime ? NanoTime() : 0;
task_queue_condition_.Wait(self); if (kMeasureWaitTime) { const uint64_t wait_end = NanoTime();
total_wait_time_ += wait_end - std::max(wait_start, start_time_);
}
--waiting_count_;
}
// We are shutting down, return null to tell the worker thread to stop looping. return nullptr;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.