diff options
Diffstat (limited to 'deps/v8/test/wasm-api-tests/threads.cc')
-rw-r--r-- | deps/v8/test/wasm-api-tests/threads.cc | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/deps/v8/test/wasm-api-tests/threads.cc b/deps/v8/test/wasm-api-tests/threads.cc new file mode 100644 index 0000000000..c93afc4a89 --- /dev/null +++ b/deps/v8/test/wasm-api-tests/threads.cc @@ -0,0 +1,105 @@ +// Copyright 2019 the V8 project 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 "test/wasm-api-tests/wasm-api-test.h" + +#include <mutex> +#include <thread> + +namespace v8 { +namespace internal { +namespace wasm { + +using ::wasm::Shared; + +namespace { + +const int kNumThreads = 10; +const int kIterationsPerThread = 3; +int g_traces; + +own<Trap*> Callback(void* env, const Val args[], Val results[]) { + std::lock_guard<std::mutex> lock(*reinterpret_cast<std::mutex*>(env)); + g_traces += args[0].i32(); + return nullptr; +} + +void Main(Engine* engine, Shared<Module>* shared, std::mutex* mutex, int id) { + own<Store*> store = Store::make(engine); + own<Module*> module = Module::obtain(store.get(), shared); + EXPECT_NE(nullptr, module.get()); + for (int i = 0; i < kIterationsPerThread; i++) { + std::this_thread::sleep_for(std::chrono::microseconds(100)); + + // Create imports. + own<FuncType*> func_type = FuncType::make( + vec<ValType*>::make(ValType::make(::wasm::I32)), vec<ValType*>::make()); + own<Func*> func = Func::make(store.get(), func_type.get(), Callback, mutex); + own<::wasm::GlobalType*> global_type = + ::wasm::GlobalType::make(ValType::make(::wasm::I32), ::wasm::CONST); + own<Global*> global = + Global::make(store.get(), global_type.get(), Val::i32(id)); + + // Instantiate and run. + // With the current implementation of the WasmModuleBuilder, global + // imports always come before function imports, regardless of the + // order of builder()->Add*Import() calls below. + Extern* imports[] = {global.get(), func.get()}; + own<Instance*> instance = + Instance::make(store.get(), module.get(), imports); + vec<Extern*> exports = instance->exports(); + Func* run_func = exports[0]->func(); + run_func->call(); + } +} + +} // namespace + +TEST_F(WasmCapiTest, Threads) { + // Create module. + ValueType i32_type[] = {kWasmI32}; + FunctionSig param_i32(0, 1, i32_type); + uint32_t callback_index = + builder()->AddImport(CStrVector("callback"), ¶m_i32); + uint32_t global_index = + builder()->AddGlobalImport(CStrVector("id"), kWasmI32, false); + + byte code[] = { + WASM_CALL_FUNCTION(callback_index, WASM_GET_GLOBAL(global_index))}; + FunctionSig empty_sig(0, 0, nullptr); + AddExportedFunction(CStrVector("run"), code, sizeof(code), &empty_sig); + Compile(); + own<Shared<Module>*> shared = module()->share(); + + // Spawn threads. + g_traces = 0; + std::mutex mutex; + std::thread threads[kNumThreads]; + for (int i = 0; i < kNumThreads; i++) { + threads[i] = std::thread(Main, engine(), shared.get(), &mutex, i); + } + for (int i = 0; i < kNumThreads; i++) { + threads[i].join(); + } + // Each thread in each iteration adds its ID to {traces}, so in the end + // we expect kIterationsPerThread * sum([0, ..., kNumThreads-1]). + // Per Gauss: + const int kExpected = + kIterationsPerThread * (kNumThreads - 1) * kNumThreads / 2; + EXPECT_EQ(kExpected, g_traces); +} + +TEST_F(WasmCapiTest, MultiStoresOneThread) { + // These Stores intentionally have overlapping, but non-nested lifetimes. + own<Store*> store1 = Store::make(engine()); + own<Store*> store2 = Store::make(engine()); + own<Store*> store3 = Store::make(engine()); + store1.reset(); + store2.reset(); + store3.reset(); +} + +} // namespace wasm +} // namespace internal +} // namespace v8 |