blob: 4b8c5d25766eec150217197a34f9204583a12f1b [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/task/thread_pool/thread_group_native_win.h"
#include "base/optional.h"
#include "base/task/thread_pool/task_tracker.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/win/scoped_com_initializer.h"
namespace base {
namespace internal {
class ThreadGroupNativeWin::ScopedCallbackMayRunLongObserver
: public BlockingObserver {
public:
ScopedCallbackMayRunLongObserver(PTP_CALLBACK_INSTANCE callback)
: callback_(callback) {
SetBlockingObserverForCurrentThread(this);
}
~ScopedCallbackMayRunLongObserver() override {
ClearBlockingObserverForCurrentThread();
}
// BlockingObserver:
void BlockingStarted(BlockingType blocking_type) override {
::CallbackMayRunLong(callback_);
// CallbackMayRunLong should not be called twice.
ClearBlockingObserverForCurrentThread();
}
void BlockingTypeUpgraded() override {}
void BlockingEnded() override {}
private:
PTP_CALLBACK_INSTANCE callback_;
DISALLOW_COPY_AND_ASSIGN(ScopedCallbackMayRunLongObserver);
};
ThreadGroupNativeWin::ThreadGroupNativeWin(
TrackedRef<TaskTracker> task_tracker,
TrackedRef<Delegate> delegate,
ThreadGroup* predecessor_thread_group)
: ThreadGroupNative(std::move(task_tracker),
std::move(delegate),
predecessor_thread_group) {}
ThreadGroupNativeWin::~ThreadGroupNativeWin() {
::DestroyThreadpoolEnvironment(&environment_);
::CloseThreadpoolWork(work_);
::CloseThreadpool(pool_);
}
void ThreadGroupNativeWin::StartImpl() {
::InitializeThreadpoolEnvironment(&environment_);
pool_ = ::CreateThreadpool(nullptr);
DCHECK(pool_) << "LastError: " << ::GetLastError();
::SetThreadpoolThreadMinimum(pool_, 1);
::SetThreadpoolThreadMaximum(pool_, 256);
work_ = ::CreateThreadpoolWork(&RunNextTaskSource, this, &environment_);
DCHECK(work_) << "LastError: " << GetLastError();
::SetThreadpoolCallbackPool(&environment_, pool_);
}
void ThreadGroupNativeWin::JoinImpl() {
::WaitForThreadpoolWorkCallbacks(work_, true);
}
void ThreadGroupNativeWin::SubmitWork() {
// TODO(fdoray): Handle priorities by having different work objects and using
// SetThreadpoolCallbackPriority().
::SubmitThreadpoolWork(work_);
}
// static
void CALLBACK
ThreadGroupNativeWin::RunNextTaskSource(PTP_CALLBACK_INSTANCE callback_instance,
void* thread_group_windows_impl,
PTP_WORK) {
auto* thread_group =
static_cast<ThreadGroupNativeWin*>(thread_group_windows_impl);
// Windows Thread Pool API best practices state that all resources created
// in the callback function should be cleaned up before returning from the
// function. This includes COM initialization.
auto win_thread_environment = thread_group->GetScopedWindowsThreadEnvironment(
thread_group->worker_environment_);
ScopedCallbackMayRunLongObserver callback_may_run_long_observer(
callback_instance);
thread_group->RunNextTaskSourceImpl();
}
} // namespace internal
} // namespace base