• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "gtest/gtest.h"
17 #include "runtime/include/coretypes/string.h"
18 #include "runtime/include/runtime.h"
19 #include "runtime/include/thread.h"
20 #include "runtime/include/gc_task.h"
21 #include "runtime/handle_base-inl.h"
22 
23 #include <array>
24 #include <atomic>
25 #include <thread>
26 #include <mutex>
27 #include <condition_variable>
28 
29 namespace panda::mem::test {
30 
31 static constexpr uint32_t TEST_THREADS = 8;
32 static constexpr uint32_t TEST_ITERS = 100;
33 
34 class MultithreadedInternStringTableTest : public testing::Test {
35 public:
MultithreadedInternStringTableTest()36     MultithreadedInternStringTableTest()
37     {
38         RuntimeOptions options;
39         options.SetShouldLoadBootPandaFiles(false);
40         options.SetShouldInitializeIntrinsics(false);
41 
42         options.SetGcType("epsilon");
43         options.SetCompilerEnableJit(false);
44         Runtime::Create(options);
45     }
46 
~MultithreadedInternStringTableTest()47     ~MultithreadedInternStringTableTest() override
48     {
49         Runtime::Destroy();
50     }
51 
AllocUtf8String(std::vector<uint8_t> data)52     static coretypes::String *AllocUtf8String(std::vector<uint8_t> data)
53     {
54         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
55         return coretypes::String::CreateFromMUtf8(data.data(), utf::MUtf8ToUtf16Size(data.data()), ctx,
56                                                   Runtime::GetCurrent()->GetPandaVM());
57     }
58 
SetUp()59     void SetUp() override
60     {
61         table_ = new StringTable();
62         thread_ = panda::MTManagedThread::GetCurrent();
63         thread_->ManagedCodeBegin();
64     }
65 
TearDown()66     void TearDown() override
67     {
68         thread_->ManagedCodeEnd();
69         delete table_;
70         table_ = nullptr;
71     }
72 
GetTable() const73     StringTable *GetTable() const
74     {
75         return table_;
76     }
77 
PreCheck()78     void PreCheck()
79     {
80         std::unique_lock<std::mutex> lk(pre_lock_);
81         counter_pre_++;
82         if (counter_pre_ == TEST_THREADS) {
83             pre_cv_.notify_all();
84             counter_pre_ = 0;
85         } else {
86             pre_cv_.wait(lk);
87         }
88     }
89 
CheckSameString(coretypes::String * string)90     void CheckSameString(coretypes::String *string)
91     {
92         // Loop until lock is taken
93         while (lock_.test_and_set(std::memory_order_seq_cst)) {
94         };
95         if (string_ != nullptr) {
96             ASSERT_EQ(string_, string);
97         } else {
98             string_ = string;
99         }
100         lock_.clear(std::memory_order_seq_cst);
101     }
102 
PostFree()103     void PostFree()
104     {
105         std::unique_lock<std::mutex> lk(post_lock_);
106         counter_post_++;
107         if (counter_post_ == TEST_THREADS) {
108             // There should be just one element in table
109             ASSERT_EQ(table_->Size(), 1);
110             string_ = nullptr;
111 
112             {
113                 os::memory::WriteLockHolder holder(table_->table_.table_lock_);
114                 table_->table_.table_.clear();
115             }
116             {
117                 os::memory::WriteLockHolder holder(table_->internal_table_.table_lock_);
118                 table_->internal_table_.table_.clear();
119             }
120 
121             post_cv_.notify_all();
122             counter_post_ = 0;
123         } else {
124             post_cv_.wait(lk);
125         }
126     }
127 
128 protected:
129     panda::MTManagedThread *thread_ {nullptr};
130 
131     std::mutex pre_lock_;
132     std::condition_variable pre_cv_;
133     int counter_pre_ = 0;
134     std::mutex post_lock_;
135     std::condition_variable post_cv_;
136     int counter_post_ = 0;
137     StringTable *table_ {nullptr};
138 
139     std::atomic_flag lock_ {0};
140     coretypes::String *string_ {nullptr};
141 };
142 
TestThreadEntry(MultithreadedInternStringTableTest * test)143 void TestThreadEntry(MultithreadedInternStringTableTest *test)
144 {
145     auto *this_thread =
146         panda::MTManagedThread::Create(panda::Runtime::GetCurrent(), panda::Runtime::GetCurrent()->GetPandaVM());
147     this_thread->ManagedCodeBegin();
148     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
149     std::vector<uint8_t> data {0xc2, 0xa7, 0x34, 0x00};
150     auto *table = test->GetTable();
151     for (uint32_t i = 0; i < TEST_ITERS; i++) {
152         test->PreCheck();
153         auto *interned_str = table->GetOrInternString(data.data(), 2U, ctx);
154         test->CheckSameString(interned_str);
155         test->PostFree();
156     }
157     this_thread->ManagedCodeEnd();
158     this_thread->Destroy();
159 }
160 
TEST_F(MultithreadedInternStringTableTest,CheckInternReturnsSameString)161 TEST_F(MultithreadedInternStringTableTest, CheckInternReturnsSameString)
162 {
163     std::array<std::thread, TEST_THREADS> threads;
164     for (uint32_t i = 0; i < TEST_THREADS; i++) {
165         threads[i] = std::thread(TestThreadEntry, this);
166     }
167     for (uint32_t i = 0; i < TEST_THREADS; i++) {
168         threads[i].join();
169     }
170 }
171 
172 }  // namespace panda::mem::test
173