[K/N][New MM] Move RunInNewThread to the main ThreadSupport.hpp
Some of unit-tests for the C++ part of the stdlib will require thread state switching. In the new MM, we already have a helper function that allows us to scopely initialize the memory subsystem for a separate thread. This patch makes this helper available for tests in the main runtime module by moving it to the main ThreadSupport.hpp.
This commit is contained in:
committed by
TeamCityServer
parent
fc43fbf578
commit
482305cfb2
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "MemoryPrivate.hpp"
|
||||
#include "TestSupport.hpp"
|
||||
|
||||
|
||||
// No-op, required for the new MM only.
|
||||
MemoryState* kotlin::InitMemoryForTests() { return nullptr; }
|
||||
|
||||
// No-op, required for the new MM only.
|
||||
void kotlin::DeinitMemoryForTests(MemoryState* state) {}
|
||||
@@ -3,6 +3,11 @@
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
namespace kotlin {
|
||||
|
||||
#if KONAN_WINDOWS
|
||||
@@ -15,4 +20,44 @@ constexpr int kDefaultThreadCount = 10;
|
||||
constexpr int kDefaultThreadCount = 100;
|
||||
#endif
|
||||
|
||||
// Performs minimal initialization of the current thread memory subsystem.
|
||||
// This initilization is enough for running tests for the C++ part for the stdlib.
|
||||
// - For the new MM: registeres the current thread in the thread registry.
|
||||
// - For the legacy MM: does nothing, returns nullptr.
|
||||
MemoryState* InitMemoryForTests();
|
||||
|
||||
// Deinitiliazes memory subsystem used for C++ stdlib tests.
|
||||
// - For the new MM: unregisteres the current thread, nullify current thread data.
|
||||
// - For the legacy MM: does nothing.
|
||||
void DeinitMemoryForTests(MemoryState* state);
|
||||
|
||||
// Scopely initializes the memory subsystem using the functions above.
|
||||
class ScopedMemoryInit : private kotlin::Pinned {
|
||||
public:
|
||||
ScopedMemoryInit() : memoryState_(InitMemoryForTests()) {}
|
||||
~ScopedMemoryInit() {
|
||||
ClearMemoryForTests(memoryState());
|
||||
DeinitMemoryForTests(memoryState_);
|
||||
}
|
||||
|
||||
MemoryState* memoryState() { return memoryState_; }
|
||||
private:
|
||||
MemoryState* memoryState_;
|
||||
};
|
||||
|
||||
// Runs the given function in a separate thread with minimally initialized memory subsystem.
|
||||
inline void RunInNewThread(std::function<void(MemoryState*)> f) {
|
||||
std::thread([&f]() {
|
||||
ScopedMemoryInit init;
|
||||
f(init.memoryState());
|
||||
}).join();
|
||||
}
|
||||
|
||||
// Runs the given function in a separate thread with minimally initialized memory subsystem.
|
||||
inline void RunInNewThread(std::function<void()> f) {
|
||||
RunInNewThread([&f](MemoryState* unused) {
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace kotlin
|
||||
|
||||
@@ -36,11 +36,11 @@ private:
|
||||
} // namespace
|
||||
|
||||
TEST_F(ExceptionObjHolderTest, NothingByDefault) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) { EXPECT_THAT(Collect(threadData), testing::IsEmpty()); });
|
||||
RunInNewThread([](mm::ThreadData& threadData) { EXPECT_THAT(Collect(threadData), testing::IsEmpty()); });
|
||||
}
|
||||
|
||||
TEST_F(ExceptionObjHolderTest, Throw) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
ASSERT_THAT(Collect(threadData), testing::IsEmpty());
|
||||
|
||||
ObjHeader exception;
|
||||
@@ -54,7 +54,7 @@ TEST_F(ExceptionObjHolderTest, Throw) {
|
||||
}
|
||||
|
||||
TEST_F(ExceptionObjHolderTest, ThrowInsideCatch) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
ASSERT_THAT(Collect(threadData), testing::IsEmpty());
|
||||
|
||||
ObjHeader exception1;
|
||||
@@ -74,7 +74,7 @@ TEST_F(ExceptionObjHolderTest, ThrowInsideCatch) {
|
||||
}
|
||||
|
||||
TEST_F(ExceptionObjHolderTest, StoreException) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
ASSERT_THAT(Collect(threadData), testing::IsEmpty());
|
||||
|
||||
ObjHeader exception1;
|
||||
|
||||
@@ -99,8 +99,7 @@ extern "C" void RestoreMemory(MemoryState*) {
|
||||
}
|
||||
|
||||
extern "C" void ClearMemoryForTests(MemoryState* state) {
|
||||
auto* threadData = FromMemoryState(state)->Get();
|
||||
threadData->ClearForTests();
|
||||
state->GetThreadData()->ClearForTests();
|
||||
}
|
||||
|
||||
extern "C" RUNTIME_NOTHROW OBJ_GETTER(AllocInstance, const TypeInfo* typeInfo) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "MemoryPrivate.hpp"
|
||||
#include "TestSupport.hpp"
|
||||
#include "ThreadRegistry.hpp"
|
||||
|
||||
MemoryState* kotlin::InitMemoryForTests() {
|
||||
auto threadDataNode = mm::ThreadRegistry::Instance().RegisterCurrentThread();
|
||||
return mm::ToMemoryState(threadDataNode);
|
||||
}
|
||||
|
||||
void kotlin::DeinitMemoryForTests(MemoryState* state) {
|
||||
auto threadDataNode = mm::FromMemoryState(state);
|
||||
mm::ThreadRegistry::Instance().Unregister(threadDataNode);
|
||||
// Nullify current thread data. The thread is still alive, so this is safe.
|
||||
mm::ThreadRegistry::TestSupport::SetCurrentThreadData(nullptr);
|
||||
}
|
||||
@@ -5,34 +5,15 @@
|
||||
|
||||
#include "../../main/cpp/TestSupport.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "MemoryPrivate.hpp"
|
||||
#include "ThreadData.hpp"
|
||||
#include "ThreadRegistry.hpp"
|
||||
|
||||
namespace kotlin {
|
||||
namespace mm {
|
||||
|
||||
template <typename F>
|
||||
void RunInNewThread(F f) {
|
||||
std::thread([&f]() {
|
||||
class ScopedRegistration : private kotlin::Pinned {
|
||||
public:
|
||||
ScopedRegistration() : node_(mm::ThreadRegistry::Instance().RegisterCurrentThread()) {}
|
||||
|
||||
~ScopedRegistration() { mm::ThreadRegistry::Instance().Unregister(node_); }
|
||||
|
||||
mm::ThreadData& threadData() { return *node_->Get(); }
|
||||
|
||||
private:
|
||||
mm::ThreadRegistry::Node* node_;
|
||||
} registration;
|
||||
|
||||
f(registration.threadData());
|
||||
|
||||
registration.threadData().ClearForTests();
|
||||
}).join();
|
||||
inline void RunInNewThread(std::function<void(mm::ThreadData&)> f) {
|
||||
kotlin::RunInNewThread([&f](MemoryState* state) {
|
||||
f(*state->GetThreadData());
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mm
|
||||
} // namespace kotlin
|
||||
|
||||
@@ -36,8 +36,16 @@ public:
|
||||
// Using this after `Unregister` for the thread has been called is undefined behaviour.
|
||||
ThreadData* CurrentThreadData() const noexcept { return currentThreadData_; }
|
||||
|
||||
class TestSupport {
|
||||
public:
|
||||
static void SetCurrentThreadData(ThreadData* newThreadData) {
|
||||
ThreadRegistry::currentThreadData_ = newThreadData;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend class GlobalData;
|
||||
friend class ThreadRegistry::TestSupport;
|
||||
|
||||
ThreadRegistry();
|
||||
~ThreadRegistry();
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
using namespace kotlin;
|
||||
|
||||
TEST(ThreadStateTest, StateSwitch) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
auto initialState = threadData.state();
|
||||
EXPECT_EQ(mm::ThreadState::kRunnable, initialState);
|
||||
|
||||
@@ -32,7 +32,7 @@ TEST(ThreadStateTest, StateSwitch) {
|
||||
}
|
||||
|
||||
TEST(ThreadStateTest, StateGuard) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
auto initialState = threadData.state();
|
||||
EXPECT_EQ(mm::ThreadState::kRunnable, initialState);
|
||||
{
|
||||
@@ -44,14 +44,14 @@ TEST(ThreadStateTest, StateGuard) {
|
||||
}
|
||||
|
||||
TEST(ThreadStateDeathTest, StateAsserts) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
EXPECT_DEATH(mm::AssertThreadState(&threadData, mm::ThreadState::kNative),
|
||||
"runtime assert: Unexpected thread state. Expected: NATIVE. Actual: RUNNABLE");
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ThreadStateDeathTest, IncorrectStateSwitch) {
|
||||
mm::RunInNewThread([](mm::ThreadData& threadData) {
|
||||
RunInNewThread([](mm::ThreadData& threadData) {
|
||||
EXPECT_DEATH(mm::SwitchThreadState(&threadData, kotlin::mm::ThreadState::kRunnable),
|
||||
"runtime assert: Illegal thread state switch. Old state: RUNNABLE. New state: RUNNABLE");
|
||||
EXPECT_DEATH(Kotlin_mm_switchThreadStateRunnable(),
|
||||
|
||||
Reference in New Issue
Block a user