xref: /oneTBB/src/tbb/tcm_adaptor.cpp (revision 627cac6d)
171e1bb8eSPavel Kumbrasev /*
2*627cac6dSIlya Isaev     Copyright (c) 2023-2024 Intel Corporation
371e1bb8eSPavel Kumbrasev 
471e1bb8eSPavel Kumbrasev     Licensed under the Apache License, Version 2.0 (the "License");
571e1bb8eSPavel Kumbrasev     you may not use this file except in compliance with the License.
671e1bb8eSPavel Kumbrasev     You may obtain a copy of the License at
771e1bb8eSPavel Kumbrasev 
871e1bb8eSPavel Kumbrasev         http://www.apache.org/licenses/LICENSE-2.0
971e1bb8eSPavel Kumbrasev 
1071e1bb8eSPavel Kumbrasev     Unless required by applicable law or agreed to in writing, software
1171e1bb8eSPavel Kumbrasev     distributed under the License is distributed on an "AS IS" BASIS,
1271e1bb8eSPavel Kumbrasev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371e1bb8eSPavel Kumbrasev     See the License for the specific language governing permissions and
1471e1bb8eSPavel Kumbrasev     limitations under the License.
1571e1bb8eSPavel Kumbrasev */
1671e1bb8eSPavel Kumbrasev 
1771e1bb8eSPavel Kumbrasev #include "oneapi/tbb/detail/_intrusive_list_node.h"
1871e1bb8eSPavel Kumbrasev #include "oneapi/tbb/detail/_template_helpers.h"
1971e1bb8eSPavel Kumbrasev #include "oneapi/tbb/task_arena.h"
2071e1bb8eSPavel Kumbrasev 
2171e1bb8eSPavel Kumbrasev #include "pm_client.h"
2271e1bb8eSPavel Kumbrasev #include "dynamic_link.h"
2371e1bb8eSPavel Kumbrasev #include "misc.h"
2471e1bb8eSPavel Kumbrasev #include "tcm.h"
2571e1bb8eSPavel Kumbrasev #include "tcm_adaptor.h"
2671e1bb8eSPavel Kumbrasev 
2771e1bb8eSPavel Kumbrasev #include <iostream>
2871e1bb8eSPavel Kumbrasev 
2971e1bb8eSPavel Kumbrasev namespace tbb {
3071e1bb8eSPavel Kumbrasev namespace detail {
3171e1bb8eSPavel Kumbrasev namespace r1 {
3271e1bb8eSPavel Kumbrasev 
3371e1bb8eSPavel Kumbrasev namespace {
3471e1bb8eSPavel Kumbrasev #if __TBB_WEAK_SYMBOLS_PRESENT
3571e1bb8eSPavel Kumbrasev #pragma weak tcmConnect
3671e1bb8eSPavel Kumbrasev #pragma weak tcmDisconnect
3771e1bb8eSPavel Kumbrasev #pragma weak tcmRequestPermit
3871e1bb8eSPavel Kumbrasev #pragma weak tcmGetPermitData
3971e1bb8eSPavel Kumbrasev #pragma weak tcmReleasePermit
4071e1bb8eSPavel Kumbrasev #pragma weak tcmIdlePermit
4171e1bb8eSPavel Kumbrasev #pragma weak tcmDeactivatePermit
4271e1bb8eSPavel Kumbrasev #pragma weak tcmActivatePermit
4371e1bb8eSPavel Kumbrasev #pragma weak tcmRegisterThread
4471e1bb8eSPavel Kumbrasev #pragma weak tcmUnregisterThread
4571e1bb8eSPavel Kumbrasev #pragma weak tcmGetVersionInfo
4671e1bb8eSPavel Kumbrasev #endif /* __TBB_WEAK_SYMBOLS_PRESENT */
4771e1bb8eSPavel Kumbrasev 
4871e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_connect)(tcm_callback_t callback, tcm_client_id_t* client_id){nullptr};
4971e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_disconnect)(tcm_client_id_t client_id){ nullptr };
5071e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_request_permit)(tcm_client_id_t client_id, tcm_permit_request_t request,
5171e1bb8eSPavel Kumbrasev     void* callback_arg, tcm_permit_handle_t* permit_handle, tcm_permit_t* permit){nullptr};
5271e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_get_permit_data)(tcm_permit_handle_t permit_handle, tcm_permit_t* permit){nullptr};
5371e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_release_permit)(tcm_permit_handle_t permit){nullptr};
5471e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_idle_permit)(tcm_permit_handle_t permit_handle){nullptr};
5571e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_deactivate_permit)(tcm_permit_handle_t permit_handle){nullptr};
5671e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_activate_permit)(tcm_permit_handle_t permit_handle){nullptr};
5771e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_register_thread)(tcm_permit_handle_t permit_handle){nullptr};
5871e1bb8eSPavel Kumbrasev tcm_result_t(*tcm_unregister_thread)(){nullptr};
5971e1bb8eSPavel Kumbrasev tcm_result_t (*tcm_get_version_info)(char* buffer, uint32_t buffer_size){nullptr};
6071e1bb8eSPavel Kumbrasev 
6171e1bb8eSPavel Kumbrasev static const dynamic_link_descriptor tcm_link_table[] = {
6271e1bb8eSPavel Kumbrasev     DLD(tcmConnect, tcm_connect),
6371e1bb8eSPavel Kumbrasev     DLD(tcmDisconnect, tcm_disconnect),
6471e1bb8eSPavel Kumbrasev     DLD(tcmRequestPermit, tcm_request_permit),
6571e1bb8eSPavel Kumbrasev     DLD(tcmGetPermitData, tcm_get_permit_data),
6671e1bb8eSPavel Kumbrasev     DLD(tcmReleasePermit, tcm_release_permit),
6771e1bb8eSPavel Kumbrasev     DLD(tcmIdlePermit, tcm_idle_permit),
6871e1bb8eSPavel Kumbrasev     DLD(tcmDeactivatePermit, tcm_deactivate_permit),
6971e1bb8eSPavel Kumbrasev     DLD(tcmActivatePermit, tcm_activate_permit),
7071e1bb8eSPavel Kumbrasev     DLD(tcmRegisterThread, tcm_register_thread),
7171e1bb8eSPavel Kumbrasev     DLD(tcmUnregisterThread, tcm_unregister_thread),
7271e1bb8eSPavel Kumbrasev     DLD(tcmGetVersionInfo, tcm_get_version_info)
7371e1bb8eSPavel Kumbrasev };
7471e1bb8eSPavel Kumbrasev 
7571e1bb8eSPavel Kumbrasev #if TBB_USE_DEBUG
7671e1bb8eSPavel Kumbrasev #define DEBUG_SUFFIX "_debug"
7771e1bb8eSPavel Kumbrasev #else
7871e1bb8eSPavel Kumbrasev #define DEBUG_SUFFIX
7971e1bb8eSPavel Kumbrasev #endif /* TBB_USE_DEBUG */
8071e1bb8eSPavel Kumbrasev 
8171e1bb8eSPavel Kumbrasev #if _WIN32 || _WIN64
8271e1bb8eSPavel Kumbrasev #define LIBRARY_EXTENSION ".dll"
8371e1bb8eSPavel Kumbrasev #define LIBRARY_PREFIX
8471e1bb8eSPavel Kumbrasev #elif __unix__
8571e1bb8eSPavel Kumbrasev #define LIBRARY_EXTENSION ".so.1"
8671e1bb8eSPavel Kumbrasev #define LIBRARY_PREFIX "lib"
8771e1bb8eSPavel Kumbrasev #else
8871e1bb8eSPavel Kumbrasev #define LIBRARY_EXTENSION
8971e1bb8eSPavel Kumbrasev #define LIBRARY_PREFIX
9071e1bb8eSPavel Kumbrasev #endif /* __unix__ */
9171e1bb8eSPavel Kumbrasev 
9271e1bb8eSPavel Kumbrasev #define TCMLIB_NAME LIBRARY_PREFIX "tcm" DEBUG_SUFFIX LIBRARY_EXTENSION
9371e1bb8eSPavel Kumbrasev 
9471e1bb8eSPavel Kumbrasev static bool tcm_functions_loaded{ false };
9571e1bb8eSPavel Kumbrasev }
9671e1bb8eSPavel Kumbrasev 
9771e1bb8eSPavel Kumbrasev class tcm_client : public pm_client {
9871e1bb8eSPavel Kumbrasev     using tcm_client_mutex_type = d1::mutex;
9971e1bb8eSPavel Kumbrasev public:
tcm_client(tcm_adaptor & adaptor,arena & a)10071e1bb8eSPavel Kumbrasev     tcm_client(tcm_adaptor& adaptor, arena& a) : pm_client(a), my_tcm_adaptor(adaptor) {}
10171e1bb8eSPavel Kumbrasev 
~tcm_client()10271e1bb8eSPavel Kumbrasev     ~tcm_client() {
10371e1bb8eSPavel Kumbrasev         if (my_permit_handle) {
10471e1bb8eSPavel Kumbrasev             __TBB_ASSERT(tcm_release_permit, nullptr);
10571e1bb8eSPavel Kumbrasev             auto res = tcm_release_permit(my_permit_handle);
10671e1bb8eSPavel Kumbrasev             __TBB_ASSERT_EX(res == TCM_RESULT_SUCCESS, nullptr);
10771e1bb8eSPavel Kumbrasev         }
10871e1bb8eSPavel Kumbrasev     }
10971e1bb8eSPavel Kumbrasev 
update_concurrency(uint32_t concurrency)11071e1bb8eSPavel Kumbrasev     int update_concurrency(uint32_t concurrency) {
11171e1bb8eSPavel Kumbrasev         return my_arena.update_concurrency(concurrency);
11271e1bb8eSPavel Kumbrasev     }
11371e1bb8eSPavel Kumbrasev 
priority_level()11471e1bb8eSPavel Kumbrasev     unsigned priority_level() {
11571e1bb8eSPavel Kumbrasev         return my_arena.priority_level();
11671e1bb8eSPavel Kumbrasev     }
11771e1bb8eSPavel Kumbrasev 
permit_request()11871e1bb8eSPavel Kumbrasev     tcm_permit_request_t& permit_request() {
11971e1bb8eSPavel Kumbrasev         return my_permit_request;
12071e1bb8eSPavel Kumbrasev     }
12171e1bb8eSPavel Kumbrasev 
permit_handle()12271e1bb8eSPavel Kumbrasev     tcm_permit_handle_t& permit_handle() {
12371e1bb8eSPavel Kumbrasev         return my_permit_handle;
12471e1bb8eSPavel Kumbrasev     }
12571e1bb8eSPavel Kumbrasev 
actualize_permit()12671e1bb8eSPavel Kumbrasev     void actualize_permit() {
12771e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_get_permit_data, nullptr);
12871e1bb8eSPavel Kumbrasev         int delta{};
12971e1bb8eSPavel Kumbrasev         {
13071e1bb8eSPavel Kumbrasev             tcm_client_mutex_type::scoped_lock lock(my_permit_mutex);
13171e1bb8eSPavel Kumbrasev 
13271e1bb8eSPavel Kumbrasev             uint32_t new_concurrency{};
13371e1bb8eSPavel Kumbrasev             tcm_permit_t new_permit{ &new_concurrency, nullptr, 1, TCM_PERMIT_STATE_VOID, {} };
13471e1bb8eSPavel Kumbrasev             auto res = tcm_get_permit_data(my_permit_handle, &new_permit);
13571e1bb8eSPavel Kumbrasev             __TBB_ASSERT_EX(res == TCM_RESULT_SUCCESS, nullptr);
13671e1bb8eSPavel Kumbrasev 
13771e1bb8eSPavel Kumbrasev             // The permit has changed during the reading, so the callback will be invoked soon one more time and
13871e1bb8eSPavel Kumbrasev             // we can just skip this renegotiation iteration.
13971e1bb8eSPavel Kumbrasev             if (!new_permit.flags.stale) {
140*627cac6dSIlya Isaev                 // If there is no other demand in TCM, the permit may still have granted concurrency but
141*627cac6dSIlya Isaev                 // be in the deactivated state thus we enforce 0 allotment to preserve arena invariants.
142*627cac6dSIlya Isaev                 delta = update_concurrency(new_permit.state != TCM_PERMIT_STATE_INACTIVE ? new_concurrency : 0);
14371e1bb8eSPavel Kumbrasev             }
14471e1bb8eSPavel Kumbrasev         }
14571e1bb8eSPavel Kumbrasev         if (delta) {
14671e1bb8eSPavel Kumbrasev             my_tcm_adaptor.notify_thread_request(delta);
14771e1bb8eSPavel Kumbrasev         }
14871e1bb8eSPavel Kumbrasev     }
14971e1bb8eSPavel Kumbrasev 
request_permit(tcm_client_id_t client_id)15071e1bb8eSPavel Kumbrasev     void request_permit(tcm_client_id_t client_id) {
15171e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_request_permit, nullptr);
15271e1bb8eSPavel Kumbrasev 
15371e1bb8eSPavel Kumbrasev         my_permit_request.max_sw_threads = max_workers();
15471e1bb8eSPavel Kumbrasev         my_permit_request.min_sw_threads = my_permit_request.max_sw_threads == 0 ? 0 : min_workers();
15571e1bb8eSPavel Kumbrasev 
15671e1bb8eSPavel Kumbrasev         if (my_permit_request.constraints_size > 0) {
15771e1bb8eSPavel Kumbrasev             my_permit_request.cpu_constraints->min_concurrency = my_permit_request.min_sw_threads;
15871e1bb8eSPavel Kumbrasev             my_permit_request.cpu_constraints->max_concurrency = my_permit_request.max_sw_threads;
15971e1bb8eSPavel Kumbrasev         }
16071e1bb8eSPavel Kumbrasev 
16171e1bb8eSPavel Kumbrasev         __TBB_ASSERT(my_permit_request.max_sw_threads >= my_permit_request.min_sw_threads, nullptr);
16271e1bb8eSPavel Kumbrasev 
16371e1bb8eSPavel Kumbrasev         tcm_result_t res = tcm_request_permit(client_id, my_permit_request, this, &my_permit_handle, nullptr);
16471e1bb8eSPavel Kumbrasev         __TBB_ASSERT_EX(res == TCM_RESULT_SUCCESS, nullptr);
16571e1bb8eSPavel Kumbrasev     }
16671e1bb8eSPavel Kumbrasev 
deactivate_permit()16771e1bb8eSPavel Kumbrasev     void deactivate_permit() {
16871e1bb8eSPavel Kumbrasev          __TBB_ASSERT(tcm_deactivate_permit, nullptr);
16971e1bb8eSPavel Kumbrasev         tcm_result_t res = tcm_deactivate_permit(my_permit_handle);
17071e1bb8eSPavel Kumbrasev         __TBB_ASSERT_EX(res == TCM_RESULT_SUCCESS, nullptr);
17171e1bb8eSPavel Kumbrasev     }
17271e1bb8eSPavel Kumbrasev 
init(d1::constraints & constraints)17371e1bb8eSPavel Kumbrasev     void init(d1::constraints& constraints) {
17471e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_request_permit, nullptr);
17571e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_deactivate_permit, nullptr);
17671e1bb8eSPavel Kumbrasev 
17771e1bb8eSPavel Kumbrasev         if (constraints.core_type            != d1::task_arena::automatic ||
17871e1bb8eSPavel Kumbrasev             constraints.numa_id              != d1::task_arena::automatic ||
17971e1bb8eSPavel Kumbrasev             constraints.max_threads_per_core != d1::task_arena::automatic)
18071e1bb8eSPavel Kumbrasev         {
18171e1bb8eSPavel Kumbrasev             my_permit_constraints.max_concurrency = constraints.max_concurrency;
18271e1bb8eSPavel Kumbrasev             my_permit_constraints.min_concurrency = 0;
18371e1bb8eSPavel Kumbrasev             my_permit_constraints.core_type_id = constraints.core_type;
18471e1bb8eSPavel Kumbrasev             my_permit_constraints.numa_id = constraints.numa_id;
18571e1bb8eSPavel Kumbrasev             my_permit_constraints.threads_per_core = constraints.max_threads_per_core;
18671e1bb8eSPavel Kumbrasev 
18771e1bb8eSPavel Kumbrasev             my_permit_request.cpu_constraints = &my_permit_constraints;
18871e1bb8eSPavel Kumbrasev             my_permit_request.constraints_size = 1;
18971e1bb8eSPavel Kumbrasev         }
19071e1bb8eSPavel Kumbrasev 
19171e1bb8eSPavel Kumbrasev         my_permit_request.min_sw_threads = 0;
19271e1bb8eSPavel Kumbrasev         my_permit_request.max_sw_threads = 0;
19371e1bb8eSPavel Kumbrasev     }
19471e1bb8eSPavel Kumbrasev 
register_thread()19571e1bb8eSPavel Kumbrasev     void register_thread() override {
19671e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_register_thread, nullptr);
19771e1bb8eSPavel Kumbrasev         auto return_code = tcm_register_thread(my_permit_handle);
19871e1bb8eSPavel Kumbrasev         __TBB_ASSERT_EX(return_code == TCM_RESULT_SUCCESS, nullptr);
19971e1bb8eSPavel Kumbrasev     }
20071e1bb8eSPavel Kumbrasev 
unregister_thread()20171e1bb8eSPavel Kumbrasev     void unregister_thread() override {
20271e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_unregister_thread, nullptr);
20371e1bb8eSPavel Kumbrasev         auto return_code = tcm_unregister_thread();
20471e1bb8eSPavel Kumbrasev         __TBB_ASSERT_EX(return_code == TCM_RESULT_SUCCESS, nullptr);
20571e1bb8eSPavel Kumbrasev     }
20671e1bb8eSPavel Kumbrasev 
20771e1bb8eSPavel Kumbrasev private:
20871e1bb8eSPavel Kumbrasev     tcm_cpu_constraints_t my_permit_constraints = TCM_PERMIT_REQUEST_CONSTRAINTS_INITIALIZER;
20971e1bb8eSPavel Kumbrasev     tcm_permit_request_t my_permit_request = TCM_PERMIT_REQUEST_INITIALIZER;
21071e1bb8eSPavel Kumbrasev     tcm_permit_handle_t my_permit_handle{};
21171e1bb8eSPavel Kumbrasev     tcm_client_mutex_type my_permit_mutex;
21271e1bb8eSPavel Kumbrasev     tcm_adaptor& my_tcm_adaptor;
21371e1bb8eSPavel Kumbrasev };
21471e1bb8eSPavel Kumbrasev 
21571e1bb8eSPavel Kumbrasev //------------------------------------------------------------------------
21671e1bb8eSPavel Kumbrasev // tcm_adaptor_impl
21771e1bb8eSPavel Kumbrasev //------------------------------------------------------------------------
21871e1bb8eSPavel Kumbrasev 
21971e1bb8eSPavel Kumbrasev struct tcm_adaptor_impl {
22071e1bb8eSPavel Kumbrasev     using demand_mutex_type = d1::mutex;
22171e1bb8eSPavel Kumbrasev     demand_mutex_type my_demand_mutex;
22271e1bb8eSPavel Kumbrasev     tcm_client_id_t client_id{};
22371e1bb8eSPavel Kumbrasev 
tcm_adaptor_impltbb::detail::r1::tcm_adaptor_impl22471e1bb8eSPavel Kumbrasev     tcm_adaptor_impl(tcm_client_id_t id) : client_id(id)
22571e1bb8eSPavel Kumbrasev     {}
22671e1bb8eSPavel Kumbrasev };
22771e1bb8eSPavel Kumbrasev 
22871e1bb8eSPavel Kumbrasev //------------------------------------------------------------------------
22971e1bb8eSPavel Kumbrasev // tcm_adaptor
23071e1bb8eSPavel Kumbrasev //------------------------------------------------------------------------
23171e1bb8eSPavel Kumbrasev 
renegotiation_callback(tcm_permit_handle_t,void * client_ptr,tcm_callback_flags_t)23271e1bb8eSPavel Kumbrasev tcm_result_t renegotiation_callback(tcm_permit_handle_t, void* client_ptr, tcm_callback_flags_t) {
23371e1bb8eSPavel Kumbrasev     __TBB_ASSERT(client_ptr, nullptr);
23471e1bb8eSPavel Kumbrasev     static_cast<tcm_client*>(client_ptr)->actualize_permit();
23571e1bb8eSPavel Kumbrasev     return TCM_RESULT_SUCCESS;
23671e1bb8eSPavel Kumbrasev }
23771e1bb8eSPavel Kumbrasev 
initialize()23871e1bb8eSPavel Kumbrasev void tcm_adaptor::initialize() {
23971e1bb8eSPavel Kumbrasev     tcm_functions_loaded = dynamic_link(TCMLIB_NAME, tcm_link_table, /* tcm_link_table size = */ 11);
24071e1bb8eSPavel Kumbrasev }
24171e1bb8eSPavel Kumbrasev 
is_initialized()24271e1bb8eSPavel Kumbrasev bool tcm_adaptor::is_initialized() {
24371e1bb8eSPavel Kumbrasev     return tcm_functions_loaded;
24471e1bb8eSPavel Kumbrasev }
24571e1bb8eSPavel Kumbrasev 
print_version()24671e1bb8eSPavel Kumbrasev void tcm_adaptor::print_version() {
24771e1bb8eSPavel Kumbrasev     if (is_initialized()) {
24871e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_get_version_info, nullptr);
24971e1bb8eSPavel Kumbrasev         char buffer[1024];
25071e1bb8eSPavel Kumbrasev         tcm_get_version_info(buffer, 1024);
25171e1bb8eSPavel Kumbrasev         std::fprintf(stderr, "%.*s", 1024, buffer);
25271e1bb8eSPavel Kumbrasev     }
25371e1bb8eSPavel Kumbrasev }
25471e1bb8eSPavel Kumbrasev 
tcm_adaptor()25571e1bb8eSPavel Kumbrasev tcm_adaptor::tcm_adaptor() {
25671e1bb8eSPavel Kumbrasev     __TBB_ASSERT(tcm_connect, nullptr);
25771e1bb8eSPavel Kumbrasev     tcm_client_id_t client_id{};
25871e1bb8eSPavel Kumbrasev     auto return_code = tcm_connect(renegotiation_callback, &client_id);
25971e1bb8eSPavel Kumbrasev     if (return_code == TCM_RESULT_SUCCESS) {
26071e1bb8eSPavel Kumbrasev         my_impl = make_cache_aligned_unique<tcm_adaptor_impl>(client_id);
26171e1bb8eSPavel Kumbrasev     }
26271e1bb8eSPavel Kumbrasev }
26371e1bb8eSPavel Kumbrasev 
~tcm_adaptor()26471e1bb8eSPavel Kumbrasev tcm_adaptor::~tcm_adaptor() {
26571e1bb8eSPavel Kumbrasev     if (my_impl) {
26671e1bb8eSPavel Kumbrasev         __TBB_ASSERT(tcm_disconnect, nullptr);
26771e1bb8eSPavel Kumbrasev         auto return_code = tcm_disconnect(my_impl->client_id);
26871e1bb8eSPavel Kumbrasev         __TBB_ASSERT_EX(return_code == TCM_RESULT_SUCCESS, nullptr);
26971e1bb8eSPavel Kumbrasev         my_impl = nullptr;
27071e1bb8eSPavel Kumbrasev     }
27171e1bb8eSPavel Kumbrasev }
27271e1bb8eSPavel Kumbrasev 
is_connected()27371e1bb8eSPavel Kumbrasev bool tcm_adaptor::is_connected() {
27471e1bb8eSPavel Kumbrasev     return my_impl != nullptr;
27571e1bb8eSPavel Kumbrasev }
27671e1bb8eSPavel Kumbrasev 
create_client(arena & a)27771e1bb8eSPavel Kumbrasev pm_client* tcm_adaptor::create_client(arena& a) {
27871e1bb8eSPavel Kumbrasev     return new (cache_aligned_allocate(sizeof(tcm_client))) tcm_client(*this, a);
27971e1bb8eSPavel Kumbrasev }
28071e1bb8eSPavel Kumbrasev 
register_client(pm_client * c,d1::constraints & constraints)28171e1bb8eSPavel Kumbrasev void tcm_adaptor::register_client(pm_client* c, d1::constraints& constraints) {
28271e1bb8eSPavel Kumbrasev     static_cast<tcm_client*>(c)->init(constraints);
28371e1bb8eSPavel Kumbrasev }
28471e1bb8eSPavel Kumbrasev 
unregister_and_destroy_client(pm_client & c)28571e1bb8eSPavel Kumbrasev void tcm_adaptor::unregister_and_destroy_client(pm_client& c) {
28671e1bb8eSPavel Kumbrasev     auto& client = static_cast<tcm_client&>(c);
28771e1bb8eSPavel Kumbrasev 
28871e1bb8eSPavel Kumbrasev     {
28971e1bb8eSPavel Kumbrasev         tcm_adaptor_impl::demand_mutex_type::scoped_lock lock(my_impl->my_demand_mutex);
29071e1bb8eSPavel Kumbrasev         client.~tcm_client();
29171e1bb8eSPavel Kumbrasev     }
29271e1bb8eSPavel Kumbrasev     cache_aligned_deallocate(&client);
29371e1bb8eSPavel Kumbrasev }
29471e1bb8eSPavel Kumbrasev 
set_active_num_workers(int)29571e1bb8eSPavel Kumbrasev void tcm_adaptor::set_active_num_workers(int) {}
29671e1bb8eSPavel Kumbrasev 
29771e1bb8eSPavel Kumbrasev 
adjust_demand(pm_client & c,int mandatory_delta,int workers_delta)29871e1bb8eSPavel Kumbrasev void tcm_adaptor::adjust_demand(pm_client& c, int mandatory_delta, int workers_delta) {
29971e1bb8eSPavel Kumbrasev     __TBB_ASSERT(-1 <= mandatory_delta && mandatory_delta <= 1, nullptr);
30071e1bb8eSPavel Kumbrasev 
30171e1bb8eSPavel Kumbrasev     auto& client = static_cast<tcm_client&>(c);
30271e1bb8eSPavel Kumbrasev     {
30371e1bb8eSPavel Kumbrasev         tcm_adaptor_impl::demand_mutex_type::scoped_lock lock(my_impl->my_demand_mutex);
30471e1bb8eSPavel Kumbrasev 
30571e1bb8eSPavel Kumbrasev         // Update client's state
30671e1bb8eSPavel Kumbrasev         workers_delta = client.update_request(mandatory_delta, workers_delta);
30771e1bb8eSPavel Kumbrasev         if (workers_delta == 0) return;
30871e1bb8eSPavel Kumbrasev 
30971e1bb8eSPavel Kumbrasev         if (client.max_workers() == 0) {
31071e1bb8eSPavel Kumbrasev             client.deactivate_permit();
31171e1bb8eSPavel Kumbrasev         } else {
31271e1bb8eSPavel Kumbrasev             client.request_permit(my_impl->client_id);
31371e1bb8eSPavel Kumbrasev         }
31471e1bb8eSPavel Kumbrasev     }
31571e1bb8eSPavel Kumbrasev 
31671e1bb8eSPavel Kumbrasev     client.actualize_permit();
31771e1bb8eSPavel Kumbrasev }
31871e1bb8eSPavel Kumbrasev 
31971e1bb8eSPavel Kumbrasev } // namespace r1
32071e1bb8eSPavel Kumbrasev } // namespace detail
32171e1bb8eSPavel Kumbrasev } // namespace tbb
322