[go: nahoru, domu]

blob: f508332a4f7f8dd0f29677559687ac241c71d783 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/tracing/public/cpp/stack_sampling/loader_lock_sampler_win.h"
#include <string>
#include <utility>
#include "base/files/file_path.h"
#include "base/scoped_native_library.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/test/test_waitable_event.h"
#include "base/win/scoped_handle.h"
#include "services/tracing/public/cpp/stack_sampling/loader_lock_sampler_test_strings.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
namespace {
class TestNamedWaitableEvent : public base::TestWaitableEvent {
public:
TestNamedWaitableEvent(const wchar_t* name)
: TestWaitableEvent(
base::win::ScopedHandle(::CreateEvent(nullptr,
/*bManualReset=*/TRUE,
/*bInitialState=*/FALSE,
name))) {}
};
} // namespace
TEST(LoaderLockSamplerTest, LockNotHeld) {
ProbingLoaderLockSampler sampler;
EXPECT_FALSE(sampler.IsLoaderLockHeld());
}
TEST(LoaderLockSamplerTest, LockHeldByOtherThread) {
ProbingLoaderLockSampler sampler;
base::test::TaskEnvironment task_environment{
base::test::TaskEnvironment::ThreadPoolCOMEnvironment::NONE};
// Creating TaskEnvironment initializes the thread pool, which takes the
// loader lock while creating background threads. Wait until it's released.
while (sampler.IsLoaderLockHeld()) {
base::TestWaitableEvent delay_event;
delay_event.TimedWait(TestTimeouts::tiny_timeout());
}
// Create events with fixed names that can be accessed from the helper DLL.
TestNamedWaitableEvent wait_for_loader_lock_event(
loader_lock_sampler_test::kWaitForLockEventName);
TestNamedWaitableEvent drop_loader_lock_event(
loader_lock_sampler_test::kDropLockEventName);
base::TestWaitableEvent dll_done_event;
base::ThreadPool::PostTask(
FROM_HERE, {base::MayBlock()},
base::BindLambdaForTesting([&dll_done_event] {
// This function will block until DllMain returns, or the load fails.
// The helper DLL will signal |wait_for_loader_lock_event| as soon as it
// enters DllMain, while it holds the loader lock. Then it will block
// with the loader lock held until |drop_loader_lock_event| is
// signalled.
base::ScopedNativeLibrary dll(base::FilePath(
FILE_PATH_LITERAL("loader_lock_sampler_test_dll.dll")));
// If the DLL did not load, |wait_for_loader_lock_event| will not be
// signalled and the TimedWait below will return false (timeout).
ASSERT_TRUE(dll.is_valid())
<< "ScopedNativeLibrary error " << dll.GetError()->ToString();
dll_done_event.Signal();
}));
// Wait for the background thread to take the loader lock.
ASSERT_TRUE(
wait_for_loader_lock_event.TimedWait(TestTimeouts::action_timeout()));
EXPECT_TRUE(sampler.IsLoaderLockHeld());
// Tell the DLL to drop the loader lock and exit from DllMain.
drop_loader_lock_event.Signal();
// Make sure the DllMain has exited.
ASSERT_TRUE(dll_done_event.TimedWait(TestTimeouts::action_timeout()));
// It takes a moment for the lock to be released.
base::TestWaitableEvent delay_event;
delay_event.TimedWait(TestTimeouts::tiny_timeout());
EXPECT_FALSE(sampler.IsLoaderLockHeld());
}
} // namespace tracing