1*cf0a6739SIlya Isaev /* 2*cf0a6739SIlya Isaev Copyright (c) 2021 Intel Corporation 3*cf0a6739SIlya Isaev 4*cf0a6739SIlya Isaev Licensed under the Apache License, Version 2.0 (the "License"); 5*cf0a6739SIlya Isaev you may not use this file except in compliance with the License. 6*cf0a6739SIlya Isaev You may obtain a copy of the License at 7*cf0a6739SIlya Isaev 8*cf0a6739SIlya Isaev http://www.apache.org/licenses/LICENSE-2.0 9*cf0a6739SIlya Isaev 10*cf0a6739SIlya Isaev Unless required by applicable law or agreed to in writing, software 11*cf0a6739SIlya Isaev distributed under the License is distributed on an "AS IS" BASIS, 12*cf0a6739SIlya Isaev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*cf0a6739SIlya Isaev See the License for the specific language governing permissions and 14*cf0a6739SIlya Isaev limitations under the License. 15*cf0a6739SIlya Isaev */ 16*cf0a6739SIlya Isaev 17*cf0a6739SIlya Isaev #if _MSC_VER && !defined(__INTEL_COMPILER) 18*cf0a6739SIlya Isaev // unreachable code 19*cf0a6739SIlya Isaev #pragma warning( push ) 20*cf0a6739SIlya Isaev #pragma warning( disable: 4702 ) 21*cf0a6739SIlya Isaev #endif 22*cf0a6739SIlya Isaev 23*cf0a6739SIlya Isaev #if __INTEL_COMPILER && _MSC_VER 24*cf0a6739SIlya Isaev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated 25*cf0a6739SIlya Isaev #endif 26*cf0a6739SIlya Isaev 27*cf0a6739SIlya Isaev #include "common/test.h" 28*cf0a6739SIlya Isaev #include "oneapi/tbb/collaborative_call_once.h" 29*cf0a6739SIlya Isaev 30*cf0a6739SIlya Isaev #include "common/utils.h" 31*cf0a6739SIlya Isaev #include "common/utils_concurrency_limit.h" 32*cf0a6739SIlya Isaev #include "common/spin_barrier.h" 33*cf0a6739SIlya Isaev #include "oneapi/tbb/parallel_for.h" 34*cf0a6739SIlya Isaev #include "oneapi/tbb/task_group.h" 35*cf0a6739SIlya Isaev 36*cf0a6739SIlya Isaev #include <type_traits> 37*cf0a6739SIlya Isaev #include <exception> 38*cf0a6739SIlya Isaev 39*cf0a6739SIlya Isaev //! \file conformance_collaborative_call_once.cpp 40*cf0a6739SIlya Isaev //! \brief Test for [algorithms.collaborative_call_once] specification 41*cf0a6739SIlya Isaev 42*cf0a6739SIlya Isaev //! Test for collaborative_once_flag member functions to be matched with spec 43*cf0a6739SIlya Isaev //! \brief \ref interface \ref requirement 44*cf0a6739SIlya Isaev TEST_CASE("collaborative_once_flag member functions match") { 45*cf0a6739SIlya Isaev REQUIRE_MESSAGE(std::is_default_constructible<oneapi::tbb::collaborative_once_flag>::value == true, 46*cf0a6739SIlya Isaev "collaborative_once_flag must be default constructible"); 47*cf0a6739SIlya Isaev REQUIRE_MESSAGE(std::is_copy_constructible<oneapi::tbb::collaborative_once_flag>::value == false, 48*cf0a6739SIlya Isaev "collaborative_once_flag must not be copy constructible"); 49*cf0a6739SIlya Isaev REQUIRE_MESSAGE(std::is_copy_assignable<oneapi::tbb::collaborative_once_flag>::value == false, 50*cf0a6739SIlya Isaev "collaborative_once_flag must not be copy assignable"); 51*cf0a6739SIlya Isaev REQUIRE_MESSAGE(std::is_move_constructible<oneapi::tbb::collaborative_once_flag>::value == false, 52*cf0a6739SIlya Isaev "collaborative_once_flag must not be move constructible"); 53*cf0a6739SIlya Isaev REQUIRE_MESSAGE(std::is_move_assignable<oneapi::tbb::collaborative_once_flag>::value == false, 54*cf0a6739SIlya Isaev "collaborative_once_flag must not be move assignable"); 55*cf0a6739SIlya Isaev } 56*cf0a6739SIlya Isaev 57*cf0a6739SIlya Isaev //! Test for collaborative_call_once to execute function exactly once 58*cf0a6739SIlya Isaev //! \brief \ref interface \ref requirement 59*cf0a6739SIlya Isaev TEST_CASE("collaborative_call_once executes function exactly once") { 60*cf0a6739SIlya Isaev oneapi::tbb::collaborative_once_flag once_flag; 61*cf0a6739SIlya Isaev 62*cf0a6739SIlya Isaev for (int iter = 0; iter < 100; ++iter) { __anon8e61f74e0102(int number) 63*cf0a6739SIlya Isaev oneapi::tbb::collaborative_call_once(once_flag, [](int number) { 64*cf0a6739SIlya Isaev // Will be executed only on first iteration 65*cf0a6739SIlya Isaev REQUIRE(number == 0); 66*cf0a6739SIlya Isaev }, iter); 67*cf0a6739SIlya Isaev } 68*cf0a6739SIlya Isaev 69*cf0a6739SIlya Isaev // concurrent call 70*cf0a6739SIlya Isaev std::size_t num_threads = utils::get_platform_max_threads(); 71*cf0a6739SIlya Isaev utils::SpinBarrier barrier{num_threads}; 72*cf0a6739SIlya Isaev 73*cf0a6739SIlya Isaev int flag = 0; __anon8e61f74e0202null74*cf0a6739SIlya Isaev auto func = [&flag] { flag++; }; 75*cf0a6739SIlya Isaev 76*cf0a6739SIlya Isaev oneapi::tbb::collaborative_once_flag once_flag_concurrent; __anon8e61f74e0302(std::size_t) 77*cf0a6739SIlya Isaev utils::NativeParallelFor(num_threads, [&](std::size_t) { 78*cf0a6739SIlya Isaev barrier.wait(); 79*cf0a6739SIlya Isaev oneapi::tbb::collaborative_call_once(once_flag_concurrent, func); 80*cf0a6739SIlya Isaev }); 81*cf0a6739SIlya Isaev REQUIRE(flag == 1); 82*cf0a6739SIlya Isaev } 83*cf0a6739SIlya Isaev 84*cf0a6739SIlya Isaev 85*cf0a6739SIlya Isaev #if TBB_USE_EXCEPTIONS 86*cf0a6739SIlya Isaev 87*cf0a6739SIlya Isaev //! Exception is received only by winner thread 88*cf0a6739SIlya Isaev //! \brief \ref error_guessing \ref requirement 89*cf0a6739SIlya Isaev TEST_CASE("Exception is received only by winner thread") { 90*cf0a6739SIlya Isaev int num_threads = static_cast<int>(utils::get_platform_max_threads()); 91*cf0a6739SIlya Isaev utils::SpinBarrier barrier(num_threads); 92*cf0a6739SIlya Isaev 93*cf0a6739SIlya Isaev oneapi::tbb::task_group tg; 94*cf0a6739SIlya Isaev oneapi::tbb::collaborative_once_flag flag; 95*cf0a6739SIlya Isaev 96*cf0a6739SIlya Isaev for (int i = 0; i < num_threads-1; ++i) { __anon8e61f74e0402null97*cf0a6739SIlya Isaev tg.run([&flag, &barrier] { 98*cf0a6739SIlya Isaev barrier.wait(); 99*cf0a6739SIlya Isaev try { 100*cf0a6739SIlya Isaev oneapi::tbb::collaborative_call_once(flag, [] { }); 101*cf0a6739SIlya Isaev } catch(...) { 102*cf0a6739SIlya Isaev REQUIRE_MESSAGE(false, "Unreachable code"); 103*cf0a6739SIlya Isaev } 104*cf0a6739SIlya Isaev }); 105*cf0a6739SIlya Isaev }; 106*cf0a6739SIlya Isaev 107*cf0a6739SIlya Isaev bool exception_happened{false}; 108*cf0a6739SIlya Isaev try { __anon8e61f74e0602null109*cf0a6739SIlya Isaev oneapi::tbb::collaborative_call_once(flag, [&barrier] { 110*cf0a6739SIlya Isaev barrier.wait(); 111*cf0a6739SIlya Isaev throw std::exception{}; 112*cf0a6739SIlya Isaev }); 113*cf0a6739SIlya Isaev } catch (std::exception&) { 114*cf0a6739SIlya Isaev exception_happened = true; 115*cf0a6739SIlya Isaev } 116*cf0a6739SIlya Isaev 117*cf0a6739SIlya Isaev REQUIRE_MESSAGE(exception_happened == true, "Exception hasn't been received from the winner thread"); 118*cf0a6739SIlya Isaev tg.wait(); 119*cf0a6739SIlya Isaev } 120*cf0a6739SIlya Isaev 121*cf0a6739SIlya Isaev #endif 122*cf0a6739SIlya Isaev 123*cf0a6739SIlya Isaev #if _MSC_VER && !defined(__INTEL_COMPILER) 124*cf0a6739SIlya Isaev #pragma warning( pop ) 125*cf0a6739SIlya Isaev #endif 126